mirror of
https://github.com/introlab/rtabmap_ros.git
synced 2026-10-12 04:29:49 +08:00
* rtabmap_demos tests and docs * added bag testing * added rtabmap_examples launch tests * updating demo bag download paths * added netherdrone demo * Fixed rgb-only callback with lidar rejected. Updated lidar params * Added back OrbitOriented rviz view to ros2, with optional octomap wll clipping * fixing ci * lidar demo added intermediate_nodes option * added netherdrone as demo test * running rtabmap_demos tests on ci * added rtabmap_launch tests, fixed ground_truth_base_frame_id usage * ficing rolling * updating demo test harnest * densify golden trajectories to avoid tf missing * fixing tf steps * updated min icp ratio for netherdrone demo * fixing image_transport arg->params * export pose opt=0 * lets process all frames * updated netherdrone golden * fixing publishers queue size just for tests * added playdback demo doc * Adding more logs to debug ci * Fixing QOS for CI to reliable, added find-object demo test * name threads * fixing camera info expected transient on lyrical/rolling. Fixing find_object not appearing idle * 30 Hz polling backward comp * fixing test tf sim lock * fixing lyrical qos bag parsing * faster replay * lockstep * fixing clock deadlock * Added test on shutdown * updated netherdrone golden poses * Extended stereo outdoor test * updated shutdown test * updated test * multi-thread flaky test * adding backtrace when test fails * increased closure slack for netherdrone * g2o gauss newton on stereo * adjusted maximum optimizer iterations * updated default iterations * Added netherdrone in list of demos
108 lines
5.2 KiB
Markdown
108 lines
5.2 KiB
Markdown
# lidar_deskewing
|
|
|
|
Removes the motion distortion from a lidar scan.
|
|
|
|
A spinning lidar takes tens of milliseconds to complete a sweep, and on a moving robot every point in that sweep is measured from a slightly different pose. The result is a *skewed* cloud: straight walls come out bent, and registration against it drifts.
|
|
|
|
This node uses TF to find where the sensor actually was when each point was taken, and moves every point into the pose at the start of the sweep. A straight wall comes back straight.
|
|
|
|
## Contents
|
|
|
|
- [Usage](#usage)
|
|
- [Subscribed Topics](#subscribed-topics)
|
|
- [Published Topics](#published-topics)
|
|
- [Required Transforms](#required-transforms)
|
|
- [Parameters](#parameters)
|
|
- [Requirements](#requirements)
|
|
- [Behavior when TF is missing](#behavior-when-tf-is-missing)
|
|
- [Notes](#notes)
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
ros2 run rtabmap_util lidar_deskewing --ros-args \
|
|
-p fixed_frame_id:=odom \
|
|
-r input_cloud:=/velodyne_points
|
|
```
|
|
|
|
```python
|
|
ComposableNode(
|
|
package='rtabmap_util',
|
|
plugin='rtabmap_util::LidarDeskewing',
|
|
name='lidar_deskewing',
|
|
parameters=[{'fixed_frame_id': 'odom'}],
|
|
remappings=[('input_cloud', '/velodyne_points')])
|
|
```
|
|
|
|
## Subscribed Topics
|
|
|
|
Connect one of the two.
|
|
|
|
| Topic | Type | Description |
|
|
|---|---|---|
|
|
| `input_cloud` | [`sensor_msgs/msg/PointCloud2`](https://docs.ros.org/en/jazzy/p/sensor_msgs/msg/PointCloud2.html) | Must carry a **per-point time channel**, see [Requirements](#requirements). |
|
|
| `input_scan` | [`sensor_msgs/msg/LaserScan`](https://docs.ros.org/en/jazzy/p/sensor_msgs/msg/LaserScan.html) | Per-point times come from `time_increment`. |
|
|
|
|
## Published Topics
|
|
|
|
Output names are derived from the **resolved** input names, so remapping the input moves the output with it. With `input_cloud` remapped to `/velodyne_points` the output is `/velodyne_points/deskewed`.
|
|
|
|
| Topic | Type | Description |
|
|
|---|---|---|
|
|
| `<input_cloud>/deskewed` | [`sensor_msgs/msg/PointCloud2`](https://docs.ros.org/en/jazzy/p/sensor_msgs/msg/PointCloud2.html) | The deskewed cloud, same frame and stamp as the input. |
|
|
| `<input_scan>/deskewed` | [`sensor_msgs/msg/PointCloud2`](https://docs.ros.org/en/jazzy/p/sensor_msgs/msg/PointCloud2.html) | A `LaserScan` cannot represent a deskewed sweep — the points no longer lie on a regular angular grid — so the scan input also produces a cloud. |
|
|
|
|
## Required Transforms
|
|
|
|
| Transform | Description |
|
|
|---|---|
|
|
| `fixed_frame_id` → sensor frame, across the sweep | Must be available for the whole span of the sweep, at both its first and last stamp. |
|
|
|
|
## Parameters
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|---|---|---|---|
|
|
| `fixed_frame_id` | `string` | `""` | **Required.** Frame the motion is measured against, usually `odom`. |
|
|
| `wait_for_transform` | `double` | `0.01` | Seconds to wait for the transforms spanning the sweep. Raise it if odometry lags the lidar. |
|
|
| `slerp` | `bool` | `false` | Interpolate between the poses at the start and end of the sweep instead of looking up TF per point. Much cheaper, and accurate enough at constant velocity. |
|
|
| `queue_size` | `int` | `5` | Queue depth of the input subscriptions. |
|
|
| `output_queue_size` | `int` | `1` | History depth of the deskewed cloud publishers. |
|
|
| `qos` | `int` | `0` | Reliability of the input subscriptions: `0` system default, `1` reliable, `2` best effort. |
|
|
|
|
## Requirements
|
|
|
|
For `input_cloud`, the cloud **must have a per-point time field**. Without one the node cannot know when each point was taken and cannot deskew.
|
|
|
|
The field has to be named `t`, `time`, `stamps` or `timestamp` — anything else is not recognized, whatever it contains. Its type decides how the value is read:
|
|
|
|
| Type | Meaning |
|
|
|---|---|
|
|
| `uint32` | nanoseconds since the cloud's own stamp |
|
|
| `float32` | seconds since the cloud's own stamp |
|
|
| `float64` | an absolute timestamp; seconds, milliseconds, microseconds and nanoseconds are told apart by magnitude |
|
|
|
|
Common drivers that satisfy this out of the box: **Ouster** (`t`), **Velodyne** (`time`), **RoboSense** (`timestamp`) and **Livox** (`timestamp`). Livox needs its PointCloud2 output rather than the default `CustomMsg` format, which this node cannot subscribe to at all.
|
|
|
|
To check what your driver actually publishes:
|
|
|
|
```bash
|
|
ros2 topic echo /your/points --field fields --once
|
|
```
|
|
|
|
If none of the four names is in that list, look for a driver option to add per-point timestamps before anything else.
|
|
|
|
The `fixed_frame_id` → sensor transform must cover the whole sweep, which means **odometry has to be at least as recent as the lidar**. If it lags, raise `wait_for_transform`.
|
|
|
|
## Behavior when TF is missing
|
|
|
|
The two inputs deliberately differ:
|
|
|
|
- A **cloud** is republished **unchanged** with a warning. Deskewing is an improvement, not a precondition, and dropping frames would break the pipeline behind it.
|
|
- A **scan** is **dropped**, because converting it to a cloud is only worth doing as part of deskewing.
|
|
|
|
## Notes
|
|
|
|
Deskewing matters most when rotating: at 1 rad/s a 100 ms sweep spans nearly 6°, and the far end of the scan is badly misplaced. Pure translation at walking speed is a few centimeters, which matters at close range.
|
|
|
|
Put this node before ICP odometry or [point_cloud_assembler](point_cloud_assembler.md), not after. Anything registering against a skewed cloud has already paid for the distortion.
|