Build a patrol robot in 10 minutes¶
This tutorial walks through the full cycle: clone the starter repo, define a world, write a patrol task, compile it, and run it in simulation. You will end up with a TurtleBot3 Burger navigating a set of named waypoints and reporting back to its dock.
What you need:
- Docker (for the sim image)
- Python 3.12+ with
uvinstalled definedCLI installed (pip install defined-cli)
1. Clone the starter repo¶
The repo ships with a working example called botcrate. You can run it immediately or adapt it.
2. Examine the default robot RDF¶
Open robots/burger.rdf.yaml:
name: turtlebot3_burger
version: "0.0.1"
description: >
TurtleBot3 Burger differential-drive robot with 360-degree LiDAR.
Supports navigation, exploration, and patrol tasks.
modules:
- name: drive_base
type: motor_controller
capabilities:
- name: differential_drive
type: differential_drive
parameters:
wheel_separation: 0.160
wheel_radius: 0.033
max_linear_velocity: 0.22
max_angular_velocity: 2.84
- name: wheel_encoders
type: wheel_encoders
parameters:
ticks_per_revolution: 4096
- name: lidar_module
type: sensor
capabilities:
- name: laser_scanner
type: lidar_2d
parameters:
model: LDS-01
range_min: 0.120
range_max: 3.500
samples: 360
update_rate: 5.0
topic: /scan
The RDF describes hardware capabilities, not software. The compiler reads required_capabilities on each verb and checks that the robot can satisfy them. go_to needs differential_drive and lidar_2d — both are present here.
3. Define POIs for your world¶
POIs (Points of Interest) are named locations in the environment. They appear in task files as $world.pois.<name> — the compiler resolves them at build time.
Open or create worlds/open_room.yaml:
name: room_10x10
description: >
A 10m x 10m open room with perimeter walls only.
Good for testing basic navigation without obstacles.
pois:
dock:
x: 0.0
y: 0.0
type: constant
description: Home/charging station
survey-1:
x: 3.0
y: 3.0
type: static
description: Northeast corner survey point
survey-2:
x: -3.0
y: -3.0
type: static
description: Southwest corner survey point
survey-3:
x: 3.0
y: -3.0
type: static
description: Southeast corner survey point
sim:
environment: room_10x10
spawn:
x: 0.0
y: 0.0
yaw: 0.0
POI types:
| type | meaning |
|---|---|
constant |
fixed for the lifetime of the robot (e.g. dock) |
static |
changes rarely — loaded from world file |
dynamic |
set at runtime by the robot or operator |
4. Write the patrol task¶
Create tasks/patrol.task.yaml:
name: Patrol
description: "Visit survey points in sequence, report at each, return to dock"
steps:
- verb: go_to
params:
target: $world.pois.survey-1
- verb: report
params:
message: "arrived_survey_1"
- verb: wait
params:
duration: 2.0
- verb: go_to
params:
target: $world.pois.survey-2
- verb: report
params:
message: "arrived_survey_2"
- verb: wait
params:
duration: 2.0
- verb: go_to
params:
target: $world.pois.survey-3
- verb: report
params:
message: "arrived_survey_3"
- verb: go_to
params:
target: $world.pois.dock
- verb: report
params:
message: "patrol_complete"
Each step is a verb + params pair. The $world.pois.* references resolve to the x/y coordinates defined in your world file.
5. Set up defined.yaml¶
The project manifest tells the compiler which robot, world, and verb directory to use:
project:
name: my-patrol-bot
robot:
rdf: robots/burger.rdf.yaml
world:
file: worlds/open_room.yaml
verbs:
path: verbs/
sim:
image: ghcr.io/defined-robotics/sim:0.1.0
6. Compile and run in simulation¶
Compile the task:
The compiler outputs a BT XML file and validates that:
- all verbs exist (built-in or local)
- all
$world.pois.*references exist in the world file - the robot has every
required_capabilitythe verbs need
Start the simulation and run the task:
This pulls ghcr.io/defined-robotics/sim:0.1.0, spawns the robot at (0, 0), and launches the TUI.
7. Watch in the TUI¶
The defined run command opens a four-panel TUI:
┌─ Mission ──────────┐ ┌─ Robot State ──────┐
│ step 1/10 │ │ x: 0.000 │
│ go_to survey-1 │ │ y: 0.000 │
│ [running] │ │ heading: 0.0° │
└────────────────────┘ └────────────────────┘
┌─ Log ──────────────────────────────────────┐
│ [12:04:01] go_to → (3.0, 3.0) │
│ [12:04:18] arrived_survey_1 │
│ [12:04:20] go_to → (-3.0, -3.0) │
└─────────────────────────────────────────────┘
┌─ Command ─────────────────────────────────┐
│ > _ │
└─────────────────────────────────────────────┘
Reports published by the report verb appear in the Log panel as the robot reaches each waypoint.
Press q to stop the mission and return to the shell.
8. Modify and re-run¶
Try adding a fourth survey point. In worlds/open_room.yaml:
Then add a step to tasks/patrol.task.yaml before the final go_to / report:
- verb: go_to
params:
target: $world.pois.survey-4
- verb: report
params:
message: "arrived_survey_4"
Re-compile and run:
The compiler will catch any mismatch (missing POI, wrong capability) before the sim starts.
What's next¶
- Add a camera to the robot and use
capture_imageat each stop — see theinspect.task.yamlexample intasks/. - Switch to the
maze_10x10world to test navigation in a confined space. - Write a custom verb — see Create your first custom verb.