Getting started¶
This is the path from a box of parts to a robot that maps a room and drives it. Steps 1 to 3 run on your workstation (step 3 with two parts on its USB); from step 4 on they run on the Pi.
If you want to try the software before building anything, skip to Simulation — it needs no hardware and runs the same launch files.
Prerequisites¶
- The robot, assembled. Printing, assembly and wiring are covered in Printing & assembly and Wiring & power; the parts list is the BOM.
- A Raspberry Pi 5 running 64-bit Linux. Ubuntu 24.04 and Raspberry Pi OS
Bookworm both work — the
Raspberry Pi Imager route is
Raspberry Pi OS (other) → Raspberry Pi OS Lite. To hand a clean Pi its
identity, network and build in one shot instead, render a cloud-init image
with
pixi run provision(see the fleet runbook). - pixi installed. Everything else — ROS 2 Lyrical, Nav2, the drivers — is pulled in by pixi. There is no system ROS install.
1. Clone¶
Forgot --recurse-submodules? pixi run submodules fetches them afterwards.
2. Build¶
Artifacts land in build/, install/ and log/, all git-ignored. If a build
complains about CMakeCache.txt naming the wrong source directory (a path
rename, usually), delete build/ and build again.
Built on your workstation? Copy it to the Pi with pixi run sync, or
pixi run -e dev sync-watch to keep it copying on every save. Launch files,
config and Python go live without a rebuild (colcon --symlink-install); only
C++ needs pixi run build again on the Pi.
3. Bench prep¶
Two parts are configured before the robot exists, plugged into your workstation over USB. The results stay in the parts or go onto the card, so nothing here is repeated on the Pi.
Device names. The tools open /dev/mote_servos and /dev/mote_camera, the
names the udev rules give the hardware. Install the rules here once, the same
way the Pi gets them:
Servo IDs. The drive wheels are expected at servo IDs 7 (left) and 9 (right) at 1 Mbaud. Fresh Feetech STS3215 servos all ship as ID 1, so assign IDs before the wheels go on, connecting one servo at a time when prompted:
An SO-101 arm's six servos share the wheels' bus at IDs 1–6 and are assigned the same way; its range calibration is not bench work, because the travel depends on the mount (the arm docs). IDs live in each servo's EEPROM, so this is once per servo. The servo bus tools cover the rest of the bus utilities.
Camera intrinsics. Optional: the packaged default fits the UGREEN webcam in the BOM. For a different camera, or for metric work, calibrate with the camera on your USB and the printed target from camera calibration:
The file goes onto the card in the next step with
pixi run provision --camera-calibration camera_calibration.yaml, or to
~/.mote/camera_calibration.yaml on a robot that is already running.
4. Set up the Pi¶
One time, on the robot:
That installs the udev rules that give the hardware stable names
(/dev/mote_servos, /dev/mote_lidar, /dev/mote_camera), disables WiFi power
save, and installs the systemd units. The robot then boots to standby — the
fleet agent and the Foxglove bridge only — because autostarting the drive stack
would flatten the battery on a desk. One command brings the stack up or down:
pixi run wake # drive the active map and take missions
pixi run map-mode # SLAM + the mapping bag
pixi run sleep # back to standby
A robot that lives on the floor can boot straight into the robot target:
sudo systemctl enable mote-robot.target.
See Bringup & reliability for what those services do, and what the pre-flight self-check refuses to start without.
5. Map a space¶
The stack runs in two phases: build a map with SLAM, then drive it without.
pixi run mapping # bringup + SLAM
pixi run teleop # in another terminal: drive it around
pixi run site save-map # save the map + posegraph into the active site
Instead of driving it yourself, pixi run explore covers the space
autonomously — run it on the Pi, so a WiFi drop cannot end the mission.
save-map writes an immutable map revision into the active site's floor, runs a
cleaning pass over it, and validates it. Sites, maps &
zones explains what a site bundle is, why maps are revisions,
and the three ways a named place gets a coordinate.
6. Drive the map¶
Send goals from RViz (pixi run rviz, which selects the dev environment), or connect a Foxglove desktop to
ws://<robot-id>:8765 — the bridge is part of the base bringup, and the shipped
layout has teleop, a map view and the pause control. Teleop
always wins over Nav2 without cancelling the mission; the
drive path explains the
arbitration.
Once places are named, missions become commands:
pixi run -- ros2 run mote_tasks mission goto target=kitchen
pixi run -- ros2 run mote_tasks mission --cancel <id> # stop it; the id is printed above
See Missions for the fetch and goto grammar.
At this point you have a working robot stack: maps, SLAM, Nav2, teleop and missions. From here:
- Perception turns the webcam into obstacles Nav2 can see and objects a mission can fetch — with the heavy models on an inference server rather than the Pi.
- The fleet layer puts several robots behind one dashboard, with enrollment, dispatch and a shared map registry.
- Simulation runs all of it against Gazebo.
Contributing¶
A pre-commit config handles hygiene checks, shell linting and Python error checking. Wire it in once per clone:
To work on these docs:
pixi run docs # live-reloading site on http://127.0.0.1:8000
pixi run docs-build # what CI runs, with --strict
AI aided contributions are welcome, but only if you can explain and vouch for every change.