Skip to content

r1pro: Point-LIO odometry on the chassis Mid-360 - #4227

Draft
jeff-hykin wants to merge 8 commits into
jeff/fix/livox_rust_reuse_addrfrom
jeff/feat/r1_pointlio
Draft

jeff-hykin wants to merge 8 commits into
jeff/fix/livox_rust_reuse_addrfrom
jeff/feat/r1_pointlio

Conversation

@jeff-hykin

@jeff-hykin jeff-hykin commented Sep 19, 2026

Copy link
Copy Markdown
Member

r1pro-pointlio: the R1 placed by the Rust Point-LIO fed by dimos's own Mid-360 driver instead of wheel odometry, reading the lidar's address from the vendor's own config and carrying the estimator's stamps onto the host clock, with the README saying what it does to the vendor's lidar driver and how to undo it.

Point-LIO knows when its state is -- lidar_end_time, which the SDK writes
into the odometry header -- and main.cpp overwrote it with
system_clock::now(). While the estimator keeps up the two agree and nothing
shows. When it falls behind, the queue inside Point-LIO grows and the pose
being published is seconds old while the stamp still says now.

On 20260916-085832-r1pro-kronknav that reached 22 s after the spin: every
camera frame paired with tf at its own stamp was posed with where the robot
had been 22 s earlier, and no lidar-side check could see it, because the
cloud is deskewed into the same wrong estimate and the error cancels.

Also refuse to publish a state twice -- re-sending one pose under a later
stamp is the same lie -- and warn when the estimator trails the wall clock,
which is the quantity that was invisible.

(cherry picked from commit b2c139e618307b85413740eda03792568190111d)
The previous commit stamped with lidar_end_time directly, and that is the
SENSOR time base: on this Mid-360 it reads 162,771 s, which is 45 hours of
lidar uptime against a host at epoch. Publishing it raw is worse than the
publish-time stamp it replaced, because nothing downstream resolves at all.

Caught by the warning that commit added -- "pointlio is behind the world
lag_s=1789421700" -- on the first live run, before any recording was taken.

That is also WHY the original code reached for system_clock::now(): it was
converting the sensor time base to epoch, and paid for it by describing the
wrong moment whenever the estimator fell behind. Both are needed: the state
time AND a way to express it on the host clock.

HostClockOffset estimates that from packet arrivals, which is the only handle
on it. host_arrival - device_stamp is the offset plus a delay that is always
positive, so the minimum is the estimate, and it is observed on the SDK
callback threads where arrival is honest -- anywhere further in and the
estimator backlog folds into it. Two buckets rather than a running minimum, so
it follows the clocks drifting apart instead of being captured by the luckiest
packet ever seen.

Four more tests, one per property, including the 45-hour number as measured.

(cherry picked from commit eb00fdff39f171f24ef5759c8f4379ad72c72bc7)
A blueprint, r1pro-pointlio, that runs the existing C++ Point-LIO on the
chassis Mid-360 and makes it the thing that places base_link. The wheel
odometry the connection integrates from the commanded chassis speed is
switched off, the lidar mount is republished inverted so base_link has one
parent, and Point-LIO's pose reaches the planners under the name they
already read (chassis_odom).

On an R1 the lidar's address is already in the vendor's MID360_config.json,
so R1ProPointLio reads it from there when nothing sets it, and refuses to
start naming the file and the variables when that cannot answer either.

A Livox streams to the host that last asked, so the vendor's
livox_ros_driver2 goes quiet while this runs and does not recover on its
own; the README says which vendor nodes keep running, and exactly how to
give the sensor back.
@codecov

codecov Bot commented Sep 19, 2026

Copy link
Copy Markdown

Codecov Report

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

Files with missing lines Patch % Lines
dimos/robot/galaxea/r1pro/lio.py 93.75% 2 Missing ⚠️
@@                        Coverage Diff                         @@
##           jeff/fix/livox_rust_reuse_addr    #4227      +/-   ##
==================================================================
+ Coverage                           79.71%   79.73%   +0.01%     
==================================================================
  Files                                1508     1511       +3     
  Lines                              142607   142713     +106     
  Branches                            12209    12210       +1     
==================================================================
+ Hits                               113685   113791     +106     
  Misses                              25483    25483              
  Partials                             3439     3439              
Components Coverage Δ
Tests 95.41% <100.00%> (+<0.01%) ⬆️
Flag Coverage Δ
OS-ubuntu-24.04-arm 75.37% <98.13%> (+0.01%) ⬆️
OS-ubuntu-latest 76.18% <98.13%> (+0.01%) ⬆️
Py-3.10 75.96% <98.13%> (+0.01%) ⬆️
Py-3.11 76.16% <98.13%> (+0.01%) ⬆️
Py-3.12 76.17% <98.13%> (+0.01%) ⬆️
SelfHosted-Large 30.63% <52.33%> (+0.01%) ⬆️
SelfHosted-Linux 36.66% <52.33%> (+0.01%) ⬆️
SelfHosted-macOS 36.99% <52.33%> (+0.01%) ⬆️

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

Files with missing lines Coverage Δ
dimos/robot/all_blueprints.py 100.00% <ø> (ø)
...alaxea/r1pro/blueprints/basic/r1pro_coordinator.py 79.54% <ø> (ø)
...t/galaxea/r1pro/blueprints/basic/r1pro_pointlio.py 100.00% <100.00%> (ø)
dimos/robot/galaxea/r1pro/config.py 100.00% <100.00%> (ø)
dimos/robot/galaxea/r1pro/connection.py 22.92% <100.00%> (ø)
dimos/robot/galaxea/r1pro/test_lio.py 100.00% <100.00%> (ø)
dimos/robot/galaxea/r1pro/lio.py 93.75% <93.75%> (ø)

... and 1 file 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.

The blueprint composes R1ProMid360 (dimos's driver, with the lidar's address
read from the vendor's MID360_config.json when nothing sets it) into
PointLioRust, in place of the C++ estimator that read the sensor itself. The
driver's raw sweep is renamed to lidar_raw; the estimator's cloud stays on
the lidar bus.

The driver stamps with the Livox's own clock, which on a sensor with no time
source is its uptime, so the Rust estimator now carries its odometry, tf and
cloud onto the host's clock the way the C++ module does: the minimum of
host-minus-device arrival over a 30 s window.
@jeff-hykin
jeff-hykin changed the base branch from main to jeff/fix/livox_rust_reuse_addr September 19, 2026 16:11
The vendor-file reader and the R1ProMid360 subclass go; the two addresses
are constants in r1pro/config.py and the CLI overrides them.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant