Feature: nativemodule livox and fastlio2#1235
Conversation
…notations` The future annotations import made Out[PointCloud2] and Out[Imu] lazy strings, preventing the Module metaclass from creating real port descriptors. Move type imports out of TYPE_CHECKING block so ports are properly resolved at class definition time.
Livox-specific module (LivoxLidarModule, LivoxLidarModuleConfig) now lives in dimos/hardware/sensors/lidar/livox/module.py alongside the driver and SDK code. Generic LidarModule stays in the parent.
Greptile OverviewGreptile SummaryThis PR introduces a comprehensive NativeModule framework that enables C++ executables to participate in the dimos blueprint system, plus native drivers for Livox Mid-360 LiDAR and FAST-LIO2 SLAM. Key Changes:
Architecture:
Test Coverage:
Confidence Score: 5/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Python as Python NativeModule
participant Subprocess as C++ Binary
participant LivoxSDK as Livox SDK2
participant FASTLIO as FAST-LIO2
participant LCM as LCM Bus
Python->>Python: start() - collect port topics
Python->>Subprocess: spawn with --port topic args
Subprocess->>Subprocess: parse CLI args (dimos_native_module.hpp)
Subprocess->>LivoxSDK: init SDK with memfd config
Subprocess->>LCM: initialize publisher
alt Mid360 Driver
LivoxSDK->>Subprocess: on_point_cloud(raw packets)
Subprocess->>Subprocess: accumulate points in buffer
loop Every 1/frequency seconds
Subprocess->>LCM: publish PointCloud2
end
LivoxSDK->>Subprocess: on_imu_data(IMU packets)
Subprocess->>LCM: publish Imu (immediately)
else FAST-LIO2
LivoxSDK->>Subprocess: on_point_cloud(raw packets)
Subprocess->>Subprocess: accumulate CustomMsg points
LivoxSDK->>Subprocess: on_imu_data(IMU)
Subprocess->>FASTLIO: feed_imu(imu_msg)
loop Main processing loop
Subprocess->>FASTLIO: feed_lidar(accumulated points)
FASTLIO->>FASTLIO: EKF-LOAM SLAM
FASTLIO->>Subprocess: return registered cloud + odometry
Subprocess->>Subprocess: voxel filter + outlier removal
Subprocess->>LCM: publish PointCloud2 (world frame)
Subprocess->>LCM: publish Odometry
opt Global Map Enabled
Subprocess->>Subprocess: VoxelMap.insert(cloud)
Subprocess->>Subprocess: VoxelMap.raycast_clear()
Subprocess->>LCM: publish global_map PointCloud2
end
end
end
Python->>Subprocess: SIGTERM (on stop())
Subprocess->>LivoxSDK: shutdown
Subprocess->>Subprocess: exit
Python->>Python: wait for exit + cleanup
Last reviewed commit: af4e732 |
Integrates FAST-LIO-NON-ROS directly with Livox SDK2 as a dimos NativeModule. The C++ binary feeds live LiDAR/IMU data into FAST-LIO's EKF-LOAM SLAM and publishes aggregated world-frame point clouds and odometry over LCM. Includes rate-limited output (pointcloud_freq, odom_freq), Odometry.to_rerun() for visualization, and nix flake deps.
Add standalone nix flakes to build native C++ modules with all dependencies (Livox SDK2, LCM, PCL, etc.) from nix, avoiding glibc version conflicts. CMakeLists.txt now accepts FASTLIO_DIR as an external parameter for hermetic nix builds.
…n flake Move livox flake.nix into cpp/ for consistency with fastlio2. Add cmake install() rules with default prefix=result so both nix and cmake produce binaries at cpp/result/bin/. Remove livox-sdk and lidar deps from main flake since native modules build via their own standalone flakes.
# Conflicts: # dimos/core/__init__.py # dimos/robot/all_blueprints.py # dimos/robot/unitree_webrtc/unitree_go2_blueprints.py
- Add generic type param to NativeModule (Module[NativeModuleConfig]) - Add Any import and type annotations to NativeModule.__init__ - Fix ModuleConfig import in lidar module - Fix FastLio2Module -> FastLio2 import in test - Rename test_spec_compliance.py to test_spec.py across lidar modules - Adjust fastlio2 voxel_size from 0.25 to 0.15
| cd dimos/hardware/sensors/lidar/fastlio2/cpp | ||
| nix build .#fastlio2_native | ||
| ``` | ||
|
|
There was a problem hiding this comment.
I know I've pushed towards dimos users to not being forced to use nix, but for C++ and similar individual modules I think its fair to say "Either use the prebuilt binary, use nix, or figure it out yourself". E.g. for future C++ modules I don't think we need to support the native install instructions.
Why I feel these are okay to force is cause its for a build of an exe instead of a devShell.
There was a problem hiding this comment.
yeah I agree, maintaining build systems would be horrible otherwise. nix can be used for wheel builds also
There was a problem hiding this comment.
actually I added a build system it was just a few lines and makes it much more ergonomic
There was a problem hiding this comment.
I think the only thing missing is docs (all my other feedback is super minor).
I can ask Jalaj to do the docs for this (after its merged) cause Jala already needs to add docs for his docker module, and this native module is way more simple.
That said, in a future I think it would be good for native modules to support automated build hook for a missing binary.
Resolved conflict in Odometry.py: kept dev's refactored class structure and added to_rerun() method from feat/livox.
Resolved conflicts: kept to_rerun() in Odometry.py, took dev's updated doc paths in modules.md.
true, this can host docker very easily.. wrote some docs, and yeah autobuild sounds good, just wanted to keep the PR smaller, pretty big already
|
| class MyConfig(NativeModuleConfig): | ||
| executable: str = "./build/my_module" # relative or absolute path to your executable | ||
| host_ip: str = "192.168.1.5" # becomes --host_ip 192.168.1.5 | ||
| frequency: float = 10.0 # becomes --frequency 10.0 | ||
| enable_imu: bool = True # becomes --enable_imu true | ||
| filters: list[str] = field(default_factory=lambda: ["a", "b"]) # becomes --filters a,b | ||
| ``` | ||
|
|
||
| - `None` values are skipped. | ||
| - Booleans are lowercased (`true`/`false`). | ||
| - Lists are comma-joined. |
There was a problem hiding this comment.
It's probably safer to pass it as JSON.
There was a problem hiding this comment.
Yeah or ENV actually, given this would make it compatible with Docker modules, need to coordinate this a bit, IMO this is a POC, wanted to create an issue and discuss
dimos/core/native_module.py
Outdated
| self._io_threads = [ | ||
| self._start_reader(self._process.stdout, "info"), | ||
| self._start_reader(self._process.stderr, "warning"), | ||
| ] |
There was a problem hiding this comment.
It's a bit wasteful to start two extra threads just to pipe two streams. You can do everything from the watchdog thread.
There was a problem hiding this comment.
I've put management of these threads in the watchdog, but the code gets really ugly if I try to process everything in the same thread, so keeping split for ease of undertanding now
Remove runtime assert_implements_protocol and test_spec files. Instead, add TYPE_CHECKING instantiation at the bottom of each module file so mypy catches missing or misnamed protocol ports statically.
Move reader thread spawning into the watchdog thread so only one thread is externally managed. Use tmp_path pytest fixture instead of manual tempfile. Use communicate() for build subprocess.
Use argparse in native_echo.py instead of env vars for output_file and die_after. Add these as config fields on StubNativeConfig so they flow through the normal to_cli_args() path.
Replace NATIVE_ECHO_OUTPUT/NATIVE_ECHO_DIE_AFTER env vars with output_file/die_after config fields passed as CLI args. Add type annotations to test functions. Remove stale type: ignore on NativeModule.default_config.
# Conflicts: # dimos/robot/all_blueprints.py
NativeModule arch, Livox Mid-360 LiDAR + FAST-LIO2 Integration, no ros
I have to add screenshots look how cool this sensor is
How do I review?
docs are at https://github.com/dimensionalOS/dimos/blob/3142b5bceb232222982d39d7960319f3d5ec3cf6/docs/usage/native_modules.md
I think NativeModule stuff is important, maybe the way I handle builds via nix, livox/fastlio is just a dumb glue that seems fine in terms of config and computational efficiency so wouldn't bother too much
C++ voxel mapper is just a hashmap. shouldn't look at it, this is vibed and will go away once I write voxel deletion
Summary
NativeModule framework, enables integration third party executables into the dimos module/blueprint system
Native C++ Dimos Module for the Livox mid360
Native C++ Dimos Module for FAST-LIO2
NativeModule
(
dimos/core/native_module.py)should this be named externalmodule or something like that?
Hosts third party process, passes topics to use via CLI to the binary.
Passes also config settings as CLI args
Assumes binary speaks LCM, in the future we can pass also the protocol.
Doesn't support RPC
C++ binaries participate in blueprints like any Python module
Livox Mid-360 driver
dimos/hardware/sensors/lidar/livox/Mid360Modulewith network config (host/lidar IPs, ports)Testing
for native build check cpp/readme.md
FAST-LIO2
(
dimos/hardware/sensors/lidar/fastlio2/)Fastlio binary has livox SDK baked in, talks to mid360 directly, LCM topics lose full spectrum of mid360 data which fastlio depends on.
raw mid360 data is so raw that I assume we'll always use it through fastlio. (for example lidar hits need compensation for rotation state of the scanner and motion of the lidar in space)
for native build check cpp/readme.md
Voxel mapper tests
fastlio has three blueprint configs:
basic ODOM + Pointcloud, ODOM + GlobalMap, ODOM + CPPGlobalMap,
CPP voxel mapper uses PCL library https://pointclouds.org/
and is 2x more efficient then already pretty efficient py/cuda mapper
no voxel deleteons yet
needs a few days of experimenting
Nix build infrastructure
mid360_nativeandfastlio2_nativevia Nix flakesBlueprints
mid360— raw LiDARmid360-fastlio— SLAM with 0.15m voxel filteringmid360-fastlio-voxels— SLAM + downstream VoxelGridMappermid360-fastlio-voxels-native— SLAM + C++ global voxel map at 3Hz