This commit is contained in:
gxt_kt 2024-07-03 22:12:30 +08:00
parent 8b714d86bc
commit 20b623596f
7 changed files with 815 additions and 162 deletions

4
launch/run.launch Normal file
View File

@ -0,0 +1,4 @@
<launch>
<node pkg="rviz" type="rviz" name="rviz" args="-d $(find guangpo_lidar)/rviz/guangpo.rviz"></node>
<node pkg="guangpo_lidar" type="guangpo_lidar_node" name="guangpo_lidar_node" output="screen" ></node>
</launch>

208
rviz/guangpo.rviz Normal file
View File

@ -0,0 +1,208 @@
Panels:
- Class: rviz/Displays
Help Height: 78
Name: Displays
Property Tree Widget:
Expanded:
- /Global Options1
- /Status1
- /MarkerArray1/Status1
- /PointCloud22
Splitter Ratio: 0.5
Tree Height: 257
- Class: rviz/Selection
Name: Selection
- Class: rviz/Tool Properties
Expanded:
- /2D Pose Estimate1
- /2D Nav Goal1
- /Publish Point1
Name: Tool Properties
Splitter Ratio: 0.5886790156364441
- Class: rviz/Views
Expanded:
- /Current View1
Name: Views
Splitter Ratio: 0.5
- Class: rviz/Time
Name: Time
SyncMode: 0
SyncSource: Image
Preferences:
PromptSaveOnExit: true
Toolbars:
toolButtonStyle: 2
Visualization Manager:
Class: ""
Displays:
- Alpha: 0.5
Cell Size: 1
Class: rviz/Grid
Color: 160; 160; 164
Enabled: true
Line Style:
Line Width: 0.029999999329447746
Value: Lines
Name: Grid
Normal Cell Count: 0
Offset:
X: 0
Y: 0
Z: 0
Plane: XY
Plane Cell Count: 10
Reference Frame: <Fixed Frame>
Value: true
- Class: rviz/Image
Enabled: true
Image Topic: /usb_cam/image_raw
Max Value: 1
Median window: 5
Min Value: 0
Name: Image
Normalize Range: true
Queue Size: 2
Transport Hint: raw
Unreliable: false
Value: true
- Alpha: 1
Class: rviz/Axes
Enabled: true
Length: 1
Name: Axes
Radius: 0.10000000149011612
Reference Frame: <Fixed Frame>
Show Trail: false
Value: true
- Class: rviz/MarkerArray
Enabled: true
Marker Topic: /obstacles_topic
Name: MarkerArray
Namespaces:
"": true
Queue Size: 100
Value: true
- Alpha: 1
Autocompute Intensity Bounds: true
Autocompute Value Bounds:
Max Value: 10
Min Value: -10
Value: true
Axis: Z
Channel Name: intensity
Class: rviz/PointCloud2
Color: 255; 255; 255
Color Transformer: Intensity
Decay Time: 0
Enabled: true
Invert Rainbow: false
Max Color: 255; 255; 255
Min Color: 0; 0; 0
Name: PointCloud2
Position Transformer: XYZ
Queue Size: 10
Selectable: true
Size (Pixels): 3
Size (m): 0.009999999776482582
Style: Flat Squares
Topic: /cloud_ground
Unreliable: false
Use Fixed Frame: true
Use rainbow: true
Value: true
- Alpha: 1
Autocompute Intensity Bounds: true
Autocompute Value Bounds:
Max Value: 2.202476739883423
Min Value: 0.08952760696411133
Value: true
Axis: Z
Channel Name: intensity
Class: rviz/PointCloud2
Color: 255; 255; 255
Color Transformer: Intensity
Decay Time: 0
Enabled: true
Invert Rainbow: false
Max Color: 255; 255; 255
Min Color: 0; 0; 0
Name: PointCloud2
Position Transformer: XYZ
Queue Size: 10
Selectable: true
Size (Pixels): 3
Size (m): 0.009999999776482582
Style: Flat Squares
Topic: /cloud_noground
Unreliable: false
Use Fixed Frame: true
Use rainbow: true
Value: true
Enabled: true
Global Options:
Background Color: 48; 48; 48
Default Light: true
Fixed Frame: world
Frame Rate: 30
Name: root
Tools:
- Class: rviz/Interact
Hide Inactive Objects: true
- Class: rviz/MoveCamera
- Class: rviz/Select
- Class: rviz/FocusCamera
- Class: rviz/Measure
- Class: rviz/SetInitialPose
Theta std deviation: 0.2617993950843811
Topic: /initialpose
X std deviation: 0.5
Y std deviation: 0.5
- Class: rviz/SetGoal
Topic: /move_base_simple/goal
- Class: rviz/PublishPoint
Single click: true
Topic: /clicked_point
Value: true
Views:
Current:
Class: rviz/Orbit
Distance: 19.902732849121094
Enable Stereo Rendering:
Stereo Eye Separation: 0.05999999865889549
Stereo Focal Distance: 1
Swap Stereo Eyes: false
Value: false
Field of View: 0.7853981852531433
Focal Point:
X: 0
Y: 0
Z: 0
Focal Shape Fixed Size: true
Focal Shape Size: 0.05000000074505806
Invert Z Axis: false
Name: Current View
Near Clip Distance: 0.009999999776482582
Pitch: 1.344796061515808
Target Frame: <Fixed Frame>
Yaw: 3.2617619037628174
Saved: ~
Window Geometry:
Displays:
collapsed: false
Height: 740
Hide Left Dock: false
Hide Right Dock: false
Image:
collapsed: false
QMainWindow State: 000000ff00000000fd00000004000000000000015600000245fc0200000009fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005d00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003e0000018c000000cb00fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d00610067006501000001d0000000b30000001600ffffff000000010000010f00000245fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003e00000245000000a500fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000005e80000003efc0100000002fb0000000800540069006d00650100000000000005e80000033700fffffffb0000000800540069006d00650100000000000004500000000000000000000003770000024500000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
Selection:
collapsed: false
Time:
collapsed: false
Tool Properties:
collapsed: false
Views:
collapsed: false
Width: 1512
X: 0
Y: 0

