Quick Start

From unboxed hardware to a driving robot in as few steps as possible.


The zero-to-running-robot journey

Before diving into steps, here is the full picture of what you are about to do and where each piece fits:

flowchart TD
    A([Flash SD card]) --> B([Power on & network])
    B --> C([Install raccoon-cli])
    C --> D([Create project])
    D --> E([Connect to robot])
    E --> F([Update firmware])
    F --> G([Configure hardware])
    G --> H([raccoon run])
    H --> I([Write missions])
    I --> H

    click B "/01-botui" "BotUI docs"
    click D "/02-programming/01-project-structure" "Project structure"
    click G "/02-programming/02-robot-definition" "Robot definition"
    click I "/02-programming/03-missions" "Missions"

    style A stroke:#853585
    style H stroke:#27ae60
    style I stroke:#27ae60

The loop at the end is your normal development cycle: write code, run it on the robot, observe, refine. Everything else (flash, connect, update) is one-time setup.


What You Need

  • Wombat controller with RaccoonOS flashed to the SD card
  • Battery pack
  • DC motors wired to motor ports (2 for a differential drivetrain, 4 for mecanum)
  • A computer with an internet connection (Windows, macOS or Linux)
  • USB keyboard — needed once to enter WiFi password on the Wombat

Step 1 — Flash the SD Card

Download the latest RaccoonOS image from:

github.com/htl-stp-ecer/raccoon-image/releases

Grab the .img.xz file from the most recent release. Then flash it to your SD card:

Use Raspberry Pi Imager (Windows, macOS, Linux):

  1. Click Choose OS → Use custom → select the .img.xz file
  2. Click Choose Storage → select your SD card
  3. Click Next and confirm — it will flash and verify automatically

Alternatively, Balena Etcher works just as well: Flash from file → select the .img.xz → Select target → Flash!

Then unscrew the lid on the back of the Wombat, insert the SD card, and close it up again.

If your SD card was pre-flashed with raccoon (e.g. at a workshop), skip to Step 2.


Step 2 — Power On & Connect to a Network

Connect the battery and power on the Wombat. After a few seconds the BotUI touchscreen dashboard appears — that’s your confirmation it booted correctly.

The Wombat supports three connection modes. Open Settings → WiFi in BotUI to choose one:

ModeWhen to use
WiFi ClientJoin your existing WiFi network
HotspotWombat creates its own network — your laptop connects to it
LANPlug in an ethernet cable (peer-to-peer also works)

For WiFi Client mode:

  1. Select WiFi Client from the dropdown and click Connect to WiFi
  2. Scroll to your network and tap it
  3. Enter the password using a USB keyboard plugged into the Wombat
  4. When the status turns green, go back and tap Device Info to see the IP address

Note the IP — you’ll need it shortly. Example: 192.168.178.124

If the robot isn’t reachable after connecting: this is a known network manager issue. Reboot the Wombat and it will reconnect.

→ See BotUI documentation for full detail on all connection modes.


Step 3 — Create Your Project

One command sets up everything: it installs the tools you need, asks you a few questions, downloads the example project, and prepares it for you.

Open a terminal in the folder you’d like to create the project in, then run the command for your system:

Linux / macOS:

curl -LsSf https://raw.githubusercontent.com/htl-stp-ecer/raccoon-example/main/raccoon-setup.sh | bash

Windows (PowerShell):

irm https://raw.githubusercontent.com/htl-stp-ecer/raccoon-example/main/raccoon-setup.ps1 | iex

The script will:

  1. Install Git and uv if they are missing (uv also downloads the right Python version for you — no separate Python install needed)
  2. Ask for a project name (letters, digits, - and _; must start with a letter)
  3. Ask for your drivetrain type: differential (two-wheeled) or mecanum (“omniwheeled”). Other bot types are currently not supported by the template.
  4. Download the matching branch of the example project into a new folder named after your project, and rename the project inside its config files
  5. Give the project its own fresh git repository and a unique project ID (uuid)
  6. Run uv sync to download raccoon-cli and raccoon-library and create the virtual environment
  7. Create the first commit, titled Initial Commit (created by raccoon-setup)

If the current folder is not writable, or a folder with your project name already exists, the script stops without changing anything.

Once it finishes, go into your project and activate the Python virtual environment, which makes the raccoon command available:

cd MyRobot
  • Windows (PowerShell): .venv\Scripts\Activate.ps1
  • Windows (cmd.exe): .venv\Scripts\activate.bat
  • Linux / macOS: source .venv/bin/activate

You know it worked when the command line is prefixed with (MyRobot) or (.venv). Remember to activate the venv again whenever you open a new terminal.

