Skip to content
Open
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
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,13 @@ CMakeLists.txt.user

# pre-commit
node_modules/

# Local notes / scratch files
claude.txt

# Pasted screenshots and videos used for debugging
Pasted image*.png
Pasted image*.jpg
*.MOV
*.mov
*.mp4
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Nebula works with ROS 2 and is the recommended sensor driver for the [Autoware](
- [Quick start](#quick-start)
- [Agnocast](#agnocast)
- [Building only specific vendors](#building-only-specific-vendors)
- [Ouster](#ouster)
- [Migration to Nebula 0.3.0](#migration-to-nebula-030)

## Documentation
Expand Down Expand Up @@ -178,8 +179,37 @@ Available vendor packages are:
- `nebula_hesai` - Hesai LiDARs (Pandar series, AT128, OT128, etc.)
- `nebula_velodyne` - Velodyne LiDARs (VLP-16, VLP-32, VLS-128)
- `nebula_robosense` - Robosense LiDARs (Bpearl, Helios)
- `nebula_ouster` - Ouster LiDARs (OS0, OS1, OS2 — all beam counts; native decoder, no external SDK)
- `nebula_continental` - Continental radars (ARS548, SRR520)

## Ouster

The `nebula_ouster` package is a native Nebula driver for Ouster OS-0 / OS-1 / OS-2 sensors
(any beam count, including OS-128). It decodes Ouster UDP packets directly and does not depend
on `ouster-sdk`.

Setup steps:

1. Build the package:

```bash
colcon build --packages-up-to nebula_ouster --cmake-args -DCMAKE_BUILD_TYPE=Release
```

2. Edit `src/nebula_ouster/nebula_ouster/config/ouster_sensor.param.yaml` and set
`connection.sensor_ip` and `connection.host_ip` to match your environment. Update
`frame_id` if needed.

3. Launch:

```bash
ros2 launch nebula_ouster ouster_launch_all_hw.xml
```

The decoder publishes point clouds on `/points`, IMU samples on `/imu`, and raw packets on
`/packets`. For offline rosbag replay without the sensor, set `metadata_file` to a cached
metadata JSON path and launch with `launch_hw:=false`.

## Migration to Nebula 0.3.0

Version 0.3.0 separates vendor-specific functionality into individual packages. This allows users
Expand Down
1 change: 1 addition & 0 deletions src/nebula/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

<depend>nebula_continental</depend>
<depend>nebula_hesai</depend>
<depend>nebula_ouster</depend>
<depend>nebula_robosense</depend>
<depend>nebula_velodyne</depend>

Expand Down
62 changes: 62 additions & 0 deletions src/nebula_ouster/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Nebula Ouster sensor package

Native Nebula driver for Ouster LiDAR sensors (OS-0 / OS-1 / OS-2 at 32, 64, or 128 beams).
The driver decodes Ouster UDP packets directly — it does **not** depend on `ouster-sdk`.

## Features

- Native packet parsing for the `RNG19_RFL8_SIG16_NIR16` (single return),
`RNG19_RFL8_SIG16_NIR16_DUAL` (dual return), and `LEGACY` UDP profiles.
- Dual return support — points from both returns are published with the correct `return_type`
field (`FIRST` and `LAST`).
- IMU output — Ouster IMU packets (~100 Hz) are decoded and published as `sensor_msgs/Imu`.
- Metadata caching — sensor metadata JSON can be cached to a file so offline rosbag replay
does not require the sensor to be reachable.
- No external SDK dependencies; uses only Nebula's built-in HTTP and UDP clients.

## Package structure

The driver is split into the four standard Nebula sub-packages:

- **nebula_ouster_common** — sensor configuration structs
- **nebula_ouster_decoders** — packet parsing, XYZ lookup, metadata JSON parsing
- **nebula_ouster_hw_interfaces** — UDP receive socket wrapper
- **nebula_ouster** — ROS 2 wrapper node, launch files, diagnostics

## Building

```bash
colcon build --packages-up-to nebula_ouster
```

## Running

Edit `config/ouster_sensor.param.yaml` and set `connection.sensor_ip` and `connection.host_ip`
to match your network. Then:

```bash
# Live hardware
ros2 launch nebula_ouster ouster_launch_all_hw.xml

# Offline replay (uses cached metadata_file; subscribes to NebulaPackets on the 'packets' topic)
ros2 launch nebula_ouster ouster_launch_all_hw.xml launch_hw:=false
```

## Topics

| Topic | Type | Description |
|-------|------|-------------|
| `points` | `sensor_msgs/PointCloud2` | Decoded point cloud (`PointXYZIRCAEDT`) |
| `imu` | `sensor_msgs/Imu` | IMU sample (~100 Hz) |
| `packets` | `nebula_msgs/NebulaPackets` | Raw packet stream for rosbag recording |

## Parameters

See `config/ouster_sensor.param.yaml` for the full list. Key parameters:

- `connection.sensor_ip` / `connection.host_ip` / `connection.data_port`
- `connection.imu_port` — dedicated UDP socket for IMU packets (set to 0 to disable)
- `launch_hw` — `true` for live hardware, `false` for rosbag replay via `NebulaPackets`
- `metadata_file` — optional cache path; enables offline replay without the sensor
- `fov.azimuth.min_deg` / `max_deg`, `fov.elevation.min_deg` / `max_deg` — FoV crop
- `frame_id` — TF frame used for the point cloud and IMU topics
61 changes: 61 additions & 0 deletions src/nebula_ouster/nebula_ouster/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
cmake_minimum_required(VERSION 3.20)
project(nebula_ouster)

find_package(autoware_cmake REQUIRED)
autoware_package()

add_library(
ouster_ros_wrapper SHARED
src/ouster_ros_wrapper.cpp)

target_include_directories(
ouster_ros_wrapper
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)

target_link_libraries(
ouster_ros_wrapper
PUBLIC diagnostic_updater::diagnostic_updater
nebula_ouster_decoders::nebula_ouster_decoders
nebula_ouster_hw_interfaces::nebula_ouster_hw_interfaces
nebula_core_ros::nebula_core_ros)
ament_target_dependencies(
ouster_ros_wrapper
PUBLIC
diagnostic_msgs
nebula_msgs
rclcpp
rclcpp_components
sensor_msgs
std_msgs)

rclcpp_components_register_node(ouster_ros_wrapper PLUGIN "nebula::ros::OusterRosWrapper"
EXECUTABLE ouster_ros_wrapper_node)

install(
TARGETS ouster_ros_wrapper
EXPORT export_ouster_ros_wrapper
LIBRARY DESTINATION lib)
install(DIRECTORY include/${PROJECT_NAME}/ DESTINATION include/${PROJECT_NAME})

install(DIRECTORY config launch DESTINATION share/${PROJECT_NAME})

ament_export_include_directories("include/${PROJECT_NAME}")
ament_export_targets(export_ouster_ros_wrapper)

ament_export_dependencies(
diagnostic_msgs
diagnostic_updater
nebula_core_common
nebula_ouster_common
nebula_core_decoders
nebula_ouster_decoders
nebula_core_hw_interfaces
nebula_ouster_hw_interfaces
nebula_core_ros
nebula_msgs
rclcpp_components
sensor_msgs
std_msgs)

ament_package()
46 changes: 46 additions & 0 deletions src/nebula_ouster/nebula_ouster/config/ouster_sensor.param.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Ouster Sensor ROS 2 Parameters
# Example configuration for an OS-128. Adjust `connection.*` and `frame_id` to match your setup.

/**:
ros__parameters:
# ROS wrapper configuration
sensor_model: OS-128
launch_hw: true
frame_id: ouster_lidar

# Optional: cache sensor metadata JSON. When launch_hw is true and this path is set,
# the wrapper saves metadata fetched via HTTP here. When launch_hw is false, it loads
# metadata from this file instead of contacting the sensor. Leave empty to always use HTTP.
metadata_file: ""

# Network configuration. `data_port` 7502 is the Ouster default for lidar data; the sensor
# also sends IMU packets to the same port.
connection:
sensor_ip: 192.168.1.201
host_ip: 192.168.1.100
data_port: 7502
# Set to 0 to disable the separate IMU socket. Ouster's factory default is 7503.
imu_port: 7503
filter_sender_ip: true

# Decoder configuration — points outside this azimuth/elevation range are filtered out.
fov:
azimuth:
min_deg: 0.0
max_deg: 360.0
elevation:
min_deg: -45.0
max_deg: 45.0

# Diagnostics configuration
diagnostics:
pointcloud_publish_rate:
frequency_ok:
min_hz: 9.0
max_hz: 11.0
frequency_warn:
min_hz: 8.0
max_hz: 12.0
num_frame_transition: 1
packet_liveness:
timeout_ms: 1000
Loading
Loading