Skip to content

holonomic trajectory controller#2697

Open
bogwi wants to merge 12 commits into
mainfrom
danvi/feat/holonomic_trajectory_controller
Open

holonomic trajectory controller#2697
bogwi wants to merge 12 commits into
mainfrom
danvi/feat/holonomic_trajectory_controller

Conversation

@bogwi

@bogwi bogwi commented Jul 2, 2026

Copy link
Copy Markdown
Member

Add Holonomic Trajectory Controller

This PR ships two modules:

  1. Holonomic Trajectory Controller
  2. Local Planner

Holonomic Trajectory Controller, htc

Why write HTC when differential already exists?

PController works for a classic diff-drive mental model: point at lookahead, drive forward, rotate in place when badly misaligned. That is simple and robust, which is why it remains the default in unitree_go2.

htc extends to:

  1. Strafe onto the path - HolonomicTrackingController maps lateral error to body vy, so the robot slides back onto the polyline while still moving - on bends and right after a replan nudge.
  2. Keep moving through corners - HTC tracks the path tangent while translating (default: no pre-align spin), so polylines and MLS hot updates stay continuous instead of stop-spin-go.
  3. Track pose and speed on the path - each tick HTC closes on a TrajectoryReferenceSample: lookahead pose on the path plus body-frame feedforward twist from the path-speed profile. PController only steers toward a lookahead XY point at fixed cruise speed.
  4. Speed and commands matched to the path - profile_speed_along_polyline slows for curvature and goal decel; clamp_holonomic_cmd_vel slews planar and yaw limits from run profiles. Odometry-derived kv/kw damp overshoot when feedforward changes. Differential has none of this - scalar speed, no lateral DOF, no geometry caps.

Htc also borrows some functionlity from the excellent "differential" ReplanningAStar and adapts it to its own workflow.

DanLocalPlanner

Is a local planner module, as it says, and has two features to support MLSPlanner performance coming from kronk-nav.

a) Lock replan, meters - to stabilize the heavy drifting path the global planner supplies. Useful in controlled, constrained environments requiring stable paths over a certain distance. By default it is set to 0.0 but you can experiment locking the path as DanLocalPlanner.blueprint(lock_replan=meters) (see unitree_go2_mls_htc.py)

b) Path smoothing (borrows directly from the existing stack) - to smooth out the path's jagged edges. As with (a), very useful in a micro environment with many turns.

Eventually both features might migrate to MLSPlanner.

How to run on bare Go2 native lidar

Very simple:

dimos --robot-ip <IP> run unitree-go2-mls-htc -o danholonomictc.run_profile=<profile>

There are three run profiles at the moment, think presets with nominal engineering envelopes . But all you need to know is they cap max speed.

walk - 0.55 m/s
trot - 1.0 m/s
run_conservative - 1.5 m/s

walk is default so you can just run like this:
dimos --robot-ip <IP> run unitree-go2-mls-htc

How to run on Go2 + mod360 + Jetson

Blueprint that works with full kronk-nav #2570 will be shared soon. But if you assembled own setup you can just swap DanLocalPlanner and DanHolonomicTC modules into unitree_go2_nav_3d.py instead of BasicPathFollower.

Next

Must know:

Run profiles are in m/s but the Go2 driver is not.

DanHolonomicTC (and MovementManager before it) publishes cmd_vel in real body-frame m/s and rad/s - walk 0.55, trot 1.0, run_conservative 1.5, corner caps, vy strafe, all of it. UnitreeWebRTCConnection.move() in dimos/robot/unitree/connection.py does not send velocities. It maps twist.linear.x/y and twist.angular.z straight onto WIRELESS_CONTROLLER stick fields lx/ly/rx.

Next PR will be: metric cmd_vel behind a toggle.

Sport Move on GO2Connection gated by a config flag (joystick API vs velocity API). Default stays WIRELESS_CONTROLLER so unitree_go2 and current controller keep today's behavior. unitree-go2-mls-htc (and anything else that outputs metric twist) opts into the velocity API. Until that lands, treat on-robot HTC speed as uncalibrated - the control law is in this PR and the proper speed execution is the follow-up.