Prefer to do it by hand? Clone the branch yourself with git clone -b <differential|mecanum> --single-branch https://github.com/htl-stp-ecer/raccoon-example MyRobot, then run uv sync inside it. You’ll also want to change the name in pyproject.toml and raccoon.project.yml and replace the uuid in raccoon.project.yml with a new one. It is also recommended to delete the cloned .git and initialize a fresh repository in the project folder.

The project you get looks like this:

MyRobot/
├── raccoon.project.yml         # top-level config — includes all sub-configs
├── config/
│   ├── connection.yml          # saved robot IP address (automatically managed)
│   ├── hardware.yml            # sensors, motors, servos
│   ├── missions.yml            # ordered list of missions to run
│   ├── motors.yml              # motor port assignments and calibration
│   ├── robot.yml               # kinematics, PID, physical dimensions
│   ├── run-configurations.yml  # named run profiles for `raccoon run` (default, dev, dev-nc, profile)
│   └── servos.yml              # servo ports and named positions
└── src/
    ├── main.py                 # entry point: Robot().start()
    ├── mission_params.py       # Mission parameter which you can adjust before a run on the screen
    ├── hardware/
    │   ├── defs.py             # auto-generated on `raccoon run` (not in git)
    │   ├── defs.pyi            # auto-generated on `raccoon run` (not in git)
    │   └── robot.py            # auto-generated on `raccoon run` (not in git)
    ├── missions/
    │   ├── m000_setup_mission.py
    │   ├── m010_navigate_to_object_mission.py
    │   ├── m020_collect_object_mission.py
    │   ├── m030_deliver_object_mission.py
    │   └── m999_shutdown_mission.py
    ├── service/                # shared, stateful logic (RobotService subclasses)
    └── steps/                  # reusable custom steps used by the missions

The example comes with a small set of demo missions you can read, change, or delete. The hardware/ files are generated from your YAML config, so edit the YAML, not the Python.

→ See Project Structure for a full explanation of every file.


Step 4 — Connect to the Robot

raccoon connect 192.168.178.124

Replace the IP with the one shown on your Wombat’s screen.

On first connect, raccoon will attempt SSH key authentication. If that fails it asks:

“Set up SSH key authentication now?”

Say yes. When prompted for a password, use the Wombat’s default credentials:

  • User: pi
  • Password: raspberrypi

raccoon will create an SSH key, copy it to the Wombat, and save an API token. From here on, no password is needed.

Security: Change the default password once your setup is complete.

If the robot’s IP ever changes, just re-run raccoon connect <new-IP>.


Step 5 — Update

Notice: raccoon update is not yet working as intended and should currently not be used. For now, just skip this step until this documentation says otherwise.

If raccoon warns about a version mismatch between your laptop and the robot, run:

raccoon update

This checks both sides against the current bundle target and updates anything that’s out of date.


Step 6 — Configure Your Hardware

The example project ships with a default hardware setup for the drivetrain type you picked. Adjust it to match your robot by editing the YAML files — they are the source of truth for your hardware:

What to changeFile
Motor ports, inverted flags, encoder scalingconfig/motors.yml
Servo ports and named positionsconfig/servos.yml
Sensorsconfig/hardware.yml
Kinematics, PID gains, physical dimensions (wheel size, track width, …)config/robot.yml

Each file is commented, so open it and work through the values from top to bottom. The generated src/hardware/ files are rebuilt from the YAML on every raccoon run, so never edit those by hand.

Measure your robot’s dimensions

The drivetrain dimensions live in config/robot.yml under drive.kinematics. They are what lets the robot turn by exactly 90° and drive exactly 30 cm, so measure them carefully (calipers or a ruler is fine).

⚠️ UNITS: THE KINEMATICS VALUES ARE IN METERS, NOT CM OR INCHES!

wheel_radius, wheelbase and track_width must be entered in meters. If you enter centimeters or inches the robot will drive and turn completely wrong (a wheelbase of 16 is a 16-meter-wide robot, not a 16 cm one) and it can look like a broken motor or a bad calibration.

You measuredConvert to metersExample
millimeters (mm)divide by 100034.5 mm → 0.0345
centimeters (cm)divide by 10016 cm → 0.16
inches (in)multiply by 0.02546.3 in → 0.16002

Note that the physical: section further down the same file is the opposite: its keys end in _cm (width_cm, x_cm, …) and are in centimeters. Always go by the unit in the key name or the comment next to it.

Both drivetrains

KeyWhat to measure
wheel_radiusRadius of one wheel: measure the diameter with calipers and halve it. Convert to meters.

Differential (two-wheeled) — one value:

KeyWhat to measure
wheelbaseDistance between the left and right wheels, measured between the points where each wheel touches the ground (contact points), not between the motors or the outside of the robot. In other words, this is the track width.
kinematics:
  type: differential
  wheel_radius: 0.0345   # 6.9 cm wheel diameter -> 3.45 cm radius -> 0.0345 m
  wheelbase: 0.16        # 16 cm between left and right contact points -> 0.16 m

