Skip to content

Commit 73086c1

Browse files
committed
Document the ManualTimestepRobot class
This documents this class and how to use it, including pointers in various relevant locations around the docs and updates to the rest of the time docs to match. See srobo/competition-simulator#158 for the underlying implementation.
1 parent accf186 commit 73086c1

File tree

3 files changed

+140
-9
lines changed

3 files changed

+140
-9
lines changed

competition-simulator/programming/index.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ Unless otherwise stated, the simulator’s API is the same as the real SR API de
3535

3636
To assist with converting your existing code from Python 2 to Python 3, you can use [`2to3`](https://docs.python.org/3/library/2to3.html).
3737

38+
### Robot
39+
40+
There are two possible classes you can use to control your robot. You are
41+
encouraged to use the newer [`ManualTimestepRobot` class][manual-timestep-class]
42+
rather than the older `Robot` class. This avoids unpredictable behaviour which
43+
can result from simulator time not passing at the same rate as real time.
44+
45+
[manual-timestep-class]: /docs/competition-simulator/programming/time#manual-timestep-robot
46+
3847
### Motors
3948

4049
Your robot has two motor boards attached, each with two motors. Board `0` has the left wheel in port `m0`, and the right wheel in `m1`. Board `1` has the gripper lift motor in `m0`, and the finger motors in `m1`.

competition-simulator/programming/time.md

Lines changed: 119 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,66 @@ is run and in cooperation with the controller code (such as the code controlling
1010
your robot). As a result, using `time.time` to know how long your robot has been
1111
running for or `time.sleep` to wait for some duration may be unreliable.
1212

13-
Instead the simulated `Robot` API provides some alternatives which you are
14-
encouraged to use instead.
13+
## Approaches
14+
15+
### Existing projects: the `Robot` class
16+
17+
<!-- We should drop this after SR2020 and move `ManualTimestepRobot` to being the default. -->
18+
19+
For existing projects the default `Robot` class will automatically advance the
20+
simulator all the time. This can make programming your robot slightly easier as
21+
you don't need to worry about the progress of time and (just like a real robot)
22+
you can assume that time passing will just happen.
23+
24+
However this has a drawback -- because the simulator advances time in small
25+
chunks (rather than the smooth progression we're used to in reality) it can mean
26+
that your robots actions sometimes run for slightly more or less time than you
27+
expect. While the time difference will be small (a few tens of milliseconds), it
28+
is likely to impact attempts at more precise movement more than larger actions
29+
due to their shorter time.
30+
31+
This may mean for example that turning by a small angle to line up with a token
32+
will sometimes work and sometimes point the robot in not quite the right
33+
direction.
34+
35+
If your robot code is impacted by these unpredictability issues we recommend
36+
that you change over to using the `ManualTimestepRobot` class instead. For
37+
guidance on doing this, see the [upgrade guide](#upgrading) below.
38+
39+
This class is maintained for compatibility with earlier releases of the
40+
simulator, though its use is discouraged (especially for new projects).
41+
42+
### New projects: the `ManualTimestepRobot` class {#manual-timestep-robot}
43+
44+
For new projects, or existing projects that want to be sure of getting precise
45+
robot behaviour, the recommended approach is to use the `ManualTimestepRobot`
46+
class.
47+
48+
This approach relies upon your code advancing the simulation explicitly by
49+
calling its `sleep` method (documented below) in order for the simulation to
50+
actually run. This should not be an issue for most robot code however as you
51+
will likely be doing this anyway in order to wait for things to happen.
52+
53+
<div class="info">
54+
If you find that the simulator freezes then this indicates that your code is
55+
busy doing something without giving the simulator a chance to run.
56+
57+
This usually indicates that you have a loop somewhere which is expecting time
58+
to advance on its own and which should be modified to call <code>R.sleep</code>
59+
occasionally (even a very small value will allow the simulator to progress).
60+
</div>
1561

1662
## Sleeping
1763

1864
If you want to wait for something to happen within the simulation, and you can
1965
be reasonably confident that it will take a given amount of time, you can use
20-
`Robot.sleep` method to pause your code for a given duration.
66+
`sleep` method on your robot to pause your code for a given duration.
2167

2268
Internally this uses the simulation's own clock and so is suitable for use in
2369
place of `time.sleep`. Note that, just as with `time.sleep`, while your code is
2470
sleeping your robot will continue any actions it was doing.
2571

2672
``` python
27-
R = Robot()
28-
2973
# Blink the output
3074
R.ruggeduinos[0].digital_write(A_PIN, 1)
3175
R.sleep(1.5) # Sleep for a second and a half of simulation time
@@ -35,16 +79,14 @@ R.ruggeduinos[0].digital_write(A_PIN, 0)
3579
## Getting the current time
3680

3781
If you need to measure the time since some previous moment within the simulator,
38-
`Robot.time` can be used in place of `time.time` to get a number (in seconds)
39-
which increases in line with simulation time.
82+
your robot has a `time` method which can be used in place of `time.time` to get
83+
a number (in seconds) that increases in line with simulation time.
4084

4185
Time zero as returned by this method is the point at which the simulation began,
4286
however you should not rely on that being a useful reference point as it may not
4387
be the moment at which the _match_ began.
4488

4589
``` python
46-
R = Robot()
47-
4890
then = R.time()
4991

5092
# .. do some other things ..
@@ -53,3 +95,71 @@ now = R.time()
5395

5496
duration = now - then
5597
```
98+
99+
## Changing from `Robot` to `ManualTimestepRobot` {#upgrading}
100+
101+
The changes needed to move from using `Robot` to `ManualTimestepRobot` are
102+
fairly small since both classes have the same interface. This means that
103+
anywhere in the docs a <code>Robot</code> is used, you can also use a
104+
<code>ManualTimestepRobot</code>.
105+
106+
1. Anywhere that your code mentions `Robot`, change it to `ManualTimestepRobot`,
107+
for example:
108+
109+
``` python
110+
from sr.robot import Robot # change this
111+
112+
R = Robot() # change this
113+
114+
R.motors[0].m1.power = 20 # this stays the same
115+
```
116+
117+
should be changed to:
118+
119+
``` python
120+
from sr.robot import ManualTimestepRobot
121+
122+
R = ManualTimestepRobot()
123+
124+
R.motors[0].m1.power = 20
125+
```
126+
127+
2. Remove any usages of either `time.time` or `time.sleep` and replace them with
128+
the equivalent robot methods (documented above). For example:
129+
130+
``` python
131+
import time # remove this everywhere
132+
133+
start = time.time()
134+
time.sleep(1.2)
135+
print("I slept for {} seconds".format(time.time() - start))
136+
```
137+
138+
should be changed to:
139+
140+
``` python
141+
start = R.time()
142+
R.sleep(1.2)
143+
print("I slept for {} seconds".format(R.time() - start))
144+
```
145+
146+
3. Check for any places where you have code which expect that `R.time()` will
147+
increase on its own and ensure that they sleep for at least a very small
148+
amount of time on each iteration. For example:
149+
150+
``` python
151+
end = R.time() + 5
152+
while R.time() < end:
153+
if has_touched_something(R):
154+
break
155+
```
156+
157+
should be changed to:
158+
159+
``` python
160+
end = R.time() + 5
161+
while R.time() < end:
162+
R.sleep(0.01) # note addition of this line
163+
if has_touched_something(R):
164+
break
165+
```

programming/sr/index.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,18 @@ from sr.robot import *
3232
R = Robot()
3333
~~~~~
3434

35+
<div class="warning">
36+
<!-- We should drop this after SR2020 and move `ManualTimestepRobot` to being the default. -->
37+
38+
When programming for the <a href="/docs/competition-simulator">Competition Simulator</a>
39+
you are strongly encouraged to use the
40+
<a href="/docs/competition-simulator/programming/time#manual-timestep-robot">
41+
<code>ManualTimestepRobot class</code>
42+
</a>
43+
instead of the <code>Robot</code> class. This avoids unpredictable behaviour
44+
which can result from simulator time not passing at the same rate as real time.
45+
</div>
46+
3547
Within your `Robot` (`R` in this case), you then have access to the following attributes:
3648

3749
* [motors](/docs/programming/sr/motors/)

0 commit comments

Comments
 (0)