Skip to content

Commit debd789

Browse files
authored
Documentation for Open Bot Brain (#12)
* Initial work on documentation for Open Bot Brain * Add line follower code example to illustrate how the primitives can be used * Explain how to clone WARDuino before building for Zephyr * Add an image showing the line follower robot
1 parent 1d3ffee commit debd789

File tree

4 files changed

+233
-1
lines changed

4 files changed

+233
-1
lines changed

warduino/.vitepress/components/home.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ const {frontmatter: fm} = useData()
5454
<p><a href="./guide/get-started.html">-&gt; Get started</a></p>
5555
<p><a href="./guide/examples/index.html">-&gt; Examples</a></p>
5656
<p><a href="./guide/plugin/">-&gt; VS Code plugin</a></p>
57+
<p><a href="./guide/open-bot-brain.html">-&gt; Open Bot Brain</a></p>
5758
<p><a href="./guide/latch.html">-&gt; Automated testing</a></p>
5859
</article>
5960
<article class="list">

warduino/.vitepress/config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export default defineConfig({
6767
{ text: 'Debugging Hardware', link: '/guide/plugin/tutorial' },
6868
]
6969
},
70+
{ text: 'Open Bot Brain', link: '/guide/open-bot-brain' },
7071
{ text: 'Testing on Hardware', link: '/guide/latch' }
7172
]
7273
},
@@ -124,7 +125,7 @@ export default defineConfig({
124125
{ text: 'Latch API', link: '/latch/api' },
125126
]
126127
},
127-
{ text: 'VS Code Plugin', link: '/reference/plugin' }
128+
{ text: 'VS Code Plugin', link: '/reference/plugin' },
128129
]
129130
},
130131