danvi added 7 commits June 26, 2026 12:05
Integrate holonomic path tracking into LocalPlanner with speed profiling,
trajectory types and metrics, JSONL telemetry, run profiles, Go2 blueprint
wiring, hot replan support, and dannav split-stack experiments.
Resolve go2/connection.py and pyproject.toml from main; combine
all_blueprints registry entries from both sides.
- Create DanLocalPlanner: module, placement, wiring
- Create lock_replan commit window
- Add path smoothing and uniform resampling
- Tune configs for testing
- Remove progress markers
- Remove the monolith: delete unitree_go2_dannav.py
Move holonomic_tc under dannav, relocate shared geometry helpers, strip stale
trajectory logging and run-profile code, and tighten controller types, configs,
tests, and unitree_go2_mls_htc blueprint wiring.
@mintlify

mintlify Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
dimensional 🟢 Ready View Preview Jul 2, 2026, 1:32 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.04959% with 159 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
dimos/navigation/dannav/holonomic_tc/module.py 83.95% 46 Missing and 19 partials ⚠️
dimos/navigation/dannav/geometry/path_distancer.py 75.47% 15 Missing and 11 partials ⚠️
dimos/navigation/dannav/local_planner/module.py 82.65% 15 Missing and 2 partials ⚠️
...s/navigation/dannav/geometry/path_speed_profile.py 85.41% 7 Missing and 7 partials ⚠️
...n/dannav/holonomic_tc/holonomic_path_controller.py 86.95% 7 Missing and 2 partials ⚠️
...nnav/holonomic_tc/holonomic_tracking_controller.py 89.87% 4 Missing and 4 partials ⚠️
...mos/navigation/dannav/holonomic_tc/run_profiles.py 81.39% 4 Missing and 4 partials ⚠️
...s/navigation/dannav/holonomic_tc/command_limits.py 90.24% 2 Missing and 2 partials ⚠️
...e/go2/blueprints/navigation/unitree_go2_mls_htc.py 81.81% 4 Missing ⚠️
dimos/core/global_config.py 0.00% 0 Missing and 1 partial ⚠️
... and 3 more
@@            Coverage Diff             @@
##             main    #2697      +/-   ##
==========================================
+ Coverage   72.05%   72.35%   +0.30%     
==========================================
  Files         893      910      +17     
  Lines       80717    82167    +1450     
  Branches     7310     7421     +111     
