【车路协同】路端 局部坐标

由于路端设备是倾斜的,存在角度问题,需要变换

1倾角计算

流程

  1. 获得一帧点云
  2. 剪裁点云,只剩下地面
  3. RANSAC平面拟合
  4. 计算平面与水平面夹角

1获得一帧点云,保存为pcd

#include <ros/ros.h>
#include <sensor_msgs/PointCloud2.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/ply_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/io/io.h>
#include <time.h>

 
int flag=1;
 
void cloudCallback(const sensor_msgs::PointCloud2 ros_cloud)
{
    //ROS_INFO("cloud is going");
    pcl::PointCloud<pcl::PointXYZ> pcl_cloud_temp;
    pcl::fromROSMsg(ros_cloud, pcl_cloud_temp);
    if(flag==1)
    {
        pcl::io::savePCDFileASCII ("./road_pcd.pcd", pcl_cloud_temp); //将点云保存到PCD文件中
        flag=0;
        std::cout<<"saved one"<<endl;
    }
}
int main(int argc, char **argv)
{ 
    ros::init(argc, argv, "pcd_get");
    ros::NodeHandle n;
    ROS_INFO("begin");
    ros::Subscriber cloud_sub = n.subscribe("/converted_velodyne_points", 50, cloudCallback);
    ros::spin();
    return 0;
}

2剪裁点云,提取地面

#include <iostream>
#include <vector>

#include <boost/shared_ptr.hpp>

#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h>

#include<pcl/filters/passthrough.h>  //直通滤波器头文件
#include<pcl/filters/voxel_grid.h>  //体素滤波器头文件
#include<pcl/filters/statistical_outlier_removal.h>   //统计滤波器头文件
#include <pcl/filters/conditional_removal.h>    //条件滤波器头文件
#include <pcl/filters/radius_outlier_removal.h>   //半径滤波器头文件

using pcl::visualization::PointCloudColorHandlerGenericField;
using pcl::visualization::PointCloudColorHandlerCustom;
using namespace std;
int main(int argc, char *argv[])
{
    std::cout<<"cnm"<<endl;
	//读取
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	if (pcl::io::loadPCDFile<pcl::PointXYZ>("/home/qm/my_projects/pcl_projects/pcd/road_pcd.pcd", *cloud) == -1)
	{
		std::cerr << "open failed!" << std::endl;
		return -1;
	}




	//
	//直通滤波器对点云 x方向进行处理。*/
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_x_PassThrough(new pcl::PointCloud<pcl::PointXYZ>);//

	pcl::PassThrough<pcl::PointXYZ> passthrough_x;
	passthrough_x.setInputCloud(cloud);//输入点云

	passthrough_x.setFilterFieldName("x");//对z轴进行操作
	passthrough_x.setFilterLimits(-5.0, 5.0);//设置直通滤波器操作范围
	// passthrough.setFilterLimitsNegative(true);//true表示保留范围内,false表示保留范围外
	passthrough_x.filter(*cloud_x_PassThrough);//执行滤波,过滤结果保存在 cloud_after_PassThrough



	//直通滤波器对点云 y方向进行处理。*/
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_y_PassThrough(new pcl::PointCloud<pcl::PointXYZ>);//

	pcl::PassThrough<pcl::PointXYZ> passthrough_y;
	passthrough_y.setInputCloud(cloud_x_PassThrough);//输入点云

	passthrough_y.setFilterFieldName("y");//对z轴进行操作
	passthrough_y.setFilterLimits(-100, 0.0);//设置直通滤波器操作范围
	// passthrough.setFilterLimitsNegative(true);//true表示保留范围内,false表示保留范围外
	passthrough_y.filter(*cloud_y_PassThrough);//执行滤波,过滤结果保存在 cloud_after_PassThrough

	//点保存点云
	pcl::io::savePCDFileASCII("./road_ground.pcd", *cloud_y_PassThrough);//将点云保存到PCD文件中
	std::cerr << "Saved" << cloud_y_PassThrough->points.size() << "data points to test_pcd.pcd" << std::endl;








	//显示
	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
	viewer->setBackgroundColor(0, 0, 0);
	viewer->addPointCloud<pcl::PointXYZ>(cloud_y_PassThrough, "sample cloud");
	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
	viewer->addCoordinateSystem(1.0);
	viewer->initCameraParameters();

	while (!viewer->wasStopped())
	{
		viewer->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100000));
	}

	return 0;
}

3 RANSAC 点云平面拟合

注意看看提取的点云是不是真的一个平面
调整ransac.setDistanceThreshold(0.1);//设定阈值 默认0.3
越小越精细

#include <iostream>
#include <pcl/console/parse.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/sample_consensus/ransac.h>
#include <pcl/sample_consensus/sac_model_plane.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
#include <Eigen/Core>

using namespace std;

