Skip to content

Feat/pim/m20 kronknav - #3776

Open
Nabla7 wants to merge 12 commits into
mainfrom
feat/pim/m20-kronknav
Open

Feat/pim/m20 kronknav#3776
Nabla7 wants to merge 12 commits into
mainfrom
feat/pim/m20-kronknav

Conversation

@Nabla7

@Nabla7 Nabla7 commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator
  • Adds the M20 integration machinery: native ROS/DDS command bridge, robot lifecycle/control, direct lidar and IMU ingestion into Point-LIO, KronkNav mapping/planning/control, and front/rear camera streams.

  • Extends NativeModuleConfig with optional Linux CPU affinity so Point-LIO, ray tracing, and MLS can be assigned to appropriate RK3588 cores, this is necessary as otherwise performance becomes severely degraded.

Some notes:

  • This runs fully on the RK3588, further tuning will be required as the mapper is always running behind and this gets worse as the global map grows, the bottleneck is RayTracingVoxelMap on this device.

  • Planning on flat terrain works consistently, planning over stairs is hit or miss. Naturally since the map is always behind dynamic obstacle avoidance does not work.

How to run:

On the M20:
Configure permissions:
./dimos/robot/deeprobotics/m20/deploy/setup.sh

Start blueprint:
dimos --transport lcm --rerun-host 0.0.0.0 run deeprobotics-m20-kronknav-control

Attach the control shell:
dimos --transport lcm shell
app.M20Connection.standup()
app.M20Connection.liedown()

On laptop:
dimos-viewer --connect rerun+http://10.21.31.104:9877/proxy
--ws-url ws://10.21.31.104:3030/ws

m20forgithub.mov

@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

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

Files with missing lines Patch % Lines
dimos/robot/deeprobotics/m20/connection.py 33.05% 158 Missing ⚠️
.../robot/deeprobotics/m20/blueprints/m20_kronknav.py 50.58% 42 Missing ⚠️
dimos/core/native_module.py 42.85% 4 Missing ⚠️
@@            Coverage Diff             @@
##             main    #3776      +/-   ##
==========================================
- Coverage   77.59%   77.50%   -0.09%     
==========================================
  Files        1311     1320       +9     
  Lines      124205   125152     +947     
  Branches    10875    11171     +296     
==========================================
+ Hits        96375    96999     +624     
+ Misses      25059    25020      -39     
- Partials     2771     3133     +362     
Flag Coverage Δ
OS-ubuntu-24.04-arm 74.16% <55.16%> (+0.61%) ⬆️
OS-ubuntu-latest 74.71% <55.16%> (+0.59%) ⬆️
Py-3.10 74.70% <55.16%> (+0.59%) ⬆️
Py-3.11 74.70% <55.16%> (+0.59%) ⬆️
Py-3.12 74.70% <55.16%> (+0.59%) ⬆️
Py-3.13 74.70% <55.16%> (+0.60%) ⬆️
Py-3.14 74.71% <55.16%> (+0.59%) ⬆️
Py-3.14t 74.70% <55.16%> (+0.59%) ⬆️
SelfHosted-Large 30.22% <28.57%> (-0.12%) ⬇️
SelfHosted-Linux 34.74% <28.57%> (-0.10%) ⬇️

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% <ø> (ø)
dimos/robot/deeprobotics/m20/bridge/module.py 100.00% <100.00%> (ø)
dimos/robot/deeprobotics/m20/constants.py 100.00% <100.00%> (ø)
dimos/robot/deeprobotics/m20/pointlio/module.py 100.00% <100.00%> (ø)
dimos/core/native_module.py 80.35% <42.85%> (-0.97%) ⬇️
.../robot/deeprobotics/m20/blueprints/m20_kronknav.py 50.58% <50.58%> (ø)
dimos/robot/deeprobotics/m20/connection.py 33.05% <33.05%> (ø)

... and 116 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.

@Nabla7
Nabla7 marked this pull request as ready for review August 31, 2026 09:46
@github-actions github-actions Bot added the ready-to-merge Required CI checks have passed on this PR label Aug 31, 2026
@greptile-apps

greptile-apps Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This change adds M20 ROS/DDS control, Point-LIO localization, navigation components, camera relays, deployment support, and CPU-affinity handling for native children.

A malformed lidar PointCloud2 message can pass Point-LIO field validation when a coordinate field begins near the end of a point record. The subsequent native coordinate read extends past the record boundary, producing undefined behavior and potentially terminating localization.

Confidence Score: 3/5

Not safe to merge until Point-LIO rejects coordinate fields that extend past a point record.

The affected validation and native read path were exercised with a valid control case and a malformed boundary-crossing coordinate field. AddressSanitizer reported the predicted out-of-bounds read for the malformed input.