Mecanum (four-wheeled) — two values. Be careful: the name wheelbase means something different than on a differential robot.

KeyWhat to measure
track_widthLeft-to-right distance between the wheel contact points (same measurement as wheelbase on a differential robot).
wheelbaseFront-to-back distance between the front and rear axles.
kinematics:
  type: mecanum
  wheel_radius: 0.0345   # 6.9 cm wheel diameter -> 3.45 cm radius -> 0.0345 m
  track_width: 0.16      # 16 cm left to right -> 0.16 m
  wheelbase: 0.12        # 12 cm front axle to rear axle -> 0.12 m

If the robot turns too much or too little, the width value (wheelbase on differential, track_width and wheelbase on mecanum) is usually the culprit. If it drives too far or too short, check wheel_radius. raccoon calibrate can fine-tune the rest later.

Motor direction

The most critical setting: all motors must spin forward when given a positive power command. Decide which direction is “forward” for your robot, then set inverted: true in config/motors.yml for any motor that spins the wrong way. We recommend you plug in all motors with the red cable facing up to keep it simple when you for example quickly need to plug in a cable that fell out under stress. For that, you need to configure the inverted property of each motor correctly.

The Wombat can be mounted in any orientation — the software accounts for it.

→ See Robot Definition for the full YAML reference.


Step 7 — Run It

raccoon run

This does everything in one command:

  1. Saves a local checkpoint (safety snapshot)
  2. Runs code generation locally on your laptop — generates defs.py and robot.py from your YAML config
  3. Syncs your files (including the generated ones) to the robot
  4. Executes src/main.py on the robot, streaming output to your terminal
  5. Pulls any files updated on the robot back to your laptop

You should see the robot boot and run the setup mission. Press Ctrl+C to stop.

The example project already ships with a few demo missions (M010NavigateToObject, M020CollectObject, M030DeliverObject), so the robot will move on after setup. If you’d rather start from a clean slate, remove them from config/missions.yml; the robot will then warn Robot does not have any missions attached and just wait — that’s expected.


Step 8 — Test Basic Motion

To check that your motors and wiring are right, create a small smoke test mission:

raccoon missions create M010SmokeMission

Mission names use a three-digit zero-padded prefix. M000 is reserved for the setup mission, M999 for shutdown, and regular missions start at M010 and increment by 10 (M010, M020, M030, …).

Open the generated file in src/missions/m010_smoke_mission.py and add a simple sequence:

from raccoon import *


class M010SmokeMission(Mission):
    def sequence(self) -> Sequential:
        return seq([
            drive_forward(30),   # drive 30 cm forward
            turn_right(90),      # turn 90° right
        ])

Then register it in config/missions.yml (keep the setup and shutdown entries; comment out or remove the demo missions while testing):

- M000SetupMission: setup
- M010SmokeMission
- M999ShutdownMission: shutdown

Run it:

raccoon run

The robot should drive forward and turn. Distance and straightness may be off — that’s fine for now. What matters is that it moves in the right direction.

If it doesn’t move at all: check config/motors.yml — are the port numbers correct, and is inverted set correctly for each motor?

→ See Missions and Steps for the full API.


What Comes Next

Your robot is running. Here’s where to go from here:

TopicWhere
Make it drive accuratelyCalibration
Add sensors, servos, and other hardwareRobot Definition — edit raccoon.project.yml
Writing real missionsMissions
Stop conditions, chaining, timingStop Conditions
Sensors, servos, drive systemProgramming Guide
Configure sensor positions visuallyWeb IDE — run with raccoon web
All CLI commands explainedraccoon-cli reference
What you can do from the touchscreenBotUI

A real first mission from a competition robot

The examplebot (a real competition entry) uses this exact pattern for a simple three-mission run. Its setup mission homes the arm, calibrates sensors, and waits for the light — all in one method:

from raccoon import *
from src.hardware.defs import Defs


class M000SetupMission(SetupMission):
    def sequence(self) -> Sequential:
        return seq([
            # Home hardware to known starting positions
            Defs.arm_servo.up(),
            Defs.claw_servo.open(),

            # Calibrate distance accuracy and IR sensors.
            # distance_cm=50 gives more accurate results than the default 30 cm.
            calibrate(distance_cm=50),

            # wait_for_light() is injected automatically by SetupMission
            # after sequence() returns — do not call it here.
        ])

The robot then drives, grabs an object, and returns — building up from drive_forward to parallel() and .until() stop conditions. When you are ready to build a real mission sequence, the Programming Guide has everything.


Optional: IDE Setup

Open the project folder in your preferred IDE (PyCharm, VS Code, etc.). You’ll have full tab completion on all raccoon types out of the box — no special interpreter configuration needed. Stubs are provided for the raccoon.* namespace and are installed alongside the library.