Skip to content

Commit f491109

Browse files
Merge pull request #139 from PeterJCLaw/expand-documentation-of-time
Expand documentation of time
2 parents d37976c + 73086c1 commit f491109

File tree

6 files changed

+196
-44
lines changed

6 files changed

+196
-44
lines changed

_data/sidebar_tree.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ tree:
88
tree:
99
- url: /competition-simulator/programming
1010
title: Programming
11+
tree:
12+
- url: /competition-simulator/programming/time
13+
title: Time
1114
- url: /IDE/
1215
title: IDE
1316
tree:

_sass/docs.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828

2929
h1, h2, h3, h4, h5, h6 {
3030
clear: both;
31+
code {
32+
text-transform: none;
33+
}
3134
}
3235

3336
p {

competition-simulator/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,4 @@ speeds (▶▶ and ▶▶▶).
112112

113113
These differences mean that your code will need to use a different mechanism to
114114
find the current time or to sleep within the simulation. Find out more by
115-
heading over to the [programming docs on time](./programming#time).
115+
heading over to the [programming docs on time](./programming/time).

competition-simulator/programming.md renamed to competition-simulator/programming/index.md

Lines changed: 12 additions & 43 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`.
@@ -108,46 +117,6 @@ In the simulated environment, time advances only at the pace that the simulator
108117
is run. As a result, using `time.time` to know how long your robot has been
109118
running for or `time.sleep` to wait for some duration will be unreliable.
110119

111-
Instead the simulated `Robot` API provides some alternatives which you are
112-
encouraged to use instead.
113-
114-
#### Sleeping
115-
116-
If you want to wait for something to happen within the simulation, and you can
117-
be reasonably confident that it will take a given amount of time, you can use
118-
`Robot.sleep` method to pause your code for a given duration.
119-
120-
Internally this uses the simulation's own clock and so is suitable for use in
121-
place of `time.sleep`. Note that, just as with `time.sleep`, while your code is
122-
sleeping your robot will continue any actions it was doing.
123-
124-
``` python
125-
R = Robot()
126-
127-
# Blink the output
128-
R.ruggeduinos[0].digital_write(A_PIN, 1)
129-
R.sleep(1.5) # Sleep for a second and a half of simulation time
130-
R.ruggeduinos[0].digital_write(A_PIN, 0)
131-
```
132-
133-
#### Getting the current time
134-
135-
If you need to measure the time since some previous moment within the simulator,
136-
`Robot.time` can be used in place of `time.time` to get a number (in seconds)
137-
which increases in line with simulation time.
138-
139-
Time zero as returned by this method is the point at which the simulation began,
140-
however you should not rely on that being a useful reference point as it may not
141-
be the moment at which the _match_ began.
142-
143-
``` python
144-
R = Robot()
145-
146-
then = R.time()
147-
148-
# .. do some other things ..
149-
150-
now = R.time()
151-
152-
duration = now - then
153-
```
120+
As a result the API present in the simulator supports a slightly different
121+
approach to handling time. See the documentation about [simulated time](./time)
122+
for more details.
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
---
2+
layout: page
3+
title: Simulated Time
4+
---
5+
6+
# Simulated Time
7+
8+
In the simulated environment, time advances only at the pace that the simulator
9+
is run and in cooperation with the controller code (such as the code controlling
10+
your robot). As a result, using `time.time` to know how long your robot has been
11+
running for or `time.sleep` to wait for some duration may be unreliable.
12+
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>
61+
62+
## Sleeping
63+
64+
If you want to wait for something to happen within the simulation, and you can
65+
be reasonably confident that it will take a given amount of time, you can use
66+
`sleep` method on your robot to pause your code for a given duration.
67+
68+
Internally this uses the simulation's own clock and so is suitable for use in
69+
place of `time.sleep`. Note that, just as with `time.sleep`, while your code is
70+
sleeping your robot will continue any actions it was doing.
71+
72+
``` python
73+
# Blink the output
74+
R.ruggeduinos[0].digital_write(A_PIN, 1)
75+
R.sleep(1.5) # Sleep for a second and a half of simulation time
76+
R.ruggeduinos[0].digital_write(A_PIN, 0)
77+
```
78+
79+
## Getting the current time
80+
81+
If you need to measure the time since some previous moment within the simulator,
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.
84+
85+
Time zero as returned by this method is the point at which the simulation began,
86+
however you should not rely on that being a useful reference point as it may not
87+
be the moment at which the _match_ began.
88+
89+
``` python
90+
then = R.time()
91+
92+
# .. do some other things ..
93+
94+
now = R.time()
95+
96+
duration = now - then
97+
```
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)