Skip to content

Commit 5f4764d

Browse files
authored
Merge pull request #230 from srobo/dgt/sr2022-ruggeduino-update
SR2022 Update Ruggeduino docs
2 parents f6cf4fe + 210a285 commit 5f4764d

File tree

2 files changed

+52
-211
lines changed

2 files changed

+52
-211
lines changed

programming/sr/ruggeduinos/custom_firmware.md

Lines changed: 18 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,15 @@ This documentation refers to a feature which is only available on the physical r
1212

1313
The Ruggeduino that came as part of your kit was shipped with a firmware that provides the functionality outlined in the [Ruggeduino](/docs/programming/sr/ruggeduinos) page.
1414
You may wish to extend the functionality of this firmware, or completely replace it.
15-
The `sr.robot` library provides support for three Ruggeduino firmware scenarios:
15+
The `sr.robot3` library provides support for three Ruggeduino firmware scenarios:
1616

1717
1. Default SR firmware
1818
2. [Extended SR firmware](#extension): Firmwares that add commands to the default SR firmware.
1919
3. [Completely custom](#completely): Any firmware not derived from the SR firmware.
2020

21-
By default, the [`sr.robot`](/docs/programming/sr/) library assumes that all connected Ruggeduinos are running the SR firmware.
22-
If you wish to use an extended SR firmware, or completely custom firmware,
23-
then you need to tell the `Robot` object what to do with your Ruggeduino(s).
24-
To do this, you will need to expand the initialisation of your `Robot` object as detailed [here](/docs/programming/sr/#CustomRobotInit).
25-
Your code will then look something like this:
26-
27-
~~~~~ python
28-
from sr.robot import *
29-
30-
R = Robot.setup()
31-
32-
R.init()
33-
34-
R.wait_start()
35-
36-
# The rest of your code
37-
~~~~~
38-
39-
The next step depends on whether you are running an extended SR firmware, or a completely custom firmware.
21+
By default, the [`sr.robot3`](/docs/programming/sr/) library assumes that all connected Ruggeduinos are running the SR firmware
22+
or firmware which is compatible with the SR Ruggeduino firmware.
23+
If you're using completely custom firmware, you'll need to tell the kit to ignore the ruggeduino so that you're able to define your own setup logic.
4024

4125
[Extension of the SR firmware](#extension) {#extension}
4226
------------------------------
@@ -95,149 +79,20 @@ Your command can read additional data from the serial port if it requires additi
9579
It can also write a response back to the host (your Python code).
9680
Have a look at the `command_read()` function to see how to do this.
9781

98-
### Step 2: Extend the `Ruggeduino` class
99-
100-
Your robot's python code will, by default, use a `Ruggeduino` object to communicate with the Ruggeduino.
101-
The object returned to you when you type `R.ruggeduinos[0]` is a `Ruggeduino` instance.
102-
This object knows how to talk to the default command handlers in the SR firmware.
103-
104-
<div class="info" markdown="1">
105-
Don't worry if you don't know what "object" means -- you can probably blag this without knowing!
106-
If you do want to know about them, you'll find introductions to them all over the web.
107-
You could try [this one](http://www.jesshamrick.com/2011/05/18/an-introduction-to-classes-and-inheritance-in-python/), for example.
108-
</div>
109-
110-
You'll need to extend the `Ruggeduino` class, giving it at least one extra method to perform your command.
111-
Start by adding this to your code:
112-
113-
~~~~~ python
114-
from sr.robot import *
115-
116-
class CustomisedRuggeduino(Ruggeduino):
117-
pass
118-
~~~~~
119-
120-
You've just declared a class called `CustomisedRuggeduino` (you will probably want to call it something else that makes more sense in your application).
121-
At the moment, it behaves in exactly the same way as the `Ruggeduino` class.
122-
You now need to add your custom method to it:
123-
124-
~~~~~ python
125-
from sr.robot import *
126-
127-
class CustomisedRuggeduino(Ruggeduino):
128-
129-
# Your function for instructing a Ruggeduino to bake a cake
130-
def bake_cake(self):
131-
with self.lock:
132-
self.command("c")
133-
~~~~~
134-
135-
Skipping ahead for a moment: Once we've told your `Robot` object about this `CustomisedRuggeduino`
136-
class (which we do in the next step), you will be able to do this:
137-
138-
~~~~~ python
139-
R.ruggeduinos[0].bake_cake()
140-
# and you'll still be able to do this:
141-
R.ruggeduinos[0].digital_read(3)
142-
~~~~~
143-
144-
<div class="warning" markdown="1">
145-
The IDE will unfortunately error about the lack of a `bake_cake` method (or your equivalent) in the above code.
146-
This is an expected restriction of the way the IDE checks the syntax of your code.
147-
148-
You can therefore ignore these errors (though you should be careful that the error is one of these and not something else).
149-
</div>
150-
151-
#### `with self.lock:`
152-
153-
You'll notice that the code above contains a line that reads:
154-
155-
~~~~~ python
156-
with self.lock:
157-
~~~~~
158-
159-
Whenever you call `self.command`, you need to ensure that it is called within a block of code headed by this `with` statement.
160-
This is a tool that makes your code "thread-safe".
161-
If you're not using threads, then you will still need to use it, but it won't affect the behaviour of your program.
82+
### Step 2: Use your new command from Python
16283

163-
#### Responses
164-
165-
The response from your command is returned by the `self.command` function.
166-
Remember that it will be a string, so you will need to convert it as necessary.
167-
168-
If, for example, our cake-baking function on our Ruggeduino responds with the number of cakes that were baked, then we could do this:
84+
You can send a custom command from your Python code to the Ruggeduino to control your cake-baking.
16985

17086
~~~~~ python
171-
class CustomisedRuggeduino(Ruggeduino):
172-
173-
def bake_cake(self):
174-
with self.lock:
175-
resp = self.command("c")
176-
return int(resp)
87+
cake_result = R.ruggeduino.command("c")
17788
~~~~~
17889

179-
180-
### Step 3: Tell the `Robot` to use your extended class
181-
182-
Now that you've extended the `Ruggeduino` class to create your `CustomisedRuggeduino` class,
183-
it's time to tell the `Robot` object about it using the `ruggeduino_set_handler_by_fwver` function:
184-
185-
~~~~~ python
186-
from sr.robot import *
187-
188-
# The class that you wrote in step 2
189-
class CustomisedRuggeduino(Ruggeduino):
190-
def bake_cake(self):
191-
with self.lock:
192-
self.command("c")
193-
194-
R = Robot.setup()
195-
196-
# Register the custom class with the Robot object
197-
R.ruggeduino_set_handler_by_fwver("SRcustom", CustomisedRuggeduino)
198-
199-
R.init()
200-
201-
R.wait_start()
202-
203-
# Now you can call your custom function!
204-
R.ruggeduinos[0].bake_cake()
205-
~~~~~
90+
The `cake_result` variable will contain any response from your firmware, if you sent one.
20691

20792
You're done! You can now use your custom cake-baking firmware!
20893

209-
210-
#### Multiple Ruggeduinos with Extended SR Firmwares
211-
212-
You may wish to use multiple Ruggeduinos with your robot, each supporting a different set of commands.
213-
There are two ways to go about this.
214-
215-
You can change the string "SRCustom" in your firmwares to be something different
216-
(but make sure you keep the colon that follows it!),
217-
and then change the string you pass to `ruggeduino_set_handler_by_fwver` to suit.
218-
For example, if you change it to be "CakeBaker" in one of your ruggeduinos,
219-
but leave it as "SRCustom" in the other, then your enumeration code would become:
220-
221-
~~~~~ python
222-
R.ruggeduino_set_handler_by_fwver("SRcustom", CustomisedRuggeduino)
223-
R.ruggeduino_set_handler_by_fwver("CakeBaker", CakeBakerRuggeduino)
224-
~~~~~
225-
226-
Alternatively, you can set the handling class using the ID of the Ruggeduino.
227-
The Ruggeduino IDs are written to the robot log when you run a program on your robot with your Ruggeduino connected.
228-
Instead of using `ruggeduino_set_handler_by_fwver`, you use `ruggeduino_set_handler_by_id`:
229-
230-
~~~~~ python
231-
R.ruggeduino_set_handler_by_id("752303138333517171B1", CustomisedRuggeduino)
232-
R.ruggeduino_set_handler_by_id("10231028301928310283", CakeBakerRuggeduino)
233-
~~~~~
234-
235-
You will then be able to access your ruggeduino using its ID like so:
236-
237-
~~~~~ python
238-
R.ruggeduinos["752303138333517171B1"]
239-
~~~~~
240-
94+
If you have multiple Ruggeduino running custom firmware, you can keep track of which one is which
95+
by using the serial numner.
24196

24297
[Completely custom firmware](#completely) {#completely}
24398
----------------------------
@@ -249,43 +104,30 @@ To configure a `Robot` object to ignore a Ruggeduino with custom firmware, you w
249104
The Ruggeduino ID is a 20 character string of mostly numbers, and is output in the robot log when you run a program on your robot with your
250105
Ruggeduino connected.
251106

252-
After calling `Robot.setup()`, you should call the `ruggeduino_ignore_id`
253-
method of the robot object, with the ID as an argument.
254107
You'll need the ID later, so it's best to save it into a variable:
255108

256109
~~~~~ python
257110
from sr.robot import *
258111

259112
RUGGEDUINO_ID = "752303138333517171B1" # Replace this with the actual ID
260113

261-
R = Robot.setup()
262-
263-
R.ruggeduino_ignore_id( RUGGEDUINO_ID )
264-
265-
R.init()
266-
267-
R.wait_start()
114+
R = Robot(ignored_ruggeduinos=["752303138333517171B1"])
268115

269116
# The rest of your code
270117
~~~~~
271118

272119
If you need to communicate with the Ruggeduino firmware, you will need its serial device path.
273-
This is accessible after the `R.init()` call through the list of Ruggeduinos:
274-
275-
~~~~~ python
276-
# ... Robot.setup() ... etc.
277120

278-
R.init()
121+
This is accessible from the `ignored_ruggeduinos` dictionary.
279122

280-
ruggeduino_device = R.ruggeduinos[RUGGEDUINO_ID].path
281-
282-
# Do your Ruggeduino initialisation here if you wish
283-
284-
R.wait_start()
123+
~~~~~ python
124+
ruggeduino_device = R.ignored_ruggeduinos[RUGGEDUINO_ID]
285125

286126
# The rest of your code
287127
~~~~~
288128

129+
The device path will look something like `/dev/ttyACM1`.
130+
289131
You may wish to use pyserial to communicate with the Ruggeduino, in which case you could open it like so:
290132

291133
~~~~~ python
@@ -294,12 +136,9 @@ from sr.robot import *
294136

295137
RUGGEDUINO_ID = "752303138333517171B1"
296138

297-
R = Robot.setup()
298-
R.ruggeduino_ignore_id( RUGGEDUINO_ID )
299-
R.init()
300-
R.wait_start()
139+
R = Robot(ignored_ruggeduinos=[RUGGEDUINO_ID])
301140

302-
ser = serial.Serial( R.ruggeduinos[RUGGEDUINO_ID].path )
141+
ser = serial.Serial(R.ignored_ruggeduinos[RUGGEDUINO_ID])
303142

304143
~~~~~
305144

programming/sr/ruggeduinos/index.md

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,45 +10,45 @@ The [Ruggeduino](http://ruggedcircuits.com/html/ruggeduino.html)
1010
provides a total of 18 pins for either digital input or output (labelled 2 to 13 and A0 to A5),
1111
including 6 for analogue input (labelled A0 to A5).
1212

13-
The `ruggeduinos` object is used to control a collection of Ruggeduinos.
14-
Similar to `motors` and `servos`, `ruggeduinos` can be used like a list.
15-
To do something with the **first Ruggeduino**, you would use:
13+
When a single Ruggeduino is connected to your robot, you can control it
14+
using the `ruggeduino` object.
1615

1716
~~~~~ python
18-
R.ruggeduinos[0].something...
17+
R.ruggeduinos.something...
1918
~~~~~
2019

21-
...because indexes are 0-based (counting starts from 0, not 1).
22-
23-
When you have more than one Ruggeduino board connected to your kit
24-
they will be ordered based upon their serial number.
25-
2620
The serial number of each detected Ruggeduino is printed to the log when your robot starts.
2721
It will look something like this:
2822

2923
~~~~~ not-code
30-
Found the following devices:
31-
- Ruggeduinos:
32-
0: Ruggeduino( serialnum = "752303138333517171B1" )
24+
sr.robot3.robot INFO - Found Ruggeduino - 752303138333517171B1
3325
~~~~~
3426

35-
In addition, like `motors`, `ruggeduinos` is actually a dictionary.
36-
As a result, in `ruggeduinos` you can also use the Ruggeduino serial number as a key.
27+
If you have more than one Ruggeduino attached, the `ruggeduinos` object
28+
can be used to control a collection of Ruggeduinos. Similar to `motors`
29+
and `servos`, `ruggeduinos` is a dictionary accessed by serial number.
3730
For example, if you had a board whose serial number was "752303138333517171B1",
3831
you could do this instead:
3932

4033
~~~~~ python
4134
R.ruggeduinos["752303138333517171B1"].something...
4235
~~~~~
4336

37+
<div class="warning">
38+
When you have more than one Ruggeduino board connected to your kit,
39+
you must use `R.ruggeduinos` and index by serial number. This is so
40+
that the kit knows which Ruggeduino you want to control.
41+
</div>
42+
43+
4444
[Setting pin modes](#pinmodes) {#pinmodes}
4545
--------------------------------------------------------------------------
4646

4747
To use one of the pins on the Ruggeduino, you must first set whether you want it to behave as an input or as an output.
4848
You can do this with the following code:
4949

5050
~~~~~ python
51-
R.ruggeduinos[RUGGEDUINO_BOARD_NUMBER].pin_mode(PIN_NO, MODE)
51+
R.ruggeduino.pins[10].mode = MODE
5252
~~~~~
5353

5454
The possible values for `MODE` are:
@@ -65,12 +65,12 @@ The possible values for `MODE` are:
6565
An example of how to use this is below:
6666

6767
~~~~~ python
68-
# set Ruggeduino board 0's pin 2 to output
69-
R.ruggeduinos[0].pin_mode(2, OUTPUT)
70-
# set Ruggeduino board 0's pin 3 to input
71-
R.ruggeduinos[0].pin_mode(3, INPUT)
72-
# set Ruggeduino board 0's pin 4 to input and enable pull-up resistor
73-
R.ruggeduinos[0].pin_mode(4, INPUT_PULLUP)
68+
# set Ruggeduino pin 2 to output
69+
R.ruggeduino.pins[2].mode = OUTPUT
70+
# set Ruggeduino pin 3 to input
71+
R.ruggeduinos[0].pins[3].mode = INPUT
72+
# set Ruggeduino git commit -m "pin 4 to input and enable pull-up resistor
73+
R.ruggeduinos[0].pins[4].mode = INPUT_PULLUP
7474
~~~~~
7575

7676
<div class="warning">You cannot use pins 0 and 1, as using these would disrupt communications between the Ruggeduino and the Power Board.</div>
@@ -81,37 +81,39 @@ R.ruggeduinos[0].pin_mode(4, INPUT_PULLUP)
8181
You can read a **digital** input pin with the following code:
8282

8383
~~~~~ python
84-
# R.ruggeduinos[RUGGEDUINO_BOARD_NUMBER].digital_read(PIN_NO)
84+
# R.ruggeduinos[RUGGEDUINO_BOARD_NUMBER].pins[PIN_NO].digital_read()
8585

86-
# to read Ruggeduino board 0's digital pin 3...
87-
pin0 = R.ruggeduinos[0].digital_read(3)
86+
# to read Ruggeduino's digital pin 3...
87+
pin0 = R.ruggeduino.pins[3].digital_read()
8888
~~~~~
8989

9090
`pin0` will now contain `True` or `False` depending on whether the pin was high (3.3v) or low (0v), respectively.
9191

9292
You can read an **analogue** input pin with the following code:
9393

9494
~~~~~ python
95-
# R.ruggeduinos[RUGGEDUINO_BOARD_NUMBER].analogue_read(PIN_NO)
95+
# R.ruggeduinos[RUGGEDUINO_BOARD_NUMBER].pins[PIN_NO].analogue_read()
9696

97-
# to read Ruggeduino board 0's analogue pin A0...
98-
pin0 = R.ruggeduinos[0].analogue_read(0)
97+
# to read Ruggeduino's analogue pin A0...
98+
pin0 = R.ruggeduino.pins[A0].analogue_read()
9999
~~~~~
100100

101+
The analogue pin numbers are available as `A0`, `A1`, `A2`, `A3`, `A4`, and `A5` respectively.
102+
101103

102104
[Output](#output) {#output}
103105
--------
104106

105107
You can only set digital outputs (there's no analogue output, although you may feel free to modify the Ruggeduino's firmware to add the ability to output [PWM](https://wikipedia.org/wiki/Pulse-width_modulation "Pulse-width modulation") if you desire). To set a digital output pin, you would use the following:
106108

107109
~~~~~ python
108-
# R.ruggeduinos[RUGGEDUINO_BOARD_NUMBER].digital_write(PIN_NO, VALUE)
110+
# R.ruggeduinos[RUGGEDUINO_BOARD_NUMBER].pins[PIN_NO].digital_write(VALUE)
109111

110-
# to set Ruggeduino board 0's pin 2 high:
111-
R.ruggeduinos[0].digital_write(2, True)
112+
# to set Ruggeduinos pin 2 high:
113+
R.ruggeduino.pins[2].digital_write(True)
112114

113-
# to set Ruggeduino board 0's pin 2 low:
114-
R.ruggeduinos[0].digital_write(2, False)
115+
# to set Ruggeduino's pin 2 low:
116+
R.ruggeduino.pins[2].digital_write(False)
115117
~~~~~
116118

117119
[Pull-up resistors](#pullup) {#pullup}

0 commit comments

Comments
 (0)