==========================================
+ Hits        58159    59452    +1293     
- Misses      20609    20712     +103     
- Partials     1949     2003      +54     
Flag Coverage Δ
OS-ubuntu-24.04-arm 64.60% <89.04%> (+0.46%) ⬆️
OS-ubuntu-latest 67.22% <89.04%> (+0.40%) ⬆️
Py-3.10 67.21% <89.04%> (+0.39%) ⬆️
Py-3.11 67.21% <89.04%> (+0.40%) ⬆️
Py-3.12 67.22% <89.04%> (+0.40%) ⬆️
Py-3.13 67.21% <89.04%> (+0.40%) ⬆️
Py-3.14 67.23% <89.04%> (+0.39%) ⬆️
Py-3.14t 67.21% <89.04%> (+0.40%) ⬆️
SelfHosted-Large 30.18% <31.11%> (+0.04%) ⬆️
SelfHosted-Linux 37.85% <31.11%> (-0.14%) ⬇️
SelfHosted-macOS 36.17% <31.11%> (-0.14%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...igation/dannav/geometry/test_path_speed_profile.py 100.00% <100.00%> (ø)
...igation/dannav/holonomic_tc/test_command_limits.py 100.00% <100.00%> (ø)
...holonomic_tc/test_holonomic_tracking_controller.py 100.00% <100.00%> (ø)
dimos/navigation/dannav/holonomic_tc/types.py 100.00% <100.00%> (ø)
...ion/dannav/local_planner/test_dan_local_planner.py 100.00% <100.00%> (ø)
dimos/robot/all_blueprints.py 100.00% <ø> (ø)
dimos/core/global_config.py 81.42% <0.00%> (-0.27%) ⬇️
...ation/dannav/holonomic_tc/test_dan_holonomic_tc.py 99.14% <99.14%> (ø)
...annav/holonomic_tc/test_holonomic_path_follower.py 98.96% <98.96%> (ø)
...avigation/dannav/holonomic_tc/test_run_envelope.py 98.57% <98.57%> (ø)
... and 9 more

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds two new navigation modules — DanHolonomicTC (a holonomic trajectory controller with feedforward twist, speed profiling, and run-profile envelopes) and DanLocalPlanner (a commit-window gate and path smoother between MLSPlannerNative and the controller) — along with supporting geometry utilities and the unitree-go2-mls-htc blueprint.

  • DanHolonomicTC: A state-machine controller (idleinitial_rotationpath_followingfinal_rotationarrived) that maps lateral cross-track error to body vy for holonomic strafe, uses a forward-backward kinematic speed profile for corner decel, and slew-limits commands via clamp_holonomic_cmd_vel.
  • DanLocalPlanner: Sits between MLSPlannerNative and DanHolonomicTC; uses _ReplanGate to suppress high-frequency planner replans within a configurable lock_replan window, commits on fresh goal clicks, and optionally smooths paths via smooth_resample_path.
  • Bug in _ends_near: path.poses[-1].x is accessed on a PoseStamped instead of path.poses[-1].position.x, causing an AttributeError whenever a goal is clicked and the planner emits a matching path — breaking the fresh-click commit path entirely.

Confidence Score: 4/5

Safe to merge after fixing _ends_near; the rest of the holonomic control and local planner logic is sound.

The _ends_near function accesses end.x on a PoseStamped object instead of end.position.x. Every time a goal is clicked and MLSPlannerNative emits a path heading toward that goal, the AttributeError fires in the subscription callback, the fresh-click commit never fires, and the gate stalls until the lock-window elapses. The rest of the codebase — the tracking law, speed profiler, command limits, run profiles, and path distancer — looks correct and well-tested.

dimos/navigation/dannav/local_planner/module.py — the _ends_near helper and its test coverage for the AttributeError path.

Important Files Changed

Filename Overview
dimos/navigation/dannav/local_planner/module.py New DanLocalPlanner module with commit-window gating and path smoothing; contains a runtime AttributeError in _ends_near (accesses end.x instead of end.position.x on a PoseStamped).
dimos/navigation/dannav/holonomic_tc/module.py Core holonomic trajectory controller; well-structured state machine with RLock protection, pre-existing concerns around lock contention and odom-race already noted in prior review threads.
dimos/navigation/dannav/holonomic_tc/holonomic_tracking_controller.py Clean omnidirectional tracking law with correct sign conventions; feedforward twist, position-error proportional correction, and optional velocity damping all look correct.
dimos/navigation/dannav/holonomic_tc/holonomic_path_controller.py Thin wrapper around HolonomicTrackingController handling profile/speed updates, rotation-in-place fallback, sim angular boost, and slew-rate limiting; looks correct.
dimos/navigation/dannav/geometry/path_distancer.py Vectorised polyline projection and arc-length queries; edge cases (empty path, single-point, degenerate segments) are handled correctly.
dimos/navigation/dannav/geometry/path_speed_profile.py Forward-backward kinematic speed profile with circumradius-based corner caps; numerically robust with divide-by-zero guards and degenerate-triangle handling.
dimos/navigation/dannav/holonomic_tc/command_limits.py Slew-rate and saturation clamping for holonomic body-frame commands; well-structured with validation and non-planar pass-through.
dimos/navigation/dannav/holonomic_tc/run_profiles.py Named movement-envelope registry with validation; three profiles (walk/trot/run_conservative) with positive-finite checks on all numeric fields.
dimos/robot/unitree/go2/blueprints/navigation/unitree_go2_mls_htc.py Blueprint wiring VoxelGridMapper, MLSPlannerNative, DanLocalPlanner, and DanHolonomicTC; straightforward autoconnect composition.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant ML as MLSPlannerNative
    participant LP as DanLocalPlanner (_ReplanGate)
    participant HTC as DanHolonomicTC (_HolonomicPathFollower)
    participant MM as MovementManager
    participant GO2 as GO2Connection

    GO2->>LP: odom (PoseStamped)
    GO2->>HTC: odom (PoseStamped)
    MM->>LP: goal (PointStamped)
    Note over LP: arm fresh-click commit

    ML->>LP: planner_path (Path)
    alt cold start / lock released / fresh-click match
        LP->>LP: _smooth + resample path
        LP->>HTC: path (committed Path)
        HTC->>HTC: start_planning / update_path
        loop "control tick @ 10 Hz"
            HTC->>HTC: _compute_path_following (speed profile + holonomic law)
            HTC->>GO2: nav_cmd_vel (Twist)
        end
        HTC->>MM: goal_reached (Bool)
    else within lock window
        LP-->>ML: suppress
    end

    MM->>HTC: stop_movement
    HTC->>GO2: cmd_vel zero (Twist)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant ML as MLSPlannerNative
    participant LP as DanLocalPlanner (_ReplanGate)
    participant HTC as DanHolonomicTC (_HolonomicPathFollower)
    participant MM as MovementManager
    participant GO2 as GO2Connection

    GO2->>LP: odom (PoseStamped)
    GO2->>HTC: odom (PoseStamped)
    MM->>LP: goal (PointStamped)
    Note over LP: arm fresh-click commit

    ML->>LP: planner_path (Path)
    alt cold start / lock released / fresh-click match
        LP->>LP: _smooth + resample path
        LP->>HTC: path (committed Path)
        HTC->>HTC: start_planning / update_path
        loop "control tick @ 10 Hz"
            HTC->>HTC: _compute_path_following (speed profile + holonomic law)
            HTC->>GO2: nav_cmd_vel (Twist)
        end
        HTC->>MM: goal_reached (Bool)
    else within lock window
        LP-->>ML: suppress
    end

    MM->>HTC: stop_movement
    HTC->>GO2: cmd_vel zero (Twist)
Loading

Reviews (3): Last reviewed commit: "Merge branch 'main' into danvi/feat/holo..." | Re-trigger Greptile

Comment thread dimos/navigation/dannav/holonomic_tc/module.py Outdated
Comment thread dimos/navigation/dannav/holonomic_tc/module.py
Comment thread dimos/robot/unitree/go2/blueprints/navigation/unitree_go2_mls_htc.py Outdated
@dimensionalOS dimensionalOS deleted a comment from greptile-apps Bot Jul 2, 2026
@dimensionalOS dimensionalOS deleted a comment from greptile-apps Bot Jul 2, 2026
@bogwi bogwi added the backport:skip Skip creating a backport to any release branches label Jul 2, 2026
Comment thread dimos/navigation/dannav/holonomic_tc/module.py
@github-actions github-actions Bot added the ready-to-merge Required CI checks have passed on this PR label Jul 2, 2026
@bogwi bogwi changed the title Danvi/feat/holonomic trajectory controller danvi/feat/holonomic trajectory controller Jul 2, 2026
@bogwi bogwi added the PlzReview label Jul 2, 2026
@github-actions github-actions Bot removed the ready-to-merge Required CI checks have passed on this PR label Jul 3, 2026
@github-actions github-actions Bot added the ready-to-merge Required CI checks have passed on this PR label Jul 3, 2026
Comment thread dimos/navigation/dannav/local_planner/module.py
@dimensionalOS dimensionalOS deleted a comment from greptile-apps Bot Jul 4, 2026
@bogwi bogwi changed the title danvi/feat/holonomic trajectory controller holonomic trajectory controller Jul 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip Skip creating a backport to any release branches PlzReview ready-to-merge Required CI checks have passed on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants