This project is a low-cost differential-drive robot platform built for students learning mechatronics and embedded programming. It combines practical robot assembly with staged MicroPython challenges, from basic wall-following PID to competition-style rescue behavior.
- Web Simulator: https://tempehs.github.io/AIDriver_MicroPython_Challanges/
- MicroPython Lab: https://lab-micropython.arduino.cc/
All parts are available from common suppliers (for example, AliExpress), with chassis parts made by laser cutting and 3D printing.
- Laser-cut chassis file and 3 mm plywood
- 3D-printed components (see manufacturing_files)
- RP2040 Uno development board
- Seeed Grove Base Shield V2.0 (UNO form factor)
- 2x Seeed Grove Ultrasonic Ranger (front and side, default distance backend)
- 2x VL53L0X ToF distance sensors (optional alternative distance backend)
- Seeed Grove LSM6DS3 6-axis accelerometer + gyroscope
- Omni wheel
- L298N(H) motor shield
- 4x Seeed Grove 4-pin cables
- 2x TT tyres
- 2x TT DC geared motors
- 5.5x2.1 mm barrel jack
- 6x AA battery holder with switch
- 6x AA batteries
Note
This build uses Grove sensors on a Grove Base Shield. The default classroom path uses Grove ultrasonic sensors for front/side distance and an LSM6DS3 for closed-loop gyro turns.
Distance backend choice is simple: use 2x Ultrasonic sensors OR 2x ToF sensors.
Default GPIO map used by AIDriver (all pin numbers are RP2040 GP values).
| Function | Pin |
|---|---|
| Right motor PWM/speed | GP3 |
| Right motor direction | GP12 |
| Right motor brake | GP9 |
| Left motor PWM/speed | GP11 |
| Left motor direction | GP13 |
| Left motor brake | GP8 |
| Mode | Front Sensor Pins | Side Sensor Pins | Notes |
|---|---|---|---|
| Ultrasonic (Grove default) | GP6 SIG | GP4 SIG | Single-wire Grove interface |
| ToF (VL53L0X) | GP29 SDA, GP28 SCL | GP6 SDA, GP5 SCL | Separate SoftI2C buses; both sensors use address 0x29 |
Note
In ToF mode, the front and side VL53L0X sensors are on separate SoftI2C buses, so both can use 0x29 without an address conflict.
The front ToF bus was moved from GP26/GP27 (Uno A0/A1) to GP28/GP29 (Uno A2/A3) because A0/A1 are physically wired to the Arduino Motor Shield's current-sensing outputs (see Pin Summary below). Bit-banging SoftI2C on those pins fought with the shield's analog current-sense lines and caused unreliable ToF readings. Do not reuse A0/A1 (GP26/GP27) for anything else — pick free pins instead.
| Device | Interface | Pins | I2C Address |
|---|---|---|---|
| LSM6DS3 gyroscope | SoftI2C | SDA GP16, SCL GP17 | 0x6A |
| TCS34725 color sensor | SoftI2C + INT | SDA GP16, SCL GP17, INT GP7 | 0x29 |
| SSD1306 OLED display | SoftI2C | SDA GP16, SCL GP17 | 0x3C |
| Rescue-kit servo (optional) | PWM | Unassigned by default | - |
| Function | Pin |
|---|---|
| Firmware recovery/reset | GP2 -> GND during boot |
| Onboard status LED | GP25 |
Note
GP16 and GP17 form one shared bit-banged SoftI2C bus for the gyro (0x6A), color sensor (0x29), and OLED (0x3C). GP7 is used for the color sensor interrupt line.
The controller board is an RP2040 chip on an Uno form-factor board, so every pin has both a MicroPython machine.Pin GPIO number and a silkscreened Uno header name (D0-D13, A0-A5). Dn maps directly to GPn. Only 4 GPIOs on the RP2040 are ADC-capable, so the Uno analog header only exposes 4 real analog pins: A0=GP26, A1=GP27, A2=GP28, A3=GP29. A4/A5 are not wired to RP2040 ADC pins.
The Arduino Motor Shield (L298N) is a fixed-function shield: it hardwires the pins below to its H-bridge and current-sense circuitry whether or not the code reads them. This table lists every pin the shield uses, including the A0/A1 current-sense lines that previously conflicted with the front ToF SoftI2C bus.
| Uno Pin | GPIO | Motor Shield Function | Used By AIDriver |
|---|---|---|---|
| D3 | GP3 | PWM Channel A (speed) | Right motor speed |
| D8 | GP8 | Brake Channel B | Left motor brake |
| D9 | GP9 | Brake Channel A | Right motor brake |
| D11 | GP11 | PWM Channel B (speed) | Left motor speed |
| D12 | GP12 | Direction Channel A | Right motor direction |
| D13 | GP13 | Direction Channel B | Left motor direction |
| A0 | GP26 | Current sense Channel A | Free — do not reuse for I2C/SoftI2C |
| A1 | GP27 | Current sense Channel B | Free — do not reuse for I2C/SoftI2C |
Warning
A0 (GP26) and A1 (GP27) are physically connected to the Motor Shield's analog current-sense outputs. Even though AIDriver never reads them, bit-banging SoftI2C (or anything else) on these two pins caused unreliable readings for the front ToF sensor. This is why the front ToF SoftI2C bus was moved to A2/A3 (GP28/GP29). Avoid A0/A1 for any new sensor wiring.
All other pins used by this project (Grove ultrasonic, ToF, IMU, color sensor, OLED, status LED, recovery pin) sit outside the Uno D0-D13/A0-A5 header and are only available via this board's extra GPIO breakout:
| Function | GPIO | Uno Header Equivalent |
|---|---|---|
| Front ultrasonic SIG | GP6 | D6 |
| Front ultrasonic ECHO (legacy) | GP7 | D7 |
| Side ultrasonic SIG | GP4 | D4 |
| Side ultrasonic ECHO (legacy) | GP5 | D5 |
| Front ToF SoftI2C SDA | GP29 | A3 |
| Front ToF SoftI2C SCL | GP28 | A2 |
| Side ToF SoftI2C SDA | GP6 | D6 |
| Side ToF SoftI2C SCL | GP5 | D5 |
| IMU/color/OLED SoftI2C SDA | GP16 | none (extra breakout) |
| IMU/color/OLED SoftI2C SCL | GP17 | none (extra breakout) |
| Color sensor interrupt | GP7 | D7 |
| Firmware recovery/reset | GP2 | D2 |
| Onboard status LED | GP25 | none (extra breakout) |
Note
TempeHS senior software engineering students may have already completed these steps.
See Assembly_Instructions.md for full assembly and hardware test steps.
The build system freezes AIDriver libraries for fast import while keeping main.py and config.py editable on the device filesystem. Existing files are preserved; missing files are provisioned from bundled defaults.
The bundled config starts with zero numeric values and commented starting ranges. Fill in required settings before running; provisioning does not install the tuned test-only config or make an unfinished configuration runnable.
Quick build:
cd /workspaces/RP2040_Competition_Robot/.devcontainer
./build_firmware.shRecovery mode:
- If
main.pyis corrupted, hold GPIO2 low (connect GP2 to GND) during boot. - Recovery restores default
main.pyand clearsevent_log.txt, but preservesconfig.py. - To explicitly reset config, call
robot_recovery.restore_config()from the MicroPython REPL. It backs up the old source before restoring the zeroed template; recover or tune required settings before restarting main.
Full guide: Build_Custom_MicroPython_Firmware.md
- Set
DEBUG_AIDRIVER = Truein shared config for richer runtime logs. - The firmware creates a run-scoped
event_log.txtnext tomain.py. - In recovery mode (GPIO2 held low at boot), main and the event log are reset; config is retained.
Keep one editable config.py while replacing main.py for each challenge.
Start from the student config, then use the same file
in the simulator and on the robot. Numeric settings start at zero; use the
comments as starting guidance and tune the settings needed by the current main.
Main contains algorithms and runtime state, not duplicate tuning.
The simulator has main.py and config.py tabs in the same editor. Run and Step use main with the latest config regardless of which tab is visible. Stop before using Validate config.py. Validation checks required variable names, Python syntax and types only; it does not validate values or calibration. Zeroed settings can pass validation without being suitable for motion.
Import, download, copy and reset act on the selected tab. Both files save independently in the browser. Transfer both files to the robot initially, then replace only main unless you deliberately retune. Reset Main and Reset Robot preserve config; Reset Config restores the zeroed template after confirmation. See the firmware guide for recovery that preserves config and an explicit config reset.
Distance targets use the sensor's reported reading, not a ruler measurement.
A setting of 50 does not guarantee a physical gap of 50 mm. With the motors
stopped, compare front and side readings with measured clearances separately;
different sensors can have different offsets or scales. Set TARGET_WALL_DISTANCE
from the side reading at the desired clearance. Set FRONT_SLOW_DISTANCE and
FRONT_STOP_DISTANCE from the front readings at the desired slowdown and safe
turning positions, allowing space for the chassis and stopping motion. Retest
at a controlled speed after changing robots or sensors. Do not use -1 as a
target. The sensor readings and type-only config validation remain unchanged.
Students complete stages in order, keeping one purpose-organised config and replacing only main. Algorithms remain visible and editable; there is no need to copy tuning between programs. Start with the shared configuration instructions.
Stage 1: PID wall following
- Challenge_1.md - P control
- Challenge_2.md - PD control
- Challenge_3.md - Full PID
Stage 2: State-machine maze solving
- Challenge_4.md - Corner detection and first state machine
- Challenge_5.md - Outside corners (nib state)
- Challenge_6.md - Dead ends and nibs in one machine
- Challenge_7.md - Full maze capstone
Stage 3: Rescue sensors and competition behavior
- Challenge_8.md - Ground color detection
- Challenge_9.md - No-go zones and recovery
- Challenge_10.md - Competition run, victims, score, OLED
Use the web simulator to test before uploading to hardware: https://tempehs.github.io/AIDriver_MicroPython_Challanges/
- Rescue_Maze_Rules_Summary.md: plain-language guide to the RoboCup Junior Australia Rescue Maze rules.
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0).


