Overview¶
Ariadne is a micromouse: a small autonomous robot that explores an unknown 16 × 16 maze, finds the shortest route to the centre, then races it. It is named after the thread that led Theseus out of the labyrinth, which is what its planner computes.
It is also a study in designing a robot in simulation first. Every turn, gain and threshold is derived, implemented twice (Python for the simulator, C++ for the robot), and tested against the other before any hardware exists.
-Wall; 33 % RAM, 27 % flashThe problem¶
A micromouse run has two halves. In the search the robot knows nothing and must map enough of the maze to be sure it has the shortest path. In the fast run it already knows the path and the only thing that matters is time.
The classic first robot does both with stop-and-pivot motion: drive to a cell centre, stop, rotate in place, go. It is simple and robust, and slow: on the test mazes more than half of the fast run is spent stopping and turning. Doing better means the robot must turn while moving. That raises four engineering problems:
- Geometry. A curve must fit between posts and walls with the robot's real body, not a point. Which curves are safe, and how fast can each be taken?
- Planning. Once turns have different lengths and speeds, the shortest path in cells is no longer the fastest path in seconds.
- Execution. At speed there is no stopping to re-align: the robot has to follow a curved reference exactly, with only odometry, a gyro and wall sensors sampled at 30 Hz.
- Verification. None of this can be tuned by trial and error without wrecking the robot; it has to be right in simulation first.
The approach¶
flowchart LR
subgraph Offline["Offline (Python, sim/)"]
TD["Turn designer<br/>clothoid search,<br/>body sweep"] -->|turn_table.h| LIB[(30-turn<br/>library)]
end
subgraph Robot["On the robot (C++, firmware/)"]
S["Search<br/>flood fill"] --> M[(maze map)]
M --> P["Planner<br/>Dijkstra on<br/>edges x 8 headings"]
LIB --> P
P --> SP["Speed plan<br/>two-pass"]
SP --> R["Plan runner<br/>1 kHz"]
R --> C["PD + feedforward<br/>+ path following"]
C --> MOT((motors))
E["Pose estimate<br/>encoders + gyro"] --> C
O["Wall observer<br/>offset, heading,<br/>gyro bias"] --> E
end
| Problem | Ariadne's answer | Where |
|---|---|---|
| Geometry | Clothoid–arc–clothoid turns found by grid search; the body is swept against posts and a wall on every edge the turn does not cross (the worst maze it can meet); 12 mm minimum clearance | Notebook 11 |
| Planning | Dijkstra over (edge, 8 headings) with integer time costs, then a forward/backward speed plan that gives the exact time of the chosen path | Notebook 12 |
| Execution | A plan runner with one continuous distance coordinate, path following on a pose estimate, and a distance-domain observer that fuses walls into offset, heading and gyro bias | Notebook 13 |
| Verification | 10 kHz physics with friction circles, quantisation and sensor models; Monte Carlo with confidence intervals; C++ checked against Python vectors | Design studies |
How the two codebases agree¶
flowchart TB
PY["Python planner + executor<br/>(sim/planner.py, sim/robot.py)"] -->|export_vectors.py| V[(vectors.h<br/>4 mazes x 2 modes)]
V --> T["Native C++ tests<br/>(pio test -e native)"]
CPP["C++ planner + runner<br/>(mazecore, motioncore)"] --> T
T -->|"same Dijkstra cost (integer)<br/>same command sequence<br/>time within 2 ms<br/>end pose within 2 mm"| OK{{CI}}
The planner works in integer units of 0.1 ms and both languages compute every cost with the same double-precision operations in the same order, so the chosen path is identical, not just similar. Tie-breaking is identical too: an indexed binary heap ordered by (cost, state id) pops in the same order as Python's heapq of tuples.
What it is not (yet)¶
- It has not driven a real maze. Everything on this site is simulation and host tests. Building and validating the hardware is the next milestone; see the roadmap and how you can sponsor it.
- The search still pivots. Smooth turns are used in the fast run; smooth search turns need a decision point before the turn starts and are on the roadmap.
- Diagonals are opt-in. They are faster but, with the current sensors and a consumer IMU, less reliable in simulation (see the gyro study).