Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
FROM ros:humble

ARG DEBIAN_FRONTEND=noninteractive

# Install system and ROS2 dependencies
RUN apt-get update && apt-get install -y \
build-essential \
cmake \
git \
wget \
curl \
python3-colcon-common-extensions \
python3-rosdep \
python3-vcstool \
libpcl-dev \
libapr1-dev \
libaprutil1-dev \
ros-humble-rclcpp \
ros-humble-rclcpp-components \
ros-humble-std-msgs \
ros-humble-sensor-msgs \
ros-humble-rcl-interfaces \
ros-humble-pcl-conversions \
ros-humble-pcl-ros \
ros-humble-rosbag2 \
ros-humble-rosidl-default-generators \
ros-humble-rosidl-default-runtime \
ros-humble-ament-lint-auto \
ros-humble-ament-lint-common \
&& rm -rf /var/lib/apt/lists/*

RUN \
echo "Installing livox_sdk2..." && \
REPO_DIR="/tmp/livox_sdk2_repo" && \
mkdir -p "$REPO_DIR" && \
git clone --branch v1.2.5 --depth 1 https://github.com/Livox-SDK/Livox-SDK2.git "$REPO_DIR/Livox-SDK2" && \
cd "$REPO_DIR/Livox-SDK2" && \
mkdir -p build && \
cd build && \
rm -rf * && \
cmake .. && \
make -j$(nproc) && \
make install && \
echo "livox_sdk2 installed successfully." && \
cd "/" && \
rm -rf "$REPO_DIR" && \
ldconfig


# Source ROS2 in every new shell
RUN echo "source /opt/ros/humble/setup.bash" >> /etc/bash.bashrc

# Set up workspace directory
WORKDIR /ros2_ws
38 changes: 38 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "livox_ros_driver2 (ROS2 Humble)",
"dockerComposeFile": "docker-compose.yml",
"service": "devcontainer",
"workspaceFolder": "/ros2_ws/src/livox_ros_driver2",
"remoteEnv": {
"ROS_DISTRO": "humble",
"AMENT_PREFIX_PATH": "/opt/ros/humble",
"ROS_DOMAIN_ID": "0"
},
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.cpptools",
"ms-vscode.cmake-tools",
"ms-python.python"
],
"settings": {
"terminal.integrated.defaultProfile.linux": "bash",
"terminal.integrated.profiles.linux": {
"bash": {
"path": "/bin/bash",
"args": ["--login"]
}
},
"cmake.buildDirectory": "/ros2_ws/build/livox_ros_driver2",
"C_Cpp.default.includePath": [
"/opt/ros/humble/include/**",
"/ros2_ws/src/livox_ros_driver2/src/**",
"/ros2_ws/src/livox_ros_driver2/3rdparty/**"
]
}
}
},
"postCreateCommand": "cd /ros2_ws && bash -c 'source /opt/ros/humble/setup.bash && cp src/livox_ros_driver2/package_ROS2.xml src/livox_ros_driver2/package.xml'",
"postStartCommand": ". /opt/ros/humble/setup.sh",
"features": {}
}
23 changes: 23 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
version: '3.8'

services:
devcontainer:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ..:/ros2_ws/src/livox_ros_driver2:cached
networks:
default: {}
livox_net:
ipv4_address: 192.168.1.10
command: sleep infinity

networks:
livox_net:
driver: bridge
ipam:
driver: default
config:
- subnet: 192.168.1.0/24
gateway: 192.168.1.1
44 changes: 44 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Livox ROS Driver 2 — Copilot Instructions

## Project Overview

This is a ROS2 device driver for Livox 3D LiDAR sensors (MID360, HAP). It targets **ROS2 Humble or later**. The codebase also retains partial ROS1 compatibility gated behind `#ifdef BUILDING_ROS1` preprocessor guards. But only ever work on the ROS2 code.

The driver supports running a **single node that manages multiple lidars** (the recommended approach for dual MID360 setups): one SDK instance handles both lidars, eliminating cross-instance SDK race conditions. See `launch/dual_mid360_launch.py`.

## Build and Test

```bash
# From the workspace root (/ros2_ws)
colcon build

```

## Architecture

- **`src/driver_node.*`** — ROS2 node entry point, lifecycle management; includes watchdog timer and Race-3 reconnect timer
- **`src/lddc.*`** — Lidar Data Distribution Center; routes point cloud and IMU data to ROS publishers
- **`src/lds_lidar.*` / `src/lds.*`** — Lidar Device Scheduler; manages sensor connections and data pipelines
- **`src/comm/`** — Low-level communication utilities: queues, semaphores, caching, and the central `PubHandler` (with per-handle allowlist)
- **`src/call_back/`** — SDK callback handlers for incoming lidar/IMU frames
- **`src/parse_cfg_file/`** — JSON config file parsing (uses RapidJSON from `3rdparty/`)
- **`src/include/`** — Shared headers; `ros_headers.h` abstracts ROS1/ROS2 includes; `livox_log.h` provides node-free logging macros
- **`config/`** — Per-sensor JSON configuration files
- **`launch/`** — ROS2 Python launch files; `dual_mid360_launch.py` launches ONE node for BOTH MID360 lidars
- **`src/tools/`** — Standalone CLI tools: `livox_scan` (discover lidars) and `livox_set_ip` (configure lidar IPs)

## Code Conventions

- **Language**: C++14, namespace `livox_ros`
- **Naming**: `PascalCase` for classes, `snake_case` for functions and member variables
- **Header guards**: `#ifndef LIVOX_<MODULE>_H` / `#define LIVOX_<MODULE>_H`
- **ROS abstraction**: Use the wrappers in `src/include/ros_headers.h` rather than including ROS headers directly; guard any ROS1-specific code with `#ifdef BUILDING_ROS1`
- **Logging**: Use `LIVOX_INFO` / `LIVOX_WARN` / `LIVOX_ERROR` / `LIVOX_DEBUG` macros from `src/include/livox_log.h` for node-free logging; they route to `RCLCPP_*` in ROS2 and `ROS_*` in ROS1
- **Thread safety**: `connect_state` in `LidarDevice` is `std::atomic<LidarConnectState>`; use `memory_order_acquire` / `memory_order_release` at all access sites
- **JSON parsing**: Use the bundled RapidJSON library in `3rdparty/rapidjson/`
- **License header**: All new source files must include the MIT license block present in existing files

## Dependencies

Key runtime deps: `rclcpp`, `rclcpp_components`, `sensor_msgs`, `pcl_conversions`, `livox_lidar_sdk`.
Do **not** add new third-party libraries without updating both `CMakeLists.txt` and `package.xml`.
60 changes: 60 additions & 0 deletions .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Copilot Setup Steps

on:
workflow_dispatch:

push:
branches:
- master
paths:
- .github/workflows/copilot-setup-steps.yml

pull_request:
paths:
- .github/workflows/copilot-setup-steps.yml

jobs:
copilot-setup-steps:
runs-on: ubuntu-22.04
permissions:
contents: read

steps:
- name: setup workspace
run: |
mkdir -p ${GITHUB_WORKSPACE}/src

- uses: actions/checkout@v6
with:
path: src/livox_ros_driver2

- name: setup ROS environment
uses: ros-tooling/setup-ros@v0.7

- name: install workspace dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake ros-humble-ros-base
source /opt/ros/humble/setup.bash
rosdep update --rosdistro humble
rosdep install --from-paths ${GITHUB_WORKSPACE}/src --ignore-src -r -y

- name: install Livox SDK2
run: |
REPO_DIR="/tmp/livox_sdk2_repo"
mkdir -p "$REPO_DIR"
git clone --branch v1.2.5 --depth 1 https://github.com/Livox-SDK/Livox-SDK2.git "$REPO_DIR/Livox-SDK2"
cd "$REPO_DIR/Livox-SDK2"
mkdir -p build && cd build
cmake ..
make -j$(nproc)
sudo make install
sudo ldconfig
rm -rf "$REPO_DIR"

- name: build workspace
run: |
cd ${GITHUB_WORKSPACE}
source /opt/ros/humble/setup.bash
colcon build --symlink-install --continue-on-error || true
source install/setup.bash
80 changes: 80 additions & 0 deletions .github/workflows/ros-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: ros CI

on:
push:
# you may want to configure the branches that this should be run on here.
branches: [ "master" ]
pull_request:

jobs:
test_docker: # On Linux, iterates on all ROS 1 and ROS 2 distributions.
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
matrix:
ros_distribution:
# - noetic
- humble
# - iron

# Define the Docker image(s) associated with each ROS distribution.
# The include syntax allows additional variables to be defined, like
# docker_image in this case. See documentation:
# https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#example-including-configurations-in-a-matrix-build
#
# Platforms are defined in REP 3 and REP 2000:
# https://ros.org/reps/rep-0003.html
# https://ros.org/reps/rep-2000.html
include:
# Noetic Ninjemys (May 2020 - May 2025)
# - docker_image: ubuntu:focal
# ros_distribution: noetic
# ros_version: 1

# Humble Hawksbill (May 2022 - May 2027)
- docker_image: ubuntu:jammy
ros_distribution: humble
ros_version: 2

# Iron Irwini (May 2023 - November 2024)
# - docker_image: ubuntu:jammy
# ros_distribution: iron
# ros_version: 2

# # Rolling Ridley (No End-Of-Life)
# - docker_image: ubuntu:jammy
# ros_distribution: rolling
# ros_version: 2

container:
image: ${{ matrix.docker_image }}
steps:
- uses: actions/checkout@v6
with:
path: src/livox_ros_driver2
- name: setup ROS environment
uses: ros-tooling/setup-ros@v0.7
- name: install build dependencies
run: |
apt-get update
apt-get install -y build-essential cmake
- name: install Livox SDK2
run: |
REPO_DIR="/tmp/livox_sdk2_repo"
mkdir -p "$REPO_DIR"
git clone --branch v1.2.5 --depth 1 https://github.com/Livox-SDK/Livox-SDK2.git "$REPO_DIR/Livox-SDK2"
Comment thread
marc-hanheide marked this conversation as resolved.
cd "$REPO_DIR/Livox-SDK2"
mkdir -p build && cd build
cmake ..
make -j$(nproc)
make install
ldconfig
rm -rf "$REPO_DIR"
- name: build and test ROS 2
if: ${{ matrix.ros_version == 2 }}
uses: ros-tooling/action-ros-ci@v0.3
with:
import-token: ${{ github.token }}
target-ros2-distro: ${{ matrix.ros_distribution }}
skip-tests: true
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.vscode
build
package.xml
#package.xml
__pycache__
36 changes: 35 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
# Set defaults if not specified, using ROS environment variables when available
if(NOT DEFINED ROS_EDITION)
if(DEFINED ENV{ROS_VERSION})
if("$ENV{ROS_VERSION}" STREQUAL "1")
set(ROS_EDITION "ROS1" CACHE STRING "ROS edition to build for (ROS1 or ROS2)" FORCE)
else()
set(ROS_EDITION "ROS2" CACHE STRING "ROS edition to build for (ROS1 or ROS2)" FORCE)
endif()
else()
set(ROS_EDITION "ROS2" CACHE STRING "ROS edition to build for (ROS1 or ROS2)" FORCE)
endif()
endif()

if(NOT DEFINED HUMBLE_ROS)
if(DEFINED ENV{ROS_DISTRO})
set(HUMBLE_ROS "$ENV{ROS_DISTRO}" CACHE STRING "ROS2 distro name" FORCE)
else()
set(HUMBLE_ROS "humble" CACHE STRING "ROS2 distro name" FORCE)
endif()
endif()

# judge which cmake codes to use
if(ROS_EDITION STREQUAL "ROS1")

Expand Down Expand Up @@ -317,6 +338,19 @@ else(ROS_EDITION STREQUAL "ROS2")
EXECUTABLE ${PROJECT_NAME}_node
)

# livox: unified command-line tool (search, setup, reboot, reset, firmware_upgrade)
# Replaces the former livox_set_ip, livox_scan, and livox_reboot tools.
add_executable(livox src/tools/livox.cpp)
target_include_directories(livox PRIVATE
${LIVOX_LIDAR_SDK_INCLUDE_DIR}
)
target_link_libraries(livox
${LIVOX_LIDAR_SDK_LIBRARY}
)
install(TARGETS livox
DESTINATION lib/${PROJECT_NAME}
)

if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
Expand All @@ -330,7 +364,7 @@ else(ROS_EDITION STREQUAL "ROS2")

ament_auto_package(INSTALL_TO_SHARE
config
launch_ROS2
launch
)

endif()
Loading
Loading