int main(int argc, char** argv)
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr final(new pcl::PointCloud<pcl::PointXYZ>);
	
	pcl::io::loadPCDFile<pcl::PointXYZ>("/home/qm/my_projects/pcl_projects/pcd/road_ground.pcd", *cloud);
	std::cout<<"origin points num:"<<cloud->points.size()<<endl;

	vector<int> inliers;	//用于存放合群点的vector

	pcl::SampleConsensusModelPlane<pcl::PointXYZ>::Ptr model_plane(new pcl::SampleConsensusModelPlane<pcl::PointXYZ>(cloud));
	pcl::RandomSampleConsensus<pcl::PointXYZ> ransac(model_plane);//定义RANSAC算法模型

	ransac.setDistanceThreshold(0.1);//设定阈值 默认0.3
	ransac.computeModel();//拟合平面


	ransac.getInliers(inliers);//获取合群点
	double a, b, c, d, A, B, C, D;//a,b,c为拟合平面的单位法向量,A,B,C为重定向后的法向量
	Eigen::VectorXf coeff;
	ransac.getModelCoefficients(coeff);//获取拟合平面参数,对于平面ax+by+cz+d=0,coeff分别按顺序保存a,b,c,d
	cout << "coeff " << coeff[0] << " \t" << coeff[1] << "\t " << coeff[2] << "\t " << coeff[3] << endl;
	a = coeff[0], b = coeff[1], c = coeff[2], d = coeff[3];
	//---------------平面法向量定向,与(1,1,1)同向,并输出平面与原点的距离D----------------------
	if (a + b + c > 0) {
		A = a;
		B = b;
		C = c;
		D = abs(d);
	}
	else {
		A = -a;
		B = -b;
		C = -c;
		D = abs(d);
	}
	cout<<" ABCD:"<<endl;
	cout << "" << A << ",\t" << "" << B << ",\t" << "" << C << ",\t" << "" << D << ",\t" << endl;
	pcl::copyPointCloud<pcl::PointXYZ>(*cloud, inliers, *final);


	std::cout<<"final points num:"<<final->points.size()<<endl;
	// pcl::io::savePCDFileASCII("1.11.pcd", *final);



	//同时显示
	// boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("cloud show"));
	// int v1 = 0;
	// int v2 = 1;
	// viewer->createViewPort(0, 0, 0.5, 1, v1);
	// viewer->createViewPort(0.5, 0, 1, 1, v2);
	// viewer->setBackgroundColor(0, 0, 0, v1);
	// viewer->setBackgroundColor(0.05, 0, 0, v2);
	// //----------------------------------原始点云绿色------------------------------
	// pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> src_h(cloud, 0, 255, 0);
	// //--------------------------------平面拟合后的点云----------------------------
	// pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> after_sac(final, 0, 0, 255);
	// viewer->setBackgroundColor(0, 0, 0);
	// viewer->addPointCloud(cloud, src_h, "source cloud", v1);
	// viewer->addPointCloud(final, after_sac, "target cloud1", v2);

	// while (!viewer->wasStopped())
	// {
	// 	viewer->spinOnce(100);
	// 	boost::this_thread::sleep(boost::posix_time::microseconds(10000));
	// }


	//显示单个
	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
	viewer->setBackgroundColor(0, 0, 0);
	viewer->addPointCloud<pcl::PointXYZ>(final, "sample cloud");
	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
	viewer->addCoordinateSystem(1.0);
	viewer->initCameraParameters();

	while (!viewer->wasStopped())
	{
		viewer->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100000));
	}

	return 0;
}

4 计算点云平面与地面夹角

Ax+By+Cz+D=0是一般方程
法向量就是(A,B,C)

#include<iostream>
#include <cmath>
using namespace std;
int main (int argc, char *argv[])
{
    // z=0
    double x1=0;
    double y1=0;
    double z1=1;


    // -0.0264245*x+0.382563*y+0.923552*z+3.34908=0 第一次
    //-0.0206086,	0.392848,	0.919372,	3.47223,	第二次
    double  x2=-0.0206086;
    double  y2=0.392848;
    double  z2=0.919372;

    // double  x2=1;
    // double  y2=0;
    // double  z2=0;

    double dz = z2 - z1;
    double dy = y2 - y1;
    double dx = x2 - x1;
    // cmath
    // arccos acos
    // 开根号 sqrt
    double t1=x1*x2+y1*y2+z1*z2;
    double l1=sqrt(x1*x1+y1*y1+z1*z1);
    double l2=sqrt(x2*x2+y2*y2+z2*z2);

    double cos_t=t1/(l1*l2);
    double angle_hd=acos(cos_t);
    double angle_jd=angle_hd * 180 / 3.1415926;
    // double angle = atan2( abs(dz), sqrt(dx * dx + dy * dy) );
    cout<<"angle"<<angle_jd<<endl;
    return 0;
}

5结果与准确性

量角器也试了,大概就是20°左右一点点。证明OK

rviz点云

计算结果

2 路段感知

使用yoloact+激光雷达获得目标的

  • 类别
  • 激光雷达坐标系下的xy坐标,三维边界框

3 坐标变换

激光雷达坐标系下的xy坐标,转换到路端水平面的坐标

示意图

在这里插入图片描述

x1=x0
y1=y0cos(a)    //a为倾角

3 附录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值