Getting started
Nothing to install but Docker. The whole scenario suite runs headless, on the CPU, in about ten minutes. A GPU is needed only for the O3DE scene.
1. Prerequisites
| Want to | Need |
|---|---|
| Run the scenario suite, sweep it, hack on the stack | Docker |
| Watch a run in RViz | Docker, an X server, xhost +local: |
| Run the O3DE orchard | An NVIDIA GPU with Vulkan, the container toolkit, ~120 GB of disk and several hours for the first engine build |
git clone <your fork> kraken-demo && cd kraken-demo
Every command below is run from the repository root.
2. The scenario suite
docker compose -f docker/docker-compose.yml run --rm test
That builds the workspace and runs all ten scenarios against the
headless simulator. Reports land in
/tmp/kraken_reports/<scenario>.json inside the container; set
KRAKEN_REPORT_DIR to move them.
To poke at it by hand instead:
docker compose -f docker/docker-compose.yml run --rm stack
# inside:
colcon build --symlink-install && . install/setup.bash
ros2 launch kraken_scenarios scenario.launch.py scenario:=total_gnss_dropout
scenario.launch.py takes report:=, seed:=, namespace:= and
simulator:=headless|o3de. The scenario names are the file stems in
ros2_ws/src/kraken_scenarios/scenarios/.
Do not quote a single run. The harness is not reproducible to the decimal place — see design. Measure a distribution:
ros2 run kraken_scenarios sweep total_gnss_dropout -n 10
ros2 run kraken_scenarios sweep total_gnss_dropout -n 8 --fixed-seed # jitter only
Against the O3DE scene, add --simulator o3de --namespace kraken1
--spawn-point line1. The spawn point is not optional there in practice: O3DE
outlives the stack, so without it every run after the first starts wherever the
previous one stopped.
3. Watching a run
RViz lives in its own image and only subscribes, so it can be started and killed mid-run without disturbing anything. On the host first:
xhost +local:
docker compose -f docker/docker-compose.yml run --rm viz
Set KRAKEN_NAMESPACE for a robot other than kraken1; the entrypoint rewrites
the config, since RViz stores topics and Target Frame as absolute strings.
Several displays ship disabled, because they cost bandwidth or clutter for a view that is only wanted while explaining something:
| display | what it is for |
|---|---|
| Ground truth | the simulator’s true pose, against the filter’s in magenta |
| Lidar (raw) | the unfiltered sweep, reaching 96 m — compare against what the costmap actually marks |
| Camera front left / right | what the stereo pair saw when visual odometry lost the row |
| Camera ground | whether the downward camera is aimed where the mounting says |
4. The orchard coverage run
This one needs the O3DE scene, so build it first — see simulation §2 and docker/README.md.
export KRAKEN_ROOT=... O3DE_HOME=...
# Always start a fresh simulator. Spawning into a running one stacks a second
# robot on the same point and they collide.
#
# The level must be named. autoexec is set to `playground`, which has no trees
# and, more to the point, no spawn points - so `spawn line1` finds nothing to
# place, no robot publishes odometry, and Nav2 waits forever for a
# `kraken1/odom` that never exists. Note `+loadlevel`: the `-LoadLevel=` form
# parses without complaint and does nothing.
docker rm -f kraken_ns
docker compose -f docker/docker-compose.yml run --rm -d --name kraken_ns sim \
/o3de/ROSConDemo/Project/build/linux/bin/profile/ROSConDemo.GameLauncher \
+loadlevel main
# main chains through intermediate loads, so wait for main by name.
until docker logs kraken_ns 2>&1 | grep -aq "main.*spawnable loaded"; do sleep 5; done
docker compose -f docker/docker-compose.yml run --rm --entrypoint bash stack -c '
source /opt/ros/$ROS_DISTRO/setup.bash && cd $KRAKEN_WS
colcon build --packages-select kraken_interfaces kraken_nav kraken_scenarios
source install/setup.bash
# Spawns, checks the robot is really publishing, and only then starts the
# stack. Doing those by hand is how a stack ends up running against a robot
# that never spawned, which from the inside looks like a Nav2 fault: it waits
# forever for an odom frame nobody publishes.
#
# It waits for /spawn_entity rather than for a duration, which is the same
# gate as the `docker logs` line above asked over ROS instead of by scraping
# a container. The old 30 s timeout was one slow load from failing on a
# healthy simulator - a measured run waited 90 s.
ros2 launch kraken_nav orchard_bringup.launch.py &
# Wait for Nav2 to actually be active rather than for a duration. nav_bringup
# holds the servers until every one of them answers, so this returns as soon
# as it is true and does not return early when the machine is loaded.
until ros2 service call /kraken1/lifecycle_manager_navigation/is_active \
std_srvs/srv/Trigger | grep -q "success=True"; do sleep 2; done
ros2 action send_goal /kraken1/cover_rows kraken_interfaces/action/CoverRows \
"{aisles: 18, aisle_pitch: 3.5, aisle_skip: 0,
row_near_x: 5.0, row_far_x: 43.0, row_heading_deg: -90.0}"'
Do not gate a script on
orchard_bringup’s own exit code.ros2 launchreturns 0 whether or not the spawn failed, so a caller checking$?sees success on a run that started nothing. Scripts should callsim_admin spawndirectly, which returns 1.
aisle_skip: 0 lets the skip rule work it out
from the turning circle. What the machine then does is
mission planning.
5. Tests and figures
Neither needs a simulator or a GPU:
colcon test --packages-select kraken_nav # 12 tests, the turn geometry
colcon test --packages-select kraken_orchard # row fitting
python3 docs/figures/make_figures.py # regenerates the SVGs, and
# asserts the same reference table
6. Where to go next
- Something to break: fault modes, then add a scenario file.
- Something to fix:
gnss_spoofis followed rather than rejected for want of an innovation gate. - Something to build:
Project/is a skeleton with no authored level, which is the biggest open piece of the repo.
Conventions and review expectations are in CONTRIBUTING.md.