mirror of
https://github.com/orbbec/OrbbecSDK_ROS2.git
synced 2026-10-04 12:07:46 +08:00
Add publish_n_pkts param
This commit is contained in:
@@ -55,11 +55,8 @@ rviz2
|
|||||||
```
|
```
|
||||||
|
|
||||||
1. Open Rviz2.
|
1. Open Rviz2.
|
||||||
|
|
||||||
2. Add a `PointCloud2` or `LaserScan` display.
|
2. Add a `PointCloud2` or `LaserScan` display.
|
||||||
|
|
||||||
3. For `PointCloud2`, select the `/lidar/cloud/points` topic; for `LaserScan`, select the `/lidar/scan/points` topic.
|
3. For `PointCloud2`, select the `/lidar/cloud/points` topic; for `LaserScan`, select the `/lidar/scan/points` topic.
|
||||||
|
|
||||||
4. Set the `Fixed Frame` to `lidar_lidar_frame` to properly align the data.
|
4. Set the `Fixed Frame` to `lidar_lidar_frame` to properly align the data.
|
||||||
|
|
||||||
* `PointCloud2` visualization example:
|
* `PointCloud2` visualization example:
|
||||||
@@ -119,6 +116,7 @@ The `lidar.launch.py` file contains default parameters for the driver. You can c
|
|||||||
- **tf_publish_rate**: TF publishing frequency.
|
- **tf_publish_rate**: TF publishing frequency.
|
||||||
- **lidar_format**: Data format for the LiDAR. Optional values: `LIDAR_POINT`, `LIDAR_SPHERE_POINT`, `LIDAR_SCAN`
|
- **lidar_format**: Data format for the LiDAR. Optional values: `LIDAR_POINT`, `LIDAR_SPHERE_POINT`, `LIDAR_SCAN`
|
||||||
- **lidar_rate**: Scan rate of the LiDAR.
|
- **lidar_rate**: Scan rate of the LiDAR.
|
||||||
|
- **publish_n_pkts**: Number of frames to accumulate before publishing merged point cloud. Range: 1-12000. Only effective when lidar_format is `LIDAR_POINT` or `LIDAR_SPHERE_POINT`, used to merge specified number of frames before publishing. Default value: `1`
|
||||||
- **enable_scan_to_point**: Enable conversion of scan data to point cloud data, publishing PointCloud2 data type topics.
|
- **enable_scan_to_point**: Enable conversion of scan data to point cloud data, publishing PointCloud2 data type topics.
|
||||||
- **repetitive_scan_mode**: Repetitive scan mode parameter.
|
- **repetitive_scan_mode**: Repetitive scan mode parameter.
|
||||||
- **filter_level**: Add filter level parameter.
|
- **filter_level**: Add filter level parameter.
|
||||||
@@ -143,14 +141,15 @@ The `lidar.launch.py` file contains default parameters for the driver. You can c
|
|||||||
|
|
||||||
## Point Cloud Data Detailed Description
|
## Point Cloud Data Detailed Description
|
||||||
|
|
||||||
Livox PointCloud2 (PointXYZRT) point cloud format is as follows:
|
PointCloud2 (PointXYZITO) point cloud format is as follows:
|
||||||
|
|
||||||
```
|
```
|
||||||
float32 x # X axis, unit:m
|
float32 x # X axis, unit:m
|
||||||
float32 y # Y axis, unit:m
|
float32 y # Y axis, unit:m
|
||||||
float32 z # Z axis, unit:m
|
float32 z # Z axis, unit:m
|
||||||
uint8 intensity # lidar intensity
|
uint8 intensity # lidar intensity
|
||||||
uint8 tag # lidar tag
|
uint8 tag # lidar tag
|
||||||
|
uint32 offset_time # Point cloud offset time relative to topic time, in nanoseconds
|
||||||
```
|
```
|
||||||
|
|
||||||
## 3. IMU Data
|
## 3. IMU Data
|
||||||
@@ -178,6 +177,7 @@ ros2 topic echo /lidar/imu/sample
|
|||||||
```
|
```
|
||||||
|
|
||||||
The IMU data includes:
|
The IMU data includes:
|
||||||
|
|
||||||
- **linear_acceleration**: 3D acceleration data (x, y, z) in m/s²
|
- **linear_acceleration**: 3D acceleration data (x, y, z) in m/s²
|
||||||
- **angular_velocity**: 3D angular velocity data (x, y, z) in rad/s
|
- **angular_velocity**: 3D angular velocity data (x, y, z) in rad/s
|
||||||
- **orientation**: Quaternion orientation (not provided by hardware, set to zero)
|
- **orientation**: Quaternion orientation (not provided by hardware, set to zero)
|
||||||
|
|||||||
+4
-2
@@ -116,6 +116,7 @@ ros2 run orbbec_camera list_camera_profile_mode_node
|
|||||||
- **tf_publish_rate**: TF发布频率。
|
- **tf_publish_rate**: TF发布频率。
|
||||||
- **lidar_format**: 激光雷达的数据格式。可选值:`LIDAR_POINT`、`LIDAR_SPHERE_POINT`、`LIDAR_SCAN`
|
- **lidar_format**: 激光雷达的数据格式。可选值:`LIDAR_POINT`、`LIDAR_SPHERE_POINT`、`LIDAR_SCAN`
|
||||||
- **lidar_rate**: 激光雷达的扫描频率。
|
- **lidar_rate**: 激光雷达的扫描频率。
|
||||||
|
- **publish_n_pkts**: 多帧数据合并发布的帧数量。范围:1-12000。仅在激光雷达格式为 `LIDAR_POINT` 或 `LIDAR_SPHERE_POINT` 时生效,用于累积指定数量的帧后再发布合并的点云数据。默认值:`1`
|
||||||
- **enable_scan_to_point**: 启用扫描数据到点云数据的转换,发布PointCloud2数据类型话题。
|
- **enable_scan_to_point**: 启用扫描数据到点云数据的转换,发布PointCloud2数据类型话题。
|
||||||
- **repetitive_scan_mode**: 重复扫描模式参数。
|
- **repetitive_scan_mode**: 重复扫描模式参数。
|
||||||
- **filter_level**: 添加过滤级别参数。
|
- **filter_level**: 添加过滤级别参数。
|
||||||
@@ -140,14 +141,15 @@ ros2 run orbbec_camera list_camera_profile_mode_node
|
|||||||
|
|
||||||
## 点云数据详细说明
|
## 点云数据详细说明
|
||||||
|
|
||||||
Livox PointCloud2 (PointXYZRT) 点云格式如下:
|
PointCloud2 (PointXYZITO) 点云格式如下:
|
||||||
|
|
||||||
```
|
```
|
||||||
float32 x # X轴,单位:米
|
float32 x # X轴,单位:米
|
||||||
float32 y # Y轴,单位:米
|
float32 y # Y轴,单位:米
|
||||||
float32 z # Z轴,单位:米
|
float32 z # Z轴,单位:米
|
||||||
uint8 intensity # 激光雷达强度
|
uint8 intensity # 激光雷达强度
|
||||||
uint8 tag # 激光雷达标签
|
uint8 tag # 激光雷达标签
|
||||||
|
uint32 offset_time # 点云相对话题时间的偏移量,单位纳秒
|
||||||
```
|
```
|
||||||
|
|
||||||
## 3. IMU数据
|
## 3. IMU数据
|
||||||
|
|||||||
@@ -184,6 +184,10 @@ class OBLidarNode {
|
|||||||
|
|
||||||
void publishSpherePointCloud(std::shared_ptr<ob::FrameSet> frame_set);
|
void publishSpherePointCloud(std::shared_ptr<ob::FrameSet> frame_set);
|
||||||
|
|
||||||
|
void publishMergedPointCloud();
|
||||||
|
|
||||||
|
void publishMergedSpherePointCloud();
|
||||||
|
|
||||||
uint64_t getFrameTimestampUs(const std::shared_ptr<ob::Frame>& frame);
|
uint64_t getFrameTimestampUs(const std::shared_ptr<ob::Frame>& frame);
|
||||||
|
|
||||||
void filterScan(sensor_msgs::msg::LaserScan& scan);
|
void filterScan(sensor_msgs::msg::LaserScan& scan);
|
||||||
@@ -268,6 +272,12 @@ class OBLidarNode {
|
|||||||
bool enable_cloud_accumulated_ = false;
|
bool enable_cloud_accumulated_ = false;
|
||||||
int cloud_accumulation_count_ = -1;
|
int cloud_accumulation_count_ = -1;
|
||||||
|
|
||||||
|
// Multi-frame publishing parameters
|
||||||
|
int publish_n_pkts_ = 1;
|
||||||
|
std::mutex frame_buffer_mutex_;
|
||||||
|
std::vector<std::shared_ptr<ob::FrameSet>> frame_buffer_;
|
||||||
|
rclcpp::Time last_frame_timestamp_;
|
||||||
|
|
||||||
// IMU
|
// IMU
|
||||||
bool enable_imu_ = false;
|
bool enable_imu_ = false;
|
||||||
std::string imu_rate_ = "50hz";
|
std::string imu_rate_ = "50hz";
|
||||||
|
|||||||
@@ -96,6 +96,11 @@ def generate_launch_description():
|
|||||||
default_value='20',
|
default_value='20',
|
||||||
description='LiDAR scan/publish rate in Hz. Supported range depends on device model.'
|
description='LiDAR scan/publish rate in Hz. Supported range depends on device model.'
|
||||||
),
|
),
|
||||||
|
DeclareLaunchArgument(
|
||||||
|
'publish_n_pkts',
|
||||||
|
default_value='1',
|
||||||
|
description='Number of frames to accumulate before publishing. Range: 1-12000. Used for multi-frame data merging.'
|
||||||
|
),
|
||||||
DeclareLaunchArgument(
|
DeclareLaunchArgument(
|
||||||
'enable_scan_to_point',
|
'enable_scan_to_point',
|
||||||
default_value='false',
|
default_value='false',
|
||||||
|
|||||||
@@ -166,6 +166,28 @@ void OBLidarNode::getParameters() {
|
|||||||
setAndGetNodeParameter<double>(liner_accel_cov_, "linear_accel_cov", 0.0003);
|
setAndGetNodeParameter<double>(liner_accel_cov_, "linear_accel_cov", 0.0003);
|
||||||
setAndGetNodeParameter<double>(angular_vel_cov_, "angular_vel_cov", 0.02);
|
setAndGetNodeParameter<double>(angular_vel_cov_, "angular_vel_cov", 0.02);
|
||||||
|
|
||||||
|
// Multi-frame publishing parameter - only for LIDAR_POINT and LIDAR_SPHERE_POINT formats
|
||||||
|
bool use_multi_frame = false;
|
||||||
|
for (auto stream_index : LIDAR_STREAMS) {
|
||||||
|
if (format_[stream_index] == OB_FORMAT_LIDAR_POINT || format_[stream_index] == OB_FORMAT_LIDAR_SPHERE_POINT) {
|
||||||
|
use_multi_frame = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_multi_frame) {
|
||||||
|
setAndGetNodeParameter<int>(publish_n_pkts_, "publish_n_pkts", 1);
|
||||||
|
if (publish_n_pkts_ < 1 || publish_n_pkts_ > 12000) {
|
||||||
|
RCLCPP_WARN_STREAM(logger_, "publish_n_pkts value " << publish_n_pkts_
|
||||||
|
<< " is out of range [1, 12000], setting to 1");
|
||||||
|
publish_n_pkts_ = 1;
|
||||||
|
}
|
||||||
|
RCLCPP_INFO_STREAM(logger_, "Multi-frame publishing enabled: " << publish_n_pkts_ << " frames will be merged");
|
||||||
|
} else {
|
||||||
|
publish_n_pkts_ = 1;
|
||||||
|
RCLCPP_INFO_STREAM(logger_, "Multi-frame publishing disabled for current lidar format");
|
||||||
|
}
|
||||||
|
|
||||||
// Setup IMU streams if enabled
|
// Setup IMU streams if enabled
|
||||||
if (enable_imu_) {
|
if (enable_imu_) {
|
||||||
enable_stream_[ACCEL] = true;
|
enable_stream_[ACCEL] = true;
|
||||||
@@ -619,14 +641,29 @@ void OBLidarNode::onNewFrameSetCallback(std::shared_ptr<ob::FrameSet> frame_set)
|
|||||||
publishStaticTransforms();
|
publishStaticTransforms();
|
||||||
tf_published_ = true;
|
tf_published_ = true;
|
||||||
}
|
}
|
||||||
if (format_[LIDAR] == OB_FORMAT_LIDAR_SCAN && !enable_scan_to_point_) {
|
|
||||||
publishScan(frame_set);
|
// Handle multi-frame publishing for LIDAR_POINT and LIDAR_SPHERE_POINT formats
|
||||||
} else if (format_[LIDAR] == OB_FORMAT_LIDAR_SCAN && enable_scan_to_point_) {
|
if ((format_[LIDAR] == OB_FORMAT_LIDAR_POINT || format_[LIDAR] == OB_FORMAT_LIDAR_SPHERE_POINT)) {
|
||||||
publishScanToPoint(frame_set);
|
std::lock_guard<std::mutex> lock(frame_buffer_mutex_);
|
||||||
} else if (format_[LIDAR] == OB_FORMAT_LIDAR_POINT) {
|
frame_buffer_.push_back(frame_set);
|
||||||
publishPointCloud(frame_set);
|
|
||||||
} else if (format_[LIDAR] == OB_FORMAT_LIDAR_SPHERE_POINT) {
|
// If we have enough frames, publish merged point cloud
|
||||||
publishSpherePointCloud(frame_set);
|
if (frame_buffer_.size() >= static_cast<size_t>(publish_n_pkts_)) {
|
||||||
|
if (format_[LIDAR] == OB_FORMAT_LIDAR_POINT) {
|
||||||
|
publishMergedPointCloud();
|
||||||
|
} else if (format_[LIDAR] == OB_FORMAT_LIDAR_SPHERE_POINT) {
|
||||||
|
publishMergedSpherePointCloud();
|
||||||
|
}
|
||||||
|
frame_buffer_.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Original single frame publishing logic
|
||||||
|
if (format_[LIDAR] == OB_FORMAT_LIDAR_SCAN && !enable_scan_to_point_) {
|
||||||
|
publishScan(frame_set);
|
||||||
|
} else if (format_[LIDAR] == OB_FORMAT_LIDAR_SCAN && enable_scan_to_point_) {
|
||||||
|
publishScanToPoint(frame_set);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (const ob::Error &e) {
|
} catch (const ob::Error &e) {
|
||||||
RCLCPP_ERROR_STREAM(logger_, "onNewFrameSetCallback error: " << e.getMessage());
|
RCLCPP_ERROR_STREAM(logger_, "onNewFrameSetCallback error: " << e.getMessage());
|
||||||
@@ -805,6 +842,181 @@ void OBLidarNode::publishSpherePointCloud(std::shared_ptr<ob::FrameSet> frame_se
|
|||||||
point_cloud_pub_->publish(std::move(point_cloud_msg));
|
point_cloud_pub_->publish(std::move(point_cloud_msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OBLidarNode::publishMergedPointCloud() {
|
||||||
|
if (frame_buffer_.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate total point count across all frames
|
||||||
|
size_t total_point_count = 0;
|
||||||
|
std::vector<std::pair<OBLiDARPoint*, size_t>> frame_data;
|
||||||
|
std::vector<uint64_t> frame_timestamps;
|
||||||
|
|
||||||
|
for (const auto& fs : frame_buffer_) {
|
||||||
|
auto lidar_frame = fs->getFrame(OB_FRAME_LIDAR_POINTS);
|
||||||
|
if (lidar_frame) {
|
||||||
|
auto* point_data = reinterpret_cast<OBLiDARPoint*>(lidar_frame->getData());
|
||||||
|
auto point_count = lidar_frame->getDataSize() / sizeof(OBLiDARPoint);
|
||||||
|
frame_data.emplace_back(point_data, point_count);
|
||||||
|
frame_timestamps.push_back(getFrameTimestampUs(lidar_frame));
|
||||||
|
total_point_count += point_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total_point_count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create merged point cloud message with offset_time field
|
||||||
|
auto point_cloud_msg = std::make_unique<sensor_msgs::msg::PointCloud2>();
|
||||||
|
sensor_msgs::PointCloud2Modifier modifier(*point_cloud_msg);
|
||||||
|
modifier.setPointCloud2Fields(6,
|
||||||
|
"x", 1, sensor_msgs::msg::PointField::FLOAT32,
|
||||||
|
"y", 1, sensor_msgs::msg::PointField::FLOAT32,
|
||||||
|
"z", 1, sensor_msgs::msg::PointField::FLOAT32,
|
||||||
|
"intensity", 1, sensor_msgs::msg::PointField::UINT8,
|
||||||
|
"tag", 1, sensor_msgs::msg::PointField::UINT8,
|
||||||
|
"offset_time", 1, sensor_msgs::msg::PointField::UINT32);
|
||||||
|
modifier.resize(total_point_count);
|
||||||
|
|
||||||
|
// Use the timestamp of the latest frame as the header timestamp
|
||||||
|
auto timestamp = fromUsToROSTime(frame_timestamps.front());
|
||||||
|
point_cloud_msg->header.stamp = timestamp;
|
||||||
|
point_cloud_msg->header.frame_id = frame_id_[LIDAR];
|
||||||
|
point_cloud_msg->height = 1;
|
||||||
|
point_cloud_msg->width = total_point_count;
|
||||||
|
point_cloud_msg->is_dense = true;
|
||||||
|
point_cloud_msg->is_bigendian = false;
|
||||||
|
point_cloud_msg->row_step = point_cloud_msg->width * point_cloud_msg->point_step;
|
||||||
|
point_cloud_msg->data.resize(point_cloud_msg->height * point_cloud_msg->row_step);
|
||||||
|
|
||||||
|
// Create iterators
|
||||||
|
sensor_msgs::PointCloud2Iterator<float> iter_x(*point_cloud_msg, "x");
|
||||||
|
sensor_msgs::PointCloud2Iterator<float> iter_y(*point_cloud_msg, "y");
|
||||||
|
sensor_msgs::PointCloud2Iterator<float> iter_z(*point_cloud_msg, "z");
|
||||||
|
sensor_msgs::PointCloud2Iterator<uint8_t> iter_intensity(*point_cloud_msg, "intensity");
|
||||||
|
sensor_msgs::PointCloud2Iterator<uint8_t> iter_tag(*point_cloud_msg, "tag");
|
||||||
|
sensor_msgs::PointCloud2Iterator<uint32_t> iter_offset_time(*point_cloud_msg, "offset_time");
|
||||||
|
|
||||||
|
// Calculate frame time interval based on lidar rate
|
||||||
|
double frame_interval_us = 1000000.0 / static_cast<double>(rate_int_[LIDAR]);
|
||||||
|
|
||||||
|
// Merge all frames with per-point timestamps
|
||||||
|
for (size_t frame_idx = 0; frame_idx < frame_data.size(); ++frame_idx) {
|
||||||
|
auto [point_data, point_count] = frame_data[frame_idx];
|
||||||
|
uint64_t frame_timestamp_us = frame_timestamps[frame_idx];
|
||||||
|
|
||||||
|
// Calculate time increment per point within this frame (uniform sampling)
|
||||||
|
double point_time_increment_us = frame_interval_us / static_cast<double>(point_count);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < point_count;
|
||||||
|
++i, ++iter_x, ++iter_y, ++iter_z, ++iter_intensity, ++iter_tag, ++iter_offset_time) {
|
||||||
|
*iter_x = static_cast<float>(point_data[i].x / 1000.0);
|
||||||
|
*iter_y = static_cast<float>(point_data[i].y / -1000.0);
|
||||||
|
*iter_z = static_cast<float>(point_data[i].z / 1000.0);
|
||||||
|
*iter_intensity = point_data[i].intensity;
|
||||||
|
*iter_tag = point_data[i].tag;
|
||||||
|
|
||||||
|
// Calculate per-point offset time in nanoseconds relative to point cloud header timestamp
|
||||||
|
double point_timestamp_us = static_cast<double>(frame_timestamp_us) + (i * point_time_increment_us);
|
||||||
|
uint64_t header_timestamp_us = frame_timestamps[0]; // First frame timestamp
|
||||||
|
*iter_offset_time = static_cast<uint32_t>((point_timestamp_us - static_cast<double>(header_timestamp_us)) * 1000.0); // Convert to nanoseconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*point_cloud_msg = filterPointCloud(*point_cloud_msg);
|
||||||
|
point_cloud_pub_->publish(std::move(point_cloud_msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OBLidarNode::publishMergedSpherePointCloud() {
|
||||||
|
if (frame_buffer_.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate total point count across all frames
|
||||||
|
size_t total_point_count = 0;
|
||||||
|
std::vector<std::pair<OBLiDARSpherePoint*, size_t>> frame_data;
|
||||||
|
std::vector<uint64_t> frame_timestamps;
|
||||||
|
|
||||||
|
for (const auto& fs : frame_buffer_) {
|
||||||
|
auto lidar_frame = fs->getFrame(OB_FRAME_LIDAR_POINTS);
|
||||||
|
if (lidar_frame) {
|
||||||
|
auto* point_data = reinterpret_cast<OBLiDARSpherePoint*>(lidar_frame->getData());
|
||||||
|
auto point_count = lidar_frame->getDataSize() / sizeof(OBLiDARSpherePoint);
|
||||||
|
frame_data.emplace_back(point_data, point_count);
|
||||||
|
frame_timestamps.push_back(getFrameTimestampUs(lidar_frame));
|
||||||
|
total_point_count += point_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total_point_count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create merged point cloud message with timestamp field
|
||||||
|
auto point_cloud_msg = std::make_unique<sensor_msgs::msg::PointCloud2>();
|
||||||
|
sensor_msgs::PointCloud2Modifier modifier(*point_cloud_msg);
|
||||||
|
modifier.setPointCloud2Fields(6,
|
||||||
|
"x", 1, sensor_msgs::msg::PointField::FLOAT32,
|
||||||
|
"y", 1, sensor_msgs::msg::PointField::FLOAT32,
|
||||||
|
"z", 1, sensor_msgs::msg::PointField::FLOAT32,
|
||||||
|
"intensity", 1, sensor_msgs::msg::PointField::UINT8,
|
||||||
|
"tag", 1, sensor_msgs::msg::PointField::UINT8,
|
||||||
|
"offset_time", 1, sensor_msgs::msg::PointField::UINT32);
|
||||||
|
modifier.resize(total_point_count);
|
||||||
|
|
||||||
|
// Use the timestamp of the latest frame as the header timestamp
|
||||||
|
auto timestamp = fromUsToROSTime(frame_timestamps.front());
|
||||||
|
point_cloud_msg->header.stamp = timestamp;
|
||||||
|
point_cloud_msg->header.frame_id = frame_id_[LIDAR];
|
||||||
|
point_cloud_msg->height = 1;
|
||||||
|
point_cloud_msg->width = total_point_count;
|
||||||
|
point_cloud_msg->is_dense = true;
|
||||||
|
point_cloud_msg->is_bigendian = false;
|
||||||
|
point_cloud_msg->row_step = point_cloud_msg->width * point_cloud_msg->point_step;
|
||||||
|
point_cloud_msg->data.resize(point_cloud_msg->height * point_cloud_msg->row_step);
|
||||||
|
|
||||||
|
// Create iterators
|
||||||
|
sensor_msgs::PointCloud2Iterator<float> iter_x(*point_cloud_msg, "x");
|
||||||
|
sensor_msgs::PointCloud2Iterator<float> iter_y(*point_cloud_msg, "y");
|
||||||
|
sensor_msgs::PointCloud2Iterator<float> iter_z(*point_cloud_msg, "z");
|
||||||
|
sensor_msgs::PointCloud2Iterator<uint8_t> iter_intensity(*point_cloud_msg, "intensity");
|
||||||
|
sensor_msgs::PointCloud2Iterator<uint8_t> iter_tag(*point_cloud_msg, "tag");
|
||||||
|
sensor_msgs::PointCloud2Iterator<uint32_t> iter_offset_time(*point_cloud_msg, "offset_time");
|
||||||
|
|
||||||
|
// Calculate frame time interval based on lidar rate
|
||||||
|
double frame_interval_us = 1000000.0 / static_cast<double>(rate_int_[LIDAR]);
|
||||||
|
|
||||||
|
// Merge all frames with per-point timestamps
|
||||||
|
for (size_t frame_idx = 0; frame_idx < frame_data.size(); ++frame_idx) {
|
||||||
|
auto [sphere_point_data, point_count] = frame_data[frame_idx];
|
||||||
|
uint64_t frame_timestamp_us = frame_timestamps[frame_idx];
|
||||||
|
|
||||||
|
// Convert sphere points to cartesian points
|
||||||
|
auto result_point = spherePointToPoint(sphere_point_data, point_count);
|
||||||
|
|
||||||
|
// Calculate time increment per point within this frame (uniform sampling)
|
||||||
|
double point_time_increment_us = frame_interval_us / static_cast<double>(point_count);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < point_count;
|
||||||
|
++i, ++iter_x, ++iter_y, ++iter_z, ++iter_intensity, ++iter_tag, ++iter_offset_time) {
|
||||||
|
*iter_x = static_cast<float>(result_point[i].x / 1000.0);
|
||||||
|
*iter_y = static_cast<float>(result_point[i].y / -1000.0);
|
||||||
|
*iter_z = static_cast<float>(result_point[i].z / 1000.0);
|
||||||
|
*iter_intensity = result_point[i].intensity;
|
||||||
|
*iter_tag = result_point[i].tag;
|
||||||
|
|
||||||
|
// Calculate per-point offset time in nanoseconds relative to point cloud header timestamp
|
||||||
|
double point_timestamp_us = static_cast<double>(frame_timestamp_us) + (i * point_time_increment_us);
|
||||||
|
uint64_t header_timestamp_us = frame_timestamps[0]; // First frame timestamp
|
||||||
|
*iter_offset_time = static_cast<uint32_t>((point_timestamp_us - static_cast<double>(header_timestamp_us)) * 1000.0); // Convert to nanoseconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*point_cloud_msg = filterPointCloud(*point_cloud_msg);
|
||||||
|
point_cloud_pub_->publish(std::move(point_cloud_msg));
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t OBLidarNode::getFrameTimestampUs(const std::shared_ptr<ob::Frame> &frame) {
|
uint64_t OBLidarNode::getFrameTimestampUs(const std::shared_ptr<ob::Frame> &frame) {
|
||||||
if (frame == nullptr) {
|
if (frame == nullptr) {
|
||||||
RCLCPP_WARN(logger_, "getFrameTimestampUs: frame is nullptr, return 0");
|
RCLCPP_WARN(logger_, "getFrameTimestampUs: frame is nullptr, return 0");
|
||||||
|
|||||||
Reference in New Issue
Block a user