Skip to the content.

Kraken autonomy stack

An autonomy stack for an Ackermann orchard robot, and the harness that measures it. Three questions, one robot.

Does it still know where it is when the sensors lie to you? Break the sensors mid-drive, score the estimate against ground truth, and keep the failing configuration as the control case.

Can it do a day’s work without being told where to point? Eighteen aisles, 3.5 m apart: drive every one of them and come back. It plans its own headland turns on geometry, follows them on curvature, and never leaves the boundary it was given.

Does it stop for a person standing in the row? The ISO 18497 test object on the centreline, at full speed, seven runs: it stops 0.78 m short every time. The same suite proves it does not stop for the trees, because a machine that stops for everything has not solved anything.

Start here → — nothing to install but Docker, and the whole suite runs in under ten minutes.

The Kraken in the orchard The machine at the edge of the field in O3DE, aisles running away to the left.

The subsystems

Page What it owns
Simulation environment The headless kinematic model that owns /clock, the O3DE scene, and which one is real about what
Localisation EKF profiles, what is fused and why, the fault shim, the robustness suite and how a run is scored
Row perception Turning a lidar cloud into the corridor the machine is standing in
Navigation Field layout, the skip rule, headland turn geometry, refusing a turn that will not sweep, the geofence
Control Reading arcs out of a path, the curvature trim law, speed limits, refusing to drive
Mission planning The CoverRows action, the navigator plugin, the behaviour tree, why the machine never stops between rows

And four references that cut across all of them:

How it fits together

flowchart LR
    world["simulation<br/>O3DE or headless"]
    inj[fault_injector]
    ekf["localisation<br/>navsat_transform + EKF"]
    percep["row perception"]
    mission["mission planning<br/>CoverRows navigator"]
    planner["navigation<br/>Smac + headland planner"]
    ctrl["control<br/>ArcTracker"]
    scorer[(scorer)]

    world -->|GNSS, IMU, wheels, radar| inj
    inj --> ekf
    world -->|lidar cloud| percep
    ekf -->|odometry/filtered| planner
    ekf --> ctrl
    percep -->|centreline| ctrl
    mission --> planner
    planner -->|path| ctrl
    ctrl -->|cmd_vel| world
    ekf --> scorer
    world -->|ground truth| scorer

The arrow that matters is the one that is missing: nothing feeds ground truth back into the robot. Nav2 judges arrival from the filter’s estimate, because the estimate is all it has, which is why a biased estimate moves the finish line with it and cancels out of every number the robot can check about itself. The scorer sits outside the robot for exactly that reason.

The short version

   
Field 18 aisles, 3.5 m pitch, 44 m rows
Machine Ackermann, 2.2 m wheelbase, 0.7 rad lock, 3.1 m long
Tightest circle 2.61 m radius — wider than one aisle, so turns skip
Coverage every aisle, one geometric headland turn between each
Best measured 4/4 aisles, 0.02–0.11 m off the planned path
Stops between rows none — the turn is appended to the path being followed
Localisation, GNSS lost 0.36 ± 0.25 m with the gyro fused, 21.8 ± 0.9 m without
Suite 20 scenarios, headless, no GPU, about ten minutes

Driving an aisle, seen in rviz Mid-mission. The machine has turned in off the headland and is running the aisle; the yellow line is the row and its next turn as one path, the cyan clusters are lidar returns off the trunks, and the magenta block on the left is the keepout mask that stops it leaving the field.

Coverage order

Repository layout

docker/                 stack (no GPU), simulation (O3DE, GPU) and viz images, plus the
                        scripts that graft the localisation sensors onto the ROSConDemo Kraken
docs/                   these pages
patches/                patches applied to the O3DE engine and gems at image build time
Project/                O3DE project skeleton
ros2_ws/src/
  kraken_interfaces/    FaultSpec, LocalisationScore, RowEstimate, SetFault, CoverRows
  kraken_sim/           headless kinematic simulator, owns /clock, models terrain traction
  kraken_faults/        the fault injector shim between the sensors and the filter
  kraken_localisation/  EKF profiles (naive / robust / radar) + navsat_transform
                        + safety_monitor, which gates cmd_vel on filter health
  kraken_scenarios/     scenario files, scorer, runner, sweep, launch tests
  kraken_nav/           Nav2 plugins: CoverRowsNavigator, HeadlandPlanner, ArcTracker,
                        BT nodes, nav2.yaml, keepout mask, launch files
  kraken_orchard/       row perception: fits the trunk lines either side from the lidar
                        cloud and publishes the corridor between them

Source: github.com/eborghi10/kraken-demo. BSD-3-Clause.