{"id":48987788,"url":"https://github.com/markgol/l2lidar_node","last_synced_at":"2026-04-22T07:00:45.990Z","repository":{"id":349016597,"uuid":"1198216568","full_name":"markgol/l2lidar_node","owner":"markgol","description":"ROS2 publisher node for the Unitree L2 lidar point cloud and IMU data","archived":false,"fork":false,"pushed_at":"2026-04-15T07:18:01.000Z","size":23867,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-18T13:42:00.991Z","etag":null,"topics":["l2","l2lidar","ros2","unitree-l2"],"latest_commit_sha":null,"homepage":"https://github.com/markgol/l2lidar_node","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/markgol.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-01T08:09:42.000Z","updated_at":"2026-04-15T07:13:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/markgol/l2lidar_node","commit_stats":null,"previous_names":["markgol/l2lidar_node"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/markgol/l2lidar_node","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markgol%2Fl2lidar_node","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markgol%2Fl2lidar_node/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markgol%2Fl2lidar_node/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markgol%2Fl2lidar_node/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/markgol","download_url":"https://codeload.github.com/markgol/l2lidar_node/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markgol%2Fl2lidar_node/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32125094,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T00:31:26.853Z","status":"online","status_checked_at":"2026-04-22T02:00:05.693Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["l2","l2lidar","ros2","unitree-l2"],"created_at":"2026-04-18T13:40:43.365Z","updated_at":"2026-04-22T07:00:45.984Z","avatar_url":"https://github.com/markgol.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"l2lidar_node\n============\n\n**updated 2026-04-21**\n============\n\nOverview\n============\n\nl2lidar_ros2 is a standalone ROS 2 Jazzy driver node for the **Unitree L2 4D LiDAR** sensor.  It provides a high-performance interface between the Unitree L2 hardware and ROS 2 by leveraging a Qt 6.10 UDP backend (`L2lidar` class) for deterministic packet handling, timestamp synchronization, and decoding.\n\nThis package publishes synchronized **3D point cloud** and **IMU data** using standard ROS 2 message types and is intended for robotics perception, mapping, and localization applications.\n\nThe node runs without any Qt GUI components and is designed to be launched independently and visualized using RViz2.\n\nThis application utlitizes the L2lidarClass for the driver interface. This driver is also available separately at:\n\nhttps://github.com/markgol/L2lidarClass\n\n\n\nNOTE: This replaces the L2lidar_ros2 (depracated) github repo: https://github.com/markgol/l2lidar_ros2\n\n* * *\n\nFeatures\n--------\n\n* Native ROS 2 Jazzy node (C++20)\n\n* Qt 6.10 UDP backend (Core + Network only, no GUI)\n\n* Publishes:\n  \n  * `/points` — `sensor_msgs/PointCloud2`\n  \n  * `/imu/data` — `sensor_msgs/Imu`\n\n* Deterministic IMU and point cloud synchronization\n\n* Per-point timestamps supported\n\n* Host ↔ LiDAR timebase synchronization\n\n* Static TF transform between LiDAR and IMU frames\n\n* RViz2 visualization support (distance/range coloring)\n\n* Designed for Ubuntu 24.04 + ROS 2 Jazzy\n\n* Target platforms: Raspberry Pi 5 (ARM64) and x86_64\n\n* * *\n\nArchitecture\n------------\n\nUnitree L2 LiDAR (UDP Ethernet)\n\n        |\n\nL2lidar (Qt 6.10 backend)\n\n        |\n\nl2lidar_node\n\n        |\n\n        +--\u003e /points      (PointCloud2)\n\n        +--\u003e /imu/data    (Imu)\n\n        +--\u003e /tf_static\n\n                base_link -\u003e l2lidar_frame (names set in config file)\n\n                l2lidar_frame -\u003e l2lidar_imu (names set in config file)\n\n\n\nThe node uses Qt’s networking and event system for UDP packet reception and ROS 2 publishers for message dissemination. No Qt GUI or ROS GUI dependencies are used.\n\n****\n\n## EXECUTABLES\n\nThe exectuable for gcc_64 (Ubuntu x86_64) has been tested under Windows 11 through WSL2 running Ubuntu24.04.\n\nThe exectuable for aarch64 (gcc_arm64) has been tested under Ubuntu 24.04 on a RPI5.\n\nThere is no executable to run under Windows 11 since Windows 11 does not directly support ROS2.\n\nIf you are only going to use the executables they cna be found at:\n\nhttps://github.com/markgol/l2lidar_node/tree/main/executables\n\n* * *\n\nTopics\n------\n\n| Topic        | Message Type                     | Description                                                   |\n| ------------ | -------------------------------- | ------------------------------------------------------------- |\n| `/points`    | `sensor_msgs/PointCloud2`        | 3D point cloud with intensity, time, and optional range field |\n| `/imu/data`  | `sensor_msgs/Imu`                | Orientation, angular velocity, and linear acceleration        |\n| `/tf_static` | `geometry_msgs/TransformStamped` | Static transform between LiDAR and IMU frames                 |\n\n* * *\n\nParameters\n----------\n\n| Parameter                   | Type   | Default                            | Description                                                 |\n| --------------------------- | ------ | ---------------------------------- | ----------------------------------------------------------- |\n| `l2_ip`                     | string | 192.168.1.62\u003cbr/\u003e(factory default) | LiDAR IP address                                            |\n| `l2_port`                   | int    | 6101\u003cbr/\u003e(factory default)         | LiDAR UDP port                                              |\n| `host_ip`                   | string | 192.168.1.2\u003cbr/\u003e(factory default)  | Host IP address                                             |\n| `host_port`                 | int    | 6201\u003cbr/\u003e(factory default)         | Host UDP port                                               |\n| frame3d                     | bool   | true                               | point cloud data is 3D not 2D                               |\n| imu_adjust                  | bool   | true                               | Apply IMU pose correction to cloud points before publishing |\n| `enable_l2_time_correction` | bool   | `true`                             | Enable LiDAR timestamp correction                           |\n| `enable_l2_host_sync`       | bool   | `true`                             | Enable host → LiDAR time sync                               |\n| `l2_sync_rate_ms`           | int    | `50`                               | Sync rate in milliseconds                                   |\n| `enable_latency_measure`    | bool   | `false`                            | Enable latency measurement                                  |\n| `frame_id`                  | string | `l2lidar_frame`                    | Point cloud frame ID                                        |\n| `imu_frame_id`              | string | `l2lidar_imu`                      | IMU frame ID                                                |\n| robot_id                    | string | base_link                          | Robot origin frame                                          |\n| robot_x                     | float  | 0.0                                | x offset from lidar position                                |\n| robot_y                     | float  | 0.0                                | y offset from lidar position                                |\n| robot_z                     | float  | 0.0                                | z offset from lidar position                                |\n| `enable_IMU_publishing`     | bool   | `false`                            | true - publish IMU data                                     |\n| aggregateNframes            | int    | 38                                 | NUmber of L2 frames to aggregate for publishing             |\n| EnableCalRangeOVR           | bool   | false                              | Override internal L2 Range calibration                      |\n| calRangeScale               | float  | 0.000978                           | Range Scale override value                                  |\n| calRangeBias                | float  | -365.625                           | Range Bias override value                                   |\n| watchdog_timeout_ms         | int    | 35000                              | max time without data from L2 in msec                       |\n\n* * *\n\nBuild Requirements\n------------------\n\n* Ubuntu 24.04\n\n* ROS 2 Jazzy\n\n* Qt 6.10.2 or newer (Core + Network only)\n\n* CMake ≥ 3.22\n\n* C++20\n\n* colcon\n\n* * *\n\nInstallation\n------------\n\n### 1. Install ROS 2 Jazzy\n\nFollow the official ROS 2 Jazzy installation instructions for Ubuntu 24.04.\n\nEnsure ROS is sourced:\n\n`source /opt/ros/jazzy/setup.bash`\n\n* * *\n\n### 2. Install Qt 6.10.2\n\nInstall Qt 6.10.2 using the Qt Online Installer:\n\n`/opt/Qt/6.10.2/gcc_64`\n\nMake sure Qt6 Core and Network modules are installed.\n\n* * *\n\n### 3. Create workspace\n\n(Edit to match your ROS2 workspace folder and repo source)\n\n`mkdir -p ~/ros2_ws/src cd ~/ros2_ws/srcgit clone \u003cyour_repo_url\u003e l2lidar_node`\n\n* * *\n\n### 4. Build\n\n(Edit to match your ROS2 workspace folder)\n\n`cd ~/ros2_ws source /opt/ros/jazzy/setup.bashcolcon build --packages-select l2lidar_node\n\nThen source:\n\n`source install/setup.bash`\n\n* * *\n\nRunning the Node\n----------------\n\nYou should edit this to point to where you have the yaml configuration file.\n\n`run l2lidar_node l2lidar_node --ros-args --params-file \\home\\robot\\SoftwareDev\\ros2_ws\\src\\l2lidar_node\\bin\\gcc_64\\config/l2lidar_node.yaml`\n\nOr using a launch file:\n\n`ros2 launch l2lidar_node l2lidar.launch.py`\n\nOr from terminal in folder with exectuable:\n\n`./l2lidar_node --params-file ./config/l2lidar_node.yaml`\n\nThis assumes are you in the folder with the following files:\n    l2lidar_node\n\n    libQt6Core.so.6.10.2\n\n    libQt6Network.so.6.10.2\n\n    config/l2lidar_node.yaml\n\n* * *\n\nRViz2 Visualization\n-------------------\n\nStart RViz2:\n\n`rviz2`\n\nLoad the provided configuration:\n\n`rviz2 -d share/l2lidar_node/rviz/l2lidar.rviz`\n\nRecommended settings:\n\n* Fixed Frame: `l2lidar_frame`\n\n* PointCloud2:\n  \n  * Topic: `/points`\n  \n  * Color Transformer: `Channel`\n  \n  * Channel Name: `range` or `time`\n  \n  * Autoscale: `false`\n  \n  * Min: `0.0`\n  \n  * Max: `5.0`\n\n* IMU: via TF visualization\n\n* * *\n\nCoordinate Frames\n-----------------\n\nThere are 3 coordinate frames used: imu, lidar, robot\n\nThe orientation (x,y,z axis) are the same in all 3 frames.\n\nStatic transform is published:\n\n`l2lidar_frame  --\u003e  l2lidar_imu\n\n`base_link --\u003e l2lidar_frame\n\nThe l2lidar_frame --\u003e l2lidar_imu is set in the source to match the Unitree L2 published spec.\n\nThe base_lik --\u003e l2lidar_frame is set in the config yaml file and represents the offset from the robot base to the L2 robot location.  The mouting surface of the L2 is not 0.0, 0.0, 0.0.  See the Unitree L2 published specification for the offsets.\n\n* * *\n\nShutdown Behavior\n-----------------\n\nThe node supports:\n\n* Clean shutdown on connection failure\n\n* Signal-safe shutdown (SIGINT / SIGTERM)\n\n* Watchdog timeout handling\n\n* Proper Qt and ROS2 event loop exit\n\n* * *\n\nDebugging\n---------\n\nRun under debugger from QtCreator:\n\n* Configure kit with Qt 6.10\n\n* Source ROS2 environment\n\n* Run target: `l2lidar_node`\n\n* Set breakpoints in:\n  \n  * `onImuReceived()`\n  \n  * `onPointCloudReceived()`\n\n* * *\n\nKnown Limitations\n-----------------\n\n* No GUI configuration (command-line only)\n\n* Static TF only (no dynamic motion TF yet)\n\n* RViz IMU display plugin is not available in Jazzy; visualization is via TF and point cloud only\n\n* Requires Qt 6.10 due to UDP reliability fixes (Qt 6.4 is not supported)\n\n* * *\n\nDesign Goals\n------------\n\n* Deterministic timing\n\n* Zero packet loss\n\n* Minimal dependencies\n\n* No GUI coupling\n\n* High throughput (≈250 Hz IMU, ≈216 Hz point cloud frames)\n\n* Clean shutdown\n\n* Host synced timestamps\n\n* * *\n\nVersion\n-------\n\n**0.1.0** – Initial functional driver with synchronized IMU and point cloud publishing.  This is only the intial release and does not include a prebuilt executable.  That is planned for the 0.2.0 release\n\n**0.2.0** - Added aggregation ofL2 frames for publishing\n\nThis is needed to align point cloud publishing to the requirements for LIO-SAM methodology\n\nChanged point time from float to double.\n\nChanged point time to eliminate truncation errors.\n\nThe L2lidar class sources moved to their own directories.\n\nThe L2lidar class was updated to improve computational accuracy and time stamp handling\n\n**0.2.1** - Included parameters in the config.yaml frame3d and imu_adjust in the implementation\n\nThis allows the user to specify that 3D frames or 2D frames are to be published.  It also allows the user to specify the pose (rotation) correction is to be applied before the point cloud data is published.\n\n**0.2.2** - added static transform publishing, renamed from l2lidar_ros2 to l2lidar_node\n\n**0.2.3** - Made publishing IMU data optional, changed ROS2 QOS publisher settins to SensorData\n\nThis specifies the static fixed transforms.  We already know the l2idar_frame -\u003e l2lidar_imu.  This also adds the transform robot origin frame (base_link) -\u003e l2lidar_frame.  This implies the L2 is at a fixed location on robot.\n\n**0.3.0** - Added override of L2 Range calibration parameters\n\nAdded dynamic settings for certain parameters:\n\n| Parameter        | type  | range            |\n| ---------------- | ----- | ---------------- |\n| imu_adjust       | bool  | true, false      |\n| aggregateNframes | int   | 0 - 4000         |\n| calRangeScale    | float | 0.002 - 0.000250 |\n| calRangeScale    | float | 0.0 to -1000.0   |\n\nNote: When using the ROS2 param set commands float values must have a decimal point or an type error will be generated.  As an example: 100 must be 100.0.\n\n* * *\n\nLicenses\n-------\n\nl2lidar_node license, see license file: l2lidar_node LICENSE.txt\n\nQt license, see license file: Qt LICENSE LGPL.txt\n\nUnitree license, see license file: Unitree BSD-3 LICENSE.txt\n\n* * *\n\nMaintainer\n----------\n\nhttps://github.com/markgol/l2lidar_node  \nSupport and contact via GitHub repository issues.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkgol%2Fl2lidar_node","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarkgol%2Fl2lidar_node","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkgol%2Fl2lidar_node/lists"}