Files Needing Attention: dimos/robot/deeprobotics/m20/pointlio/cpp/main.cpp

Security Review

Point-LIO accepts malformed FLOAT32 x, y, or z field offsets that begin within point_step but do not leave room for the full four-byte value. A focused AddressSanitizer reproduction confirmed that the accepted message causes an out-of-bounds native read. Rejecting coordinate fields whose typed width exceeds point_step prevents corrupted or untrusted lidar traffic from reaching this unsafe read.

T-Rex T-Rex Logs

What T-Rex did

  • Ran the focused parser reproduction script to reproduce the P1 finding and reviewed the related review comment.
  • Opened and inspected the focused parser reproduction source and its accompanying run logs to confirm the repro setup and expectations.
  • Validated the general contract by confirming that x_offset=0 is accepted and all reads complete with exit 0, and that x_offset=31 triggers an AddressSanitizer-reported over-read.
  • Checked the toolchain readiness using the ASan harness build log, valid point execution, stack trace, and native M20 environment result.

View all artifacts

T-Rex Ran code and verified through T-Rex

Comments Outside Diff (1)

  1. General comment

    P1 Coordinate field widths are not validated before native reads

    • Bug
      • validate_m20_cloud accepts a FLOAT32 x, y, or z field when its offset is merely below point_step. A one-point cloud with point_step=32, exactly 32 bytes of data, and x.offset=31 passes validation. The subsequent read_unaligned<float> copies four bytes from offset 31, which AddressSanitizer confirmed reads beyond the point/data allocation.
    • Cause
      • The bounds check at lines 157-160 covers timestamp, ring, and intensity only; x/y/z are omitted despite being read as four-byte floats at lines 544-546.
    • Fix
      • Extend the point-step validation to require offsets.x + sizeof(float), offsets.y + sizeof(float), and offsets.z + sizeof(float) to be no greater than cloud.point_step (ideally through one common typed-field bounds helper).

    T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "chore(robot): automate M20 provisioning" | Re-trigger Greptile

Comment on lines +157 to +161
if (offsets.timestamp + sizeof(double) > static_cast<std::size_t>(cloud.point_step) ||
offsets.ring + sizeof(uint16_t) > static_cast<std::size_t>(cloud.point_step) ||
offsets.intensity + sizeof(float) > static_cast<std::size_t>(cloud.point_step)) {
throw std::runtime_error("M20 point fields extend past point_step");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Coordinate field widths are not validated before native reads

validate_m20_cloud accepts FLOAT32 x, y, and z fields when their offsets are below point_step, but it does not verify that the complete four-byte values fit within the point record. A one-point cloud with point_step = 32, 32 bytes of data, and x.offset = 31 passes validation; the later read_unaligned<float> at lines 544–546 reads four bytes beginning at byte 31. AddressSanitizer confirms that this reads past the allocation. Reject coordinate fields whose offset + sizeof(float) exceeds point_step, just as the timestamp, ring, and intensity fields are checked.

Artifacts

Focused parser reproduction script

  • Builds and runs an AddressSanitizer harness that extracts the reviewed validation and read helpers, showing the valid and malformed cases side by side.

Focused parser reproduction source

  • Contains the extracted production validation/read code and minimal PointCloud2 inputs, including the malformed FLOAT32 x field at offset 31 of a 32-byte record.

AddressSanitizer harness build log

  • Shows the focused C++ harness compiled successfully with AddressSanitizer enabled.

Valid point record execution

  • Runs a valid 32-byte point record with x at offset 0; validation and coordinate reads complete successfully with exit 0.

Malformed coordinate field AddressSanitizer failure

  • Runs the accepted malformed record with x at offset 31 and captures AddressSanitizer's four-byte out-of-bounds read past the 32-byte allocation.

Native M20 build environment result

  • Attempts the repository's native Point-LIO build script and shows it stops because `/opt/robot/scripts/setup_ros2.sh` is absent.

View artifacts

T-Rex Ran code and verified through T-Rex


config: M20PointLioConfig

lidar: Out[PointCloud2]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do the point clouds coming from the ray tracer look like they are correct? Since the two sensor clouds are getting merged together the points are getting traced through the base_link instead of the sensor origins I'd expect that ray tracing won't be great in all cases

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @jeff-hykin is working on supporting this rn

debug: bool = False


class M20PointLio(NativeModule, perception.Lidar):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we have a general PointLio module and then we just need to write drivers for each lidar. Don't expect that here because it's not really refactored for that, but just thought I'd drop that in as an fyi

logger = setup_logger()


class _M20CameraRelay(Module):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this module maybe be moved out of the blueprint?

throw std::runtime_error("M20 cloud has no finite Point-LIO returns");
}

std::sort(points.begin(), points.end(),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why sort the entire point cloud if we just need min and max timestamps?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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