Skip to content

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

git clone --recurse-submodules https://github.com/ClachDev/Mote
cd Mote

Forgot --recurse-submodules? pixi run submodules fetches them afterwards.

2. Build

pixi run 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:

pixi run setup udev

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:

pixi run setup-ids

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:

pixi run camera-calibrate      # -> ./camera_calibration.yaml

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:

pixi run setup

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

pixi run robot     # bringup + Nav2 against the saved 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 tasks     # the behaviour-tree task layer, alongside `pixi run robot`
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:

pixi run lint-install   # into .git/hooks
pixi run lint           # or across the tree by hand (~1 s)

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.