warduino/guide/open-bot-brain.md

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
# Open Bot Brain
2+
The WARDuino VM has support for [specialised hardware](https://www.openbotbrain.org/) that can be used to control Lego Mindstorms components.
3+
4+
## Prerequisites
5+
To use WARDuino on this hardware, the Zephyr platform should be used. To get started you will first need to install Zephyr by following the [official installation guide](https://docs.zephyrproject.org/latest/develop/getting_started/index.html).
6+
7+
By default Zephyr will use the [STM32CubeProgrammer](https://www.st.com/en/development-tools/stm32cubeprog.html) to flash the board, which you will also need to install.
8+
9+
## Cloning WARDuino
10+
To get started with WARDuino for Open Bot Brain you will first need to clone it using the following command:
11+
```bash
12+
git clone --recursive [email protected]:TOPLLab/WARDuino.git
13+
```
14+
15+
## Adding your program
16+
Before building WARDuino you will need to specify the program which the VM will execute when starting. To achieve this, you will need to compile your WebAssembly program and place the resulting executable in the `platforms/Zephyr` directory with the name `upload.wasm`.
17+
18+
### Example
19+
The following program written in [AssemblyScript](https://www.assemblyscript.org/) will make one of the built-in LEDs on the board blink.
20+
```ts:line-numbers [AS]
21+
@external("env", "chip_delay")
22+
declare function delay(value: i32): void;
23+
@external("env", "chip_pin_mode")
24+
declare function pinMode(pin: i32, mode: i32): void;
25+
@external("env", "chip_digital_write")
26+
declare function digitalWrite(pin: i32, value: i32): void;
27+
28+
enum PinVoltage {
29+
LOW = 0,
30+
HIGH = 1,
31+
}
32+
33+
enum PinMode {
34+
INPUT = 0,
35+
OUTPUT = 2
36+
}
37+
38+
enum Pin {
39+
powerSupply = 60,
40+
led1 = 45,
41+
}
42+
43+
function setup(): void {
44+
// Configure and enable power supply pin (active low).
45+
pinMode(Pin.powerSupply, PinMode.OUTPUT);
46+
delay(500); // Wait for 500ms to avoid current spike.
47+
digitalWrite(Pin.powerSupply, PinVoltage.LOW);
48+
49+
// Configure LED.
50+
pinMode(Pin.led1, PinMode.OUTPUT);
51+
}
52+
53+
export function main(): void {
54+
setup();
55+
56+
while (true) {
57+
digitalWrite(Pin.led1, PinVoltage.HIGH);
58+
delay(500);
59+
digitalWrite(Pin.led1, PinVoltage.LOW);
60+
delay(500);
61+
}
62+
}
63+
```
64+
65+
This program can be compiled using the following command if you have the [AssemblyScript](https://www.assemblyscript.org/) compiler globally installed on your system:
66+
```bash
67+
asc blink.ts -o upload.wasm
68+
```
69+
70+
With the program compiled and placed in the `platforms/Zephyr` directory you should now have the following directory structure:
71+
72+
```tree
73+
.
74+
├── app.overlay
75+
├── boards
76+
│   ├── ...
77+
├── CMakeLists.txt
78+
├── Kconfig
79+
├── main.cpp
80+
├── prj.conf
81+
└── upload.wasm // [!code ++]
82+
```
83+
84+
## Building
85+
To build WARDuino for Open Bot Brain, run the following commands starting from the root directory of the repository:
86+
```bash
87+
cd platforms/Zephyr
88+
source ~/zephyrproject/zephyr/zephyr-env.sh
89+
source ~/zephyrproject/.venv/bin/activate
90+
west build -b stm32l496g_disco
91+
```
92+
93+
## Flashing
94+
To flash WARDuino to the board, the following command can be used. By default this will use the [STM32CubeProgrammer](https://www.st.com/en/development-tools/stm32cubeprog.html). You can also use a different runner by using the `--runner` flag, more info can be found in the [Zephyr documentation](https://docs.zephyrproject.org/latest/boards/st/nucleo_l496zg/doc/index.html#flashing).
95+
```bash
96+
west flash
97+
```
98+
99+
Once flashed, you should start seeing one of the LEDs blink.
100+
101+
## Board information
102+
The Open Bot Brain has various built-in LEDs and buttons, in the following table we list some of the pin numbers for use in your programs.
103+
|Description|Pin number|
104+
|:--|---:|
105+
|Power supply|60|
106+
|Motor AB Driver sleep|46|
107+
|Motor CD Driver sleep|78|
108+
|Led 1|45|
109+
|Led 2|56|
110+
|Led 3|39|
111+
|Button SW1 |21|
112+
|Button SW5 |20|
113+
|Button SW2 |10|
114+
115+
## Lego Mindstorms Primitives
116+
Aside from the built-in LEDs and buttons, Open Bot Brain also has 4 input and 4 output ports that can be used to control Lego Mindstorms components.
117+
118+
### Outputs
119+
In terms of outputs we support both the NXT and EV3 (medium and large) motors. These can be controlled using the following primitives:
120+
121+
| Primitive | Description |
122+
|----------------------------|-------------------------------------------|
123+
| `drive_motor(port, speed)` | Makes the motor spin at a constant speed. |
124+
| `drive_motor_ms(port, speed, time)` | Makes the motor spin for x ms. |
125+
| `drive_motor_degrees(port, speed, angle)` | Makes the motor rotate x degrees. |
126+
| `stop_motor(port)` | Actively slows down the motor. |
127+
128+
### Inputs
129+
In terms of inputs we supports UART based sensors such as the EV3 Color and Gyro sensors. These can be controlled using the following primitives:
130+
131+
| Primitive | Description |
132+
|----------------------------|-------------------------------------------|
133+
| `setup_uart_sensor(port, mode)` | Configure the UART sensor and set its mode. |
134+
| `read_uart_sensor(port)` | Read the latest value from the UART sensor. |
135+
136+
137+
### Example usage
138+
To illustrate how some of these primitives could be used we show a simple line follower example program. This robot has two wheels and drives left or right depending on if it sees a dark or a light color with its color sensor. By doing so the robot will follow the edge of a dark line on the floor.
139+
140+
![Line follower robot](/images/line-follower.jpg)
141+
142+
Since a lot of this code is similar to the blink example, we highlighted the main changes. In particular we now import three extra primitives and disable the sleep mode on the motor drivers. Using this setup a simple line follower can be written in just a few lines of code as shown in the `main` function.
143+
144+
```ts:line-numbers [AS]
145+
@external("env", "chip_delay")
146+
declare function delay(value: i32): void;
147+
@external("env", "chip_pin_mode")
148+
declare function pinMode(pin: i32, mode: i32): void;
149+
@external("env", "chip_digital_write")
150+
declare function digitalWrite(pin: i32, value: i32): void;
151+
@external("env", "drive_motor") // [!code focus:6]
152+
declare function driveMotor(port: i32, speed: i32): void;
153+
@external("env", "setup_uart_sensor")
154+
declare function setupUARTSensor(port: i32, mode: i32): void;
155+
@external("env", "read_uart_sensor")
156+
declare function readUARTSensor(port: i32): i32;
157+
158+
enum PinVoltage {
159+
LOW = 0,
160+
HIGH = 1,
161+
}
162+
163+
enum PinMode {
164+
INPUT = 0,
165+
OUTPUT = 2
166+
}
167+
168+
enum Pin {
169+
powerSupply = 60,
170+
motorABDriverSleep = 46,
171+
motorCDDriverSleep = 78,
172+
}
173+
174+
enum InputPort {
175+
portA = 0,
176+
portB,
177+
portC,
178+
portD
179+
}
180+
181+
enum OutputPort {
182+
port1 = 0,
183+
port2,
184+
port3,
185+
port4
186+
}
187+
188+
enum ColorSensorMode {
189+
reflectivity = 0,
190+
ambient,
191+
colour
192+
}
193+
194+
function setupBoard(): void {
195+
// Configure and enable power supply pin (active low).
196+
pinMode(Pin.powerSupply, PinMode.OUTPUT);
197+
delay(500); // Wait for 500ms to avoid current spike.
198+
digitalWrite(Pin.powerSupply, PinVoltage.LOW);
199+
200+
// Disable sleep on motor AB driver. // [!code focus:7]
201+
pinMode(Pin.motorABDriverSleep, PinMode.OUTPUT)
202+
digitalWrite(Pin.motorABDriverSleep, PinVoltage.HIGH)
203+
204+
// Disable sleep on motor CD driver.
205+
pinMode(Pin.motorCDDriverSleep, PinMode.OUTPUT)
206+
digitalWrite(Pin.motorCDDriverSleep, PinVoltage.HIGH)
207+
}
208+
209+
const threshold = 5;
210+
211+
export function main(): void { // [!code focus:19]
212+
setupBoard();
213+
214+
// Setup color sensor.
215+
setupUARTSensor(InputPort.portA, ColorSensorMode.reflectivity);
216+
217+
while (true) {
218+
if (readUARTSensor(InputPort.portA) < threshold) {
219+
// Drive right.
220+
driveMotor(OutputPort.port1, 5000);
221+
driveMotor(OutputPort.port2, 0);
222+
}
223+
else {
224+
// Drive left.
225+
driveMotor(OutputPort.port1, 0);
226+
driveMotor(OutputPort.port2, 5000);
227+
}
228+
}
229+
}
230+
```
788 KB
Loading

0 commit comments

Comments
 (0)