View File

@ -49,4 +49,4 @@ std::vector<PtCdtr<PointT>> ClusterPts<PointT>::EuclidCluster(PtCdtr<PointT> clo
}
}
return clusters;
}
}

View File

@ -126,17 +126,6 @@ void initCamera(CameraAngle setAngle, pcl::visualization::PCLVisualizer::Ptr &vi
viewer->addCoordinateSystem(1.0);
}
// 计算旋转矩阵
Eigen::Matrix4d TransforMatrix(Eigen::Vector3d translation,double roll,double pitch,double yaw) {
Eigen::Quaterniond q = Eigen::AngleAxisd(yaw, Eigen::Vector3d::UnitZ())
* Eigen::AngleAxisd(pitch, Eigen::Vector3d::UnitY())
* Eigen::AngleAxisd(roll, Eigen::Vector3d::UnitX());
Eigen::Matrix4d transformation_matrix = Eigen::Matrix4d::Identity(); // 初始化为单位矩阵
transformation_matrix.block<3, 3>(0, 0) = q.toRotationMatrix(); // 设置旋转矩阵部分
transformation_matrix.block<3, 1>(0, 3) = translation; // 设置平移向量部分
std::cout << "旋转矩阵:" << std::endl << transformation_matrix << std::endl;
return transformation_matrix;
}
// char* argv[] means array of char pointers, whereas char** argv means pointer to a char pointer.
int main(int argc, char **argv) {

View File

@ -1,11 +1,15 @@
#include <eigen3/Eigen/Core>
#include <eigen3/Eigen/Geometry>
#include <pcl/PCLPointCloud2.h>
#include <pcl/point_types.h>
#include <pcl_conversions/pcl_conversions.h>
#include <ros/ros.h>
#include <sensor_msgs/PointCloud2.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/point_types.h>
#include <pcl/PCLPointCloud2.h>
#include <visualization_msgs/Marker.h>
#include <visualization_msgs/MarkerArray.h>
#include "render/render.h"
#include "processPointClouds.h"
#include "render/render.h"
// using templates for processPointClouds so also include .cpp to help linker
#include "processPointClouds.cpp"
@ -15,55 +19,402 @@
using namespace lidar_obstacle_detection;
template <typename PointT = pcl::PointXYZI>
std::pair<PtCdtr<PointT>, PtCdtr<PointT>>
RansacSegmentPlane(PtCdtr<PointT> cloud, int maxIterations, float distanceTol) {
// 使用pcl的分割分离出地面
// Count time
auto startTime = std::chrono::steady_clock::now();
// Create the segmentation object
pcl::SACSegmentation<PointT> seg;
// Optional
seg.setOptimizeCoefficients(true);
seg.setModelType(pcl::SACMODEL_PLANE);
seg.setMethodType(pcl::SAC_RANSAC);
seg.setMaxIterations(maxIterations);
seg.setDistanceThreshold(distanceTol);
// Segment the largest planar component
// PtCdtr<PointT> cloud_plane(new pcl::PointCloud<PointT>());
// PtCdtr<PointT> cloud_out(new pcl::PointCloud<PointT>());
pcl::ModelCoefficients::Ptr cloud_out(new pcl::ModelCoefficients);
pcl::PointIndices::Ptr cloud_plane(new pcl::PointIndices);
seg.setInputCloud(cloud);
seg.segment(*cloud_plane, *cloud_out);
PtCdtr<PointT> in_plane(new pcl::PointCloud<PointT>());
PtCdtr<PointT> out_plane(new pcl::PointCloud<PointT>());
// Extract the inliers
pcl::ExtractIndices<PointT> extract;
extract.setInputCloud(cloud);
extract.setIndices(cloud_plane);
extract.setNegative(false);
extract.filter(*in_plane);
// Extract the outliers
extract.setNegative(true);
extract.filter(*out_plane);
auto endTime = std::chrono::steady_clock::now();
auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(
endTime - startTime);
std::cout << "plane ransac-segment took " << elapsedTime.count()
<< " milliseconds" << std::endl;
bool if_view_segment = yaml_config["view"]["segment"].as<bool>();
if (if_view_segment) {
// 创建可视化窗口
pcl::visualization::PCLVisualizer::Ptr viewer(
new pcl::visualization::PCLVisualizer("RANSAC Plane Segmentation"));
viewer->setWindowName("My Plane Segmentation Viewer");
viewer->setBackgroundColor(0, 0, 0);
// 添加坐标系
viewer->addCoordinateSystem(1.0);
// 添加栅格
for (float x = -10.0; x <= 10.0; x += 1.0) {
viewer->addLine(pcl::PointXYZ(x, -10, 0), pcl::PointXYZ(x, 10, 0), 0.5,
0.5, 0.5, std::string("grid_") + std::to_string(x) + "y");
}
for (float y = -10.0; y <= 10.0; y += 1.0) {
viewer->addLine(pcl::PointXYZ(-10, y, 0), pcl::PointXYZ(10, y, 0), 0.5,
0.5, 0.5, std::string("grid_") + std::to_string(y) + "x");
}
// 可视化地面点云
pcl::visualization::PointCloudColorHandlerCustom<PointT> plane_color(
in_plane, 255, 0, 0);
viewer->addPointCloud<PointT>(in_plane, plane_color, "plane");
viewer->setPointCloudRenderingProperties(
pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "plane");
// 可视化非地面点云
pcl::visualization::PointCloudColorHandlerCustom<PointT> non_plane_color(
out_plane, 0, 255, 0);
viewer->addPointCloud<PointT>(out_plane, non_plane_color, "non_plane");
viewer->setPointCloudRenderingProperties(
pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "non_plane");
// 显示可视化窗口
while (!viewer->wasStopped()) {
viewer->spinOnce();
}
}
return std::make_pair(out_plane, in_plane);
}
template <typename PointT = pcl::PointXYZI>
pcl::PointCloud<pcl::PointXYZI>::Ptr
FilterCloud(const pcl::PointCloud<pcl::PointXYZI>::Ptr &cloud, float filterRes,
const Eigen::Vector4f &minPoint, const Eigen::Vector4f &maxPoint) {
// Time segmentation process
auto startTime = std::chrono::steady_clock::now();
// TODO:: Fill in the function to do voxel grid point reduction and region
// based filtering Create the filtering object: downsample the dataset using a
// leaf size of .2m 体素降采样
pcl::VoxelGrid<PointT> vg;
PtCdtr<PointT> cloudFiltered(new pcl::PointCloud<PointT>);
vg.setInputCloud(cloud);
vg.setLeafSize(filterRes, filterRes, filterRes);
vg.filter(*cloudFiltered);
// 设置roi区域
PtCdtr<PointT> cloudRegion(new pcl::PointCloud<PointT>);
pcl::CropBox<PointT> region(true);
region.setMin(minPoint);
region.setMax(maxPoint);
region.setInputCloud(cloudFiltered);
region.filter(*cloudRegion);
// 去除屋顶点云
std::vector<int> indices;
pcl::CropBox<PointT> roof(true);
// roof.setMin(Eigen::Vector4f(-1.5, -1.7, -1, 1));
// roof.setMax(Eigen::Vector4f(2.6, 1.7, -0.4, 1));
double max_x = yaml_config["roof"]["max_x"].as<double>();
double max_y = yaml_config["roof"]["max_y"].as<double>();
double max_z = yaml_config["roof"]["max_z"].as<double>();
double min_x = yaml_config["roof"]["min_x"].as<double>();
double min_y = yaml_config["roof"]["min_y"].as<double>();
double min_z = yaml_config["roof"]["min_z"].as<double>();
roof.setMin(Eigen::Vector4f(min_x, min_y, min_z, 1));
roof.setMax(Eigen::Vector4f(max_x, max_y, max_z, 1));
roof.setInputCloud(cloudRegion);
roof.filter(indices);
pcl::PointIndices::Ptr inliers{new pcl::PointIndices};
for (int point : indices) {
inliers->indices.push_back(point);
}
pcl::ExtractIndices<PointT> extract;
extract.setInputCloud(cloudRegion);
extract.setIndices(inliers);
extract.setNegative(true);
extract.filter(*cloudRegion);
auto endTime = std::chrono::steady_clock::now();
auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(
endTime - startTime);
std::cout << "filtering took " << elapsedTime.count() << " milliseconds"
<< std::endl;
// return cloud;
return cloudRegion;
}
class PCLSubscriber {
public:
PCLSubscriber(ros::NodeHandle& nh) {
std::string sub_topic=yaml_config["sub_cloud_topic"].as<std::string>();
std::cout << "订阅点云话题" << sub_topic << std::endl;
std::string pub_topic=yaml_config["pub_cloud_topic"].as<std::string>();
std::cout << "发布点云话题" << pub_topic << std::endl;
sub_ = nh.subscribe<sensor_msgs::PointCloud2>(sub_topic, 10, &PCLSubscriber::pointCloudCallback, this);
pub_ = nh.advertise<sensor_msgs::PointCloud2>(pub_topic, 1);
}
PCLSubscriber(ros::NodeHandle &nh) {
std::string sub_topic = yaml_config["sub_cloud_topic"].as<std::string>();
std::cout << "订阅点云话题" << sub_topic << std::endl;
std::string pub_cloud_ground_topic =
yaml_config["pub_cloud_ground_topic"].as<std::string>();
std::cout << "发布地面点云话题" << pub_cloud_ground_topic << std::endl;
std::string pub_cloud_noground_topic =
yaml_config["pub_cloud_noground_topic"].as<std::string>();
std::cout << "发布非地面点云话题" << pub_cloud_ground_topic << std::endl;
std::string markder_pub_topic =
yaml_config["obstacles_topic"].as<std::string>();
std::cout << "发布障碍物可视化话题" << markder_pub_topic << std::endl;
sub_ = nh.subscribe<sensor_msgs::PointCloud2>(
sub_topic, 10, &PCLSubscriber::pointCloudCallback, this);
pub_cloud_ground_ =
nh.advertise<sensor_msgs::PointCloud2>(pub_cloud_ground_topic, 10);
pub_cloud_noground_ =
nh.advertise<sensor_msgs::PointCloud2>(pub_cloud_noground_topic, 10);
marker_pub_ =
nh.advertise<visualization_msgs::MarkerArray>(markder_pub_topic, 10);
void pointCloudCallback(const sensor_msgs::PointCloud2ConstPtr& msg) {
pcl::PCLPointCloud2 pcl_pc2;
pcl_conversions::toPCL(*msg, pcl_pc2);
// 初始化坐标系变换的旋转矩阵
Eigen::Vector3d trans;
trans[0] = yaml_config["convert"]["transform"]["x"].as<double>();
trans[1] = yaml_config["convert"]["transform"]["y"].as<double>();
trans[2] = yaml_config["convert"]["transform"]["z"].as<double>();
std::cout << "trans x=" << trans[0] << std::endl;
std::cout << "trans y=" << trans[1] << std::endl;
std::cout << "trans z=" << trans[2] << std::endl;
// trans<<0.3643,0.2078,1.21;
double roll = yaml_config["convert"]["rotation"]["roll"].as<double>();
double pitch = yaml_config["convert"]["rotation"]["pitch"].as<double>();
double yaw = yaml_config["convert"]["rotation"]["yaw"].as<double>();
std::cout << "roll=" << roll << std::endl;
std::cout << "pitch=" << pitch << std::endl;
std::cout << "yaw=" << yaw << std::endl;
Eigen::Matrix4d tran_matrix = TransforMatrix(
trans, roll * M_PI / 180.0, pitch * M_PI / 180.0, yaw * M_PI / 180.0);
Eigen::Affine3d affine3d_transform(tran_matrix); // 转换为Affine3d类型
affine3f_transform = affine3d_transform.cast<float>(); // 转换为Affine3f类型
affine3f_transform = affine3f_transform.inverse();
}
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZI>);
pcl::fromPCLPointCloud2(pcl_pc2, *cloud);
void pointCloudCallback(const sensor_msgs::PointCloud2ConstPtr &msg) {
pcl::PCLPointCloud2 pcl_pc2;
pcl_conversions::toPCL(*msg, pcl_pc2);
processPointCloud(cloud);
publishCloud(cloud);
}
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZI>);
pcl::fromPCLPointCloud2(pcl_pc2, *cloud);
processPointCloud(cloud);
}
private:
void processPointCloud(const pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud) {
// 在这里添加对点云数据的处理逻辑
ROS_INFO("收到包含 %lu 个点的点云数据", cloud->size());
void processPointCloud(const pcl::PointCloud<pcl::PointXYZI>::Ptr &cloud) {
// 在这里添加对点云数据的处理逻辑
ROS_INFO("收到包含 %lu 个点的点云数据", cloud->size());
// 将点云进行转换
pcl::transformPointCloud(*cloud, *cloud, affine3f_transform);
auto startTime = std::chrono::steady_clock::now();
// 对点云进行处理
DealWithCloud(cloud);
auto endTime = std::chrono::steady_clock::now();
auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(
endTime - startTime);
std::cout << "All operators took " << elapsedTime.count()
<< " milliseconds" << std::endl;
}
// Test read Lidar data
void DealWithCloud(pcl::PointCloud<pcl::PointXYZI>::Ptr inputCloud) {
// ----------------------------------------------------
// -----Open 3D viewer and display City Block -----
// ----------------------------------------------------
// Setting hyper parameters
// FilterCloud
// float filterRes = 0.4;
float filterRes = yaml_config["filterRes"].as<float>();
// Eigen::Vector4f minpoint(-10, -6.5, -2, 1);
// Eigen::Vector4f maxpoint(30, 6.5, 1, 1);
double max_x = yaml_config["roi"]["max_x"].as<double>();
double max_y = yaml_config["roi"]["max_y"].as<double>();
double max_z = yaml_config["roi"]["max_z"].as<double>();
double min_x = yaml_config["roi"]["min_x"].as<double>();
double min_y = yaml_config["roi"]["min_y"].as<double>();
double min_z = yaml_config["roi"]["min_z"].as<double>();
Eigen::Vector4f maxpoint(max_x, max_y, max_z, 1);
Eigen::Vector4f minpoint(min_x, min_y, min_z, 1);
// SegmentPlane
// int maxIterations = 40;
int maxIterations = yaml_config["ransac"]["maxIterations"].as<int>();
// float distanceThreshold = 0.3;
float distanceThreshold =
yaml_config["ransac"]["distanceThreshold"].as<float>();
// 聚类参数设置
// Clustering
// float clusterTolerance = 0.5;
// int minsize = 10;
// int maxsize = 140;
float clusterTolerance =
yaml_config["cluster"]["clusterTolerance"].as<float>();
int minsize = yaml_config["cluster"]["minsize"].as<int>();
int maxsize = yaml_config["cluster"]["maxsize"].as<int>();
// 1. 降采样+设置roi区域+去除车辆相关点云
// First:Filter cloud to reduce amount of points
pcl::PointCloud<pcl::PointXYZI>::Ptr filteredCloud =
FilterCloud(inputCloud, filterRes, minpoint, maxpoint);
// 2. 把点云分离出路面
// Second: Segment the filtered cloud into obstacles and road
std::pair<pcl::PointCloud<pcl::PointXYZI>::Ptr,
pcl::PointCloud<pcl::PointXYZI>::Ptr>
segmentCloud =
RansacSegmentPlane(filteredCloud, maxIterations, distanceThreshold);
// 发布点云
ROS_INFO("发布点云cloud");
PublishGroundCloud(segmentCloud.second);
PublishNoGroundCloud(segmentCloud.first);
// renderPointCloud(viewer, segmentCloud.first, "obstCloud", Color(1, 0,
// 0));
// renderPointCloud(viewer, segmentCloud.second, "planeCloud", Color(0, 1,
// 0));
// renderPointCloud(viewer,inputCloud,"inputCloud");
// Third: Cluster different obstacle cloud
// std::vector<pcl::PointCloud<pcl::PointXYZI>::Ptr> cloudClusters =
// pointProcessorI->EuclideanClustering(segmentCloud.first,
// clusterTolerance, minsize, maxsize); 提取出障碍物的点云
std::vector<pcl::PointCloud<pcl::PointXYZI>::Ptr> cloudClusters =
GxtEuclideanClustering(segmentCloud.first, clusterTolerance, minsize,
maxsize);
std::cout << "begin ExtractObstacles" << std::endl;
std::vector<Eigen::Vector3f> centroids;
std::vector<Eigen::Vector3f> sizes;
std::vector<Eigen::Quaternionf> orientations;
bool enable_verbose = yaml_config["log"]["enable_obstacles"].as<bool>();
// 根据障碍物点云提取出框
ExtractObstacles(cloudClusters, centroids, sizes, orientations,
enable_verbose);
// visualizeObstacles(cloudClusters, centroids, sizes, orientations);
// int clusterId = 0;
// std::vector<Color> colors = {Color(1, 0, 0), Color(0, 1, 0), Color(0, 0,
// 1)};
// for (pcl::PointCloud<pcl::PointXYZI>::Ptr cluster : cloudClusters) {
//
// std::cout << "cluster size";
// pointProcessorI->numPoints(cluster);
// renderPointCloud(viewer, cluster, "obstCLoud" +
// std::to_string(clusterId),
// colors[clusterId % colors.size()]);
// // Fourth: Find bounding boxes for each obstacle cluster
// Box box = pointProcessorI->BoundingBox(cluster);
// renderBox(viewer, box, clusterId);
// ++clusterId;
// }
PublishObstacles(centroids, sizes, orientations);
}
void PublishGroundCloud(const pcl::PointCloud<pcl::PointXYZI>::Ptr &cloud) {
// 将 pcl::PointCloud 转换为 sensor_msgs::PointCloud2
sensor_msgs::PointCloud2 msg;
pcl::toROSMsg(*cloud, msg);
msg.header.frame_id = "world";
msg.header.stamp = ros::Time::now();
pub_cloud_ground_.publish(msg);
}
void PublishNoGroundCloud(const pcl::PointCloud<pcl::PointXYZI>::Ptr &cloud) {
// 将 pcl::PointCloud 转换为 sensor_msgs::PointCloud2
sensor_msgs::PointCloud2 msg;
pcl::toROSMsg(*cloud, msg);
msg.header.frame_id = "world";
msg.header.stamp = ros::Time::now();
pub_cloud_noground_.publish(msg);
}
void PublishObstacles(
const std::vector<Eigen::Vector3f> &obstacle_centroids,
const std::vector<Eigen::Vector3f> &obstacle_sizes,
const std::vector<Eigen::Quaternionf> &obstacle_orientations) {
visualization_msgs::MarkerArray marker_array;
// 首先发布一个DELETEALL命令,删除上次发布的所有障碍物标记
visualization_msgs::Marker delete_marker;
delete_marker.header.frame_id = "world";
delete_marker.action = visualization_msgs::Marker::DELETEALL;
marker_array.markers.push_back(delete_marker);
marker_pub_.publish(marker_array);
marker_array.markers.clear(); // 清空marker_array
for (size_t i = 0; i < obstacle_centroids.size(); ++i) {
visualization_msgs::Marker marker;
marker.header.frame_id = "world";
marker.type = visualization_msgs::Marker::CUBE;
marker.action = visualization_msgs::Marker::ADD;
marker.id = i;
marker.pose.position.x = obstacle_centroids[i].x();
marker.pose.position.y = obstacle_centroids[i].y();
marker.pose.position.z = obstacle_centroids[i].z();
marker.pose.orientation.x = obstacle_orientations[i].x();
marker.pose.orientation.y = obstacle_orientations[i].y();
marker.pose.orientation.z = obstacle_orientations[i].z();
marker.pose.orientation.w = obstacle_orientations[i].w();
marker.scale.x = obstacle_sizes[i].x();
marker.scale.y = obstacle_sizes[i].y();
marker.scale.z = obstacle_sizes[i].z();
marker.color.r = 1.0f;
marker.color.g = 0.0f;
marker.color.b = 0.0f;
marker.color.a = 0.3;
marker_array.markers.push_back(marker);
}
void publishCloud(const pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud) {
// 将 pcl::PointCloud 转换为 sensor_msgs::PointCloud2
sensor_msgs::PointCloud2 msg;
pcl::toROSMsg(*cloud, msg);
msg.header.frame_id = "world";
msg.header.stamp = ros::Time::now();
marker_pub_.publish(marker_array);
}
ros::Publisher marker_pub_;
pub_.publish(msg);
}
ros::Subscriber sub_;
ros::Publisher pub_cloud_noground_;
ros::Publisher pub_cloud_ground_;
ros::Subscriber sub_;
ros::Publisher pub_;
// 激光雷达到车体坐标系的变换
Eigen::Affine3f affine3f_transform;
};
int main(int argc, char** argv) {
ros::init(argc, argv, "pcl_subscriber");
ros::NodeHandle nh;
int main(int argc, char **argv) {
setlocale(LC_ALL, "");
ros::init(argc, argv, "pcl_subscriber");
ros::NodeHandle nh;
PCLSubscriber subscriber(nh);
PCLSubscriber subscriber(nh);
ros::spin();
return 0;
ros::spin();
return 0;
}

View File

@ -1,29 +1,27 @@
#pragma once
#include <pcl/point_types.h>
#include <pcl/common/transforms.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/point_types.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/common/transforms.h>
#include <pcl/common/pca.h>
#include <pcl/point_types.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/common/transforms.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/filters/filter.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/features/normal_3d.h>
#include <pcl/kdtree/kdtree.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/common/common.h>
#include <pcl/common/eigen.h>
#include <Eigen/Dense>
#include <iostream>
#include <pcl/common/common.h>
#include <pcl/common/eigen.h>
#include <pcl/common/pca.h>
#include <pcl/common/transforms.h>
#include <pcl/features/normal_3d.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/filters/filter.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/kdtree/kdtree.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <vector>
#include <pcl/features/moment_of_inertia_estimation.h>
@ -31,7 +29,81 @@
#include <pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h>
// reference https://pointclouds.org/documentation/tutorials/moment_of_inertia.html
/**
* 使
* @param input_cloud
* @param cluster_tolerance (:)
* @param min_cluster_size
* @param max_cluster_size
* @param output_clouds
*/
template <typename PointT = pcl::PointXYZI>
std::vector<typename pcl::PointCloud<PointT>::Ptr>
GxtEuclideanClustering(typename pcl::PointCloud<PointT>::Ptr input_cloud,
float cluster_tolerance, int min_cluster_size,
int max_cluster_size) {
auto startTime = std::chrono::steady_clock::now();
// 创建欧式聚类对象
pcl::EuclideanClusterExtraction<PointT> ec;
ec.setClusterTolerance(cluster_tolerance);
ec.setMinClusterSize(min_cluster_size);
ec.setMaxClusterSize(max_cluster_size);
ec.setSearchMethod(pcl::search::KdTree<pcl::PointXYZI>::Ptr(
new pcl::search::KdTree<PointT>));
// 提取聚类
std::vector<pcl::PointIndices> cluster_indices;
ec.setInputCloud(input_cloud);
ec.extract(cluster_indices);
std::vector<typename pcl::PointCloud<PointT>::Ptr> output_clouds;
// 生成聚类结果点云
output_clouds.clear();
for (const auto &indices : cluster_indices) {
typename pcl::PointCloud<PointT>::Ptr cluster(new pcl::PointCloud<PointT>);
for (int index : indices.indices) {
cluster->push_back(input_cloud->at(index));
}
output_clouds.push_back(cluster);
}
auto endTime = std::chrono::steady_clock::now();
auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(
endTime - startTime);
std::cout << "euclidean clustering took " << elapsedTime.count() << " milliseconds"
<< std::endl;
if (false) {
// 可视化聚类结果
pcl::visualization::PCLVisualizer viewer("Euclidean Clustering");
viewer.setWindowName("My Plane Segmentation Viewer");
viewer.setBackgroundColor(0, 0, 0);
int j = 0;
for (const auto &indices : cluster_indices) {
pcl::PointCloud<pcl::PointXYZI>::Ptr cluster(
new pcl::PointCloud<pcl::PointXYZI>);
for (int index : indices.indices) {
cluster->push_back(input_cloud->at(index));
}
viewer.addPointCloud<pcl::PointXYZI>(cluster,
"cluster_" + std::to_string(j++));
viewer.setPointCloudRenderingProperties(
pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2,
"cluster_" + std::to_string(j - 1));
viewer.setPointCloudRenderingProperties(
pcl::visualization::PCL_VISUALIZER_COLOR,
(float)rand() / (float)RAND_MAX, (float)rand() / (float)RAND_MAX,
(float)rand() / (float)RAND_MAX, "cluster_" + std::to_string(j - 1));
}
viewer.spin();
// // 显示可视化窗口
// while (!viewer.wasStopped()) {
// viewer.spinOnce();
// }
}
return output_clouds;
}
// reference
// https://pointclouds.org/documentation/tutorials/moment_of_inertia.html
/**
*
* @param obstacle_clouds
@ -39,28 +111,40 @@
* @param obstacle_sizes
* @param obstacle_orientations
*/
void ExtractObstacles(
std::vector<pcl::PointCloud<pcl::PointXYZI>::Ptr>& obstacle_clouds,
std::vector<Eigen::Vector3f>& obstacle_centroids,
std::vector<Eigen::Vector3f>& obstacle_sizes,
std::vector<Eigen::Quaternionf>& obstacle_orientations)
{
obstacle_centroids.clear();
obstacle_sizes.clear();
obstacle_orientations.clear();
for (const auto &obstacle_cloud : obstacle_clouds) {
pcl::MomentOfInertiaEstimation<pcl::PointXYZI> feature_extractor;
feature_extractor.setInputCloud(obstacle_cloud);
feature_extractor.compute();
inline void ExtractObstacles(
std::vector<pcl::PointCloud<pcl::PointXYZI>::Ptr> &obstacle_clouds,
std::vector<Eigen::Vector3f> &obstacle_centroids,
std::vector<Eigen::Vector3f> &obstacle_sizes,
std::vector<Eigen::Quaternionf> &obstacle_orientations,
bool enable_verbose = false) {
auto startTime = std::chrono::steady_clock::now();
obstacle_centroids.clear();
obstacle_sizes.clear();
obstacle_orientations.clear();
for (const auto &obstacle_cloud : obstacle_clouds) {
pcl::MomentOfInertiaEstimation<pcl::PointXYZI> feature_extractor;
feature_extractor.setInputCloud(obstacle_cloud);
feature_extractor.compute();
pcl::PointXYZI min_point_OBB;
pcl::PointXYZI max_point_OBB;
pcl::PointXYZI position_OBB;
Eigen::Matrix3f rotational_matrix_OBB;
pcl::PointXYZI min_point_OBB;
pcl::PointXYZI max_point_OBB;
pcl::PointXYZI position_OBB;
Eigen::Matrix3f rotational_matrix_OBB;
feature_extractor.getOBB(min_point_OBB, max_point_OBB, position_OBB,
rotational_matrix_OBB);
feature_extractor.getOBB(min_point_OBB, max_point_OBB, position_OBB,
rotational_matrix_OBB);
Eigen::Vector3f position(position_OBB.x, position_OBB.y, position_OBB.z);
Eigen::Quaternionf quat(rotational_matrix_OBB);
obstacle_centroids.push_back(position);
obstacle_orientations.push_back(quat);
Eigen::Vector3f size;
size << (max_point_OBB.x - min_point_OBB.x),
(max_point_OBB.y - min_point_OBB.y),
(max_point_OBB.z - min_point_OBB.z);
obstacle_sizes.push_back(size);
// 可视化障碍物框
if (false) {
pcl::visualization::PCLVisualizer::Ptr viewer(
new pcl::visualization::PCLVisualizer("3D Viewer"));
viewer->setBackgroundColor(0, 0, 0);
@ -68,90 +152,91 @@ void ExtractObstacles(
viewer->initCameraParameters();
viewer->addPointCloud<pcl::PointXYZI>(obstacle_cloud, "sample cloud");
Eigen::Vector3f position(position_OBB.x, position_OBB.y, position_OBB.z);
Eigen::Quaternionf quat(rotational_matrix_OBB);
// 添加可视化
// viewer->addCube(position, quat, max_point_OBB.x - min_point_OBB.x,
// max_point_OBB.y - min_point_OBB.y,
// max_point_OBB.z - min_point_OBB.z, "OBB");
// viewer->setShapeRenderingProperties(
// pcl::visualization::PCL_VISUALIZER_REPRESENTATION,
// pcl::visualization::PCL_VISUALIZER_REPRESENTATION_WIREFRAME, "OBB");
obstacle_centroids.push_back(position);
obstacle_orientations.push_back(quat);
Eigen::Vector3f size;
size << (max_point_OBB.x - min_point_OBB.x) ,(max_point_OBB.y - min_point_OBB.y),(max_point_OBB.z - min_point_OBB.z);
obstacle_sizes.push_back(size);
viewer->addCube(position, quat, max_point_OBB.x - min_point_OBB.x,
max_point_OBB.y - min_point_OBB.y,
max_point_OBB.z - min_point_OBB.z, "OBB");
viewer->setShapeRenderingProperties(
pcl::visualization::PCL_VISUALIZER_REPRESENTATION,
pcl::visualization::PCL_VISUALIZER_REPRESENTATION_WIREFRAME, "OBB");
}
}
auto endTime = std::chrono::steady_clock::now();
auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(
endTime - startTime);
std::cout << "extract obstacles took " << elapsedTime.count() << " milliseconds"
<< std::endl;
// debug
if(0) {
std::cout << obstacle_centroids.size();
for(int i=0;i < obstacle_centroids.size();i++) {
std::cout << "====" << std::endl;
std::cout << obstacle_centroids[i] << std::endl;
std::cout << obstacle_sizes[i] << std::endl;
// std::cout << obstacle_orientations[i] << std::endl;
}
// debug
if (enable_verbose) {
std::cout << obstacle_centroids.size();
for (int i = 0; i < obstacle_centroids.size(); i++) {
std::cout << "======obstacle[" << i << "]======" << std::endl;
std::cout << obstacle_centroids[i] << std::endl;
std::cout << obstacle_sizes[i] << std::endl;
std::cout << obstacle_orientations[i].matrix() << std::endl;
std::cout << "========================" << std::endl;
}
}
}
/**
*
* @param viewer PCL可视化器
* @param obstacle_clouds
* @param obstacle_centroids
* @param obstacle_sizes
* @param obstacle_orientations
*/
void visualizeObstacles(
const std::vector<pcl::PointCloud<pcl::PointXYZI>::Ptr>& cloudClusters,
const std::vector<Eigen::Vector3f>& obstacle_centroids,
const std::vector<Eigen::Vector3f>& obstacle_sizes,
const std::vector<Eigen::Quaternionf>& obstacle_orientations)
{
// 创建可视化窗口
std::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
viewer->setBackgroundColor(0, 0, 0);
inline void visualizeObstacles(
const std::vector<pcl::PointCloud<pcl::PointXYZI>::Ptr> &cloudClusters,
const std::vector<Eigen::Vector3f> &obstacle_centroids,
const std::vector<Eigen::Vector3f> &obstacle_sizes,
const std::vector<Eigen::Quaternionf> &obstacle_orientations) {
// 创建可视化窗口
std::shared_ptr<pcl::visualization::PCLVisualizer> viewer(
new pcl::visualization::PCLVisualizer("3D Viewer"));
viewer->setBackgroundColor(0, 0, 0);
// 绘制包围盒
for (size_t i = 0; i < obstacle_centroids.size(); i++)
{
std::stringstream cloud_name;
cloud_name << "cloud_" << i;
viewer->addPointCloud<pcl::PointXYZI>(cloudClusters[i], cloud_name.str());
std::stringstream box_name;
box_name << "box_" << i;
viewer->addCube(obstacle_centroids[i], obstacle_orientations[i], obstacle_sizes[i][0],
obstacle_sizes[i][1],
obstacle_sizes[i][2], box_name.str());
// 设置颜色
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR,
0.5,0,0, box_name.str());
viewer->setShapeRenderingProperties(
pcl::visualization::PCL_VISUALIZER_REPRESENTATION,
pcl::visualization::PCL_VISUALIZER_REPRESENTATION_WIREFRAME, box_name.str());
}
// 绘制包围盒
for (size_t i = 0; i < obstacle_centroids.size(); i++) {
// 启动可视化
while (!viewer->wasStopped()) {
viewer->spinOnce();
// std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
std::stringstream cloud_name;
cloud_name << "cloud_" << i;
viewer->addPointCloud<pcl::PointXYZI>(cloudClusters[i], cloud_name.str());
std::stringstream box_name;
box_name << "box_" << i;
viewer->addCube(obstacle_centroids[i], obstacle_orientations[i],
obstacle_sizes[i][0], obstacle_sizes[i][1],
obstacle_sizes[i][2], box_name.str());
// 设置颜色
viewer->setShapeRenderingProperties(
pcl::visualization::PCL_VISUALIZER_COLOR, 0.5, 0, 0, box_name.str());
viewer->setShapeRenderingProperties(
pcl::visualization::PCL_VISUALIZER_REPRESENTATION,
pcl::visualization::PCL_VISUALIZER_REPRESENTATION_WIREFRAME,
box_name.str());
}
// 启动可视化
while (!viewer->wasStopped()) {
viewer->spinOnce();
// std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
// 计算旋转矩阵
Eigen::Matrix4d TransforMatrix(Eigen::Vector3d translation,double roll,double pitch,double yaw) {
Eigen::Quaterniond q = Eigen::AngleAxisd(yaw, Eigen::Vector3d::UnitZ())
* Eigen::AngleAxisd(pitch, Eigen::Vector3d::UnitY())
* Eigen::AngleAxisd(roll, Eigen::Vector3d::UnitX());
Eigen::Matrix4d transformation_matrix = Eigen::Matrix4d::Identity(); // 初始化为单位矩阵
transformation_matrix.block<3, 3>(0, 0) = q.toRotationMatrix(); // 设置旋转矩阵部分
transformation_matrix.block<3, 1>(0, 3) = translation; // 设置平移向量部分
std::cout << "旋转矩阵:" << std::endl << transformation_matrix << std::endl;
return transformation_matrix;
// 计算旋转矩阵
inline Eigen::Matrix4d TransforMatrix(Eigen::Vector3d translation, double roll,
double pitch, double yaw) {
Eigen::Quaterniond q = Eigen::AngleAxisd(yaw, Eigen::Vector3d::UnitZ()) *
Eigen::AngleAxisd(pitch, Eigen::Vector3d::UnitY()) *
Eigen::AngleAxisd(roll, Eigen::Vector3d::UnitX());
Eigen::Matrix4d transformation_matrix =
Eigen::Matrix4d::Identity(); // 初始化为单位矩阵
transformation_matrix.block<3, 3>(0, 0) =
q.toRotationMatrix(); // 设置旋转矩阵部分
transformation_matrix.block<3, 1>(0, 3) = translation; // 设置平移向量部分
std::cout << "旋转矩阵:" << std::endl << transformation_matrix << std::endl;
return transformation_matrix;
}

View File

@ -1,6 +1,19 @@
# 基础ros设置
sub_cloud_topic : "abc"
pub_cloud_topic : "efg"
sub_cloud_topic : "/livox/lidar_192_168_20_105"
pub_cloud_ground_topic : "cloud_ground"
pub_cloud_noground_topic : "cloud_noground"
obstacles_topic : "obstacles_topic"
# 激光雷达到车体坐标系变换
convert:
transform:
x: 0.3643
y: 0.2078
z: 1.21
# 角度,代码里会转成弧度
rotation :
roll: -179.5
pitch: 0.5
yaw: 360
# 降采样大小
filterRes : 0.05
# 设置roi区域
@ -25,10 +38,13 @@ ransac:
distanceThreshold : 0.1
# 设置聚类参数
cluster:
clusterTolerance : 0.2
clusterTolerance : 0.15
minsize : 30
maxsize : 1000
maxsize : 2000
# 可视化分割地面点云
view:
segment : false
# 打印日志
log:
enable_obstacles: false