Go2 Non-ROS Navigation
The Go2 navigation stack runs entirely without ROS. It uses a column-carving voxel map strategy: each new LiDAR frame replaces the corresponding region of the global map entirely, ensuring the map always reflects the latest observations.
Data Flow
Pipeline Steps
1. LiDAR Frame — GO2Connection
We don’t connect to the LiDAR directly — instead we use Unitree’s WebRTC client (via legion’s webrtc driver), which streams a heavily preprocessed 5cm voxel grid rather than raw point cloud data. This allows us to support stock, unjailbroken Go2 Air and Pro models out of the box.
2. Global Voxel Map — VoxelGridMapper
The VoxelGridMapper maintains a sparse 3D occupancy grid using Open3D’s VoxelBlockGrid backed by a hash map. Each voxel is a 5cm cube by default.
Voxel hash map provides O(1) insert/erase/lookup, so this is efficient even with millions of voxels. The grid runs on CUDA by default for speed, with CPU fallback.
Each incoming LiDAR frame is spliced into the global map via column carving. We consider any previously mapped voxels in the space of a received LiDAR frame stale, by erasing entire Z-columns in the footprint, we guarantee:
- No ghost obstacles from previous passes
- Dynamic objects (people, doors) get cleared automatically
- The latest observation always wins
Configuration
3. Global Costmap — CostMapper
The CostMapper converts the 3D voxel map into a 2D occupancy grid. The default algorithm (height_cost) maps rate of change of Z, with some smoothing.
algo settings are in occupancy.py and can be configured per robot
Configuration
skip
4. Navigation Costmap — ReplanningAStarPlanner
The planner will process the terrain gradient and compute it’s own algo-relevant costmap, prioritizing safe free paths, while be willing to path aggressively through tight spaces if it has to
We run the planner in a constant loop so it will dynamically react to obstacles encountered.
5. All Layers Combined
All visualization layers shown together
Patrolling
The patrolling system drives the robot to systematically cover a known area. It is exposed as an agent skill. An LLM agent can callstart_patrol and stop_patrol to control it. Note that the area has to be explored first.
How it works
- Visitation tracking — As the robot moves, a visitation grid (aligned to the costmap) marks cells around the robot’s position as visited. This gives the system a running picture of where the robot has and hasn’t been. This expires over time, and has to be visited again.
- Goal selection — A patrol router picks the next goal. The default strategy is coverage: it samples a handful of candidate points from unvisited, obstacle-free cells, plans a path to each one, and picks the candidate whose path would cover the most new ground. Candidates are weighted by a Voronoi skeleton so goals are more likely to be spread evenly across the map, rather than clustering in large open areas.
-
Navigation loop — The module sends each goal to the planner and waits for a
goal_reachedsignal before requesting the next one. If no valid goal is available (e.g. the map hasn’t loaded yet), it retries after a short delay. - Stopping — When patrol is stopped, the module cancels in-progress navigation by publishing the robot’s current pose as the goal, then re-enables the planner’s normal replanning behavior.
Patrol router strategies
Safety
Goal candidates are filtered through a safe mask — the free-space region eroded by the robot’s clearance radius — so the robot is never sent to a position too close to walls or obstacles. The planner’s safe-goal clearance is also tightened while patrolling to ensure the robot can rotate in place at every goal.Router comparison
Sample patrol trace (26 min)
Blueprint Composition
The navigation stack is composed in theunitree_go2 blueprint:
skip fold output=assets/go2_blueprint.svg



