ros2 学习launch文件组织工程 yaml配置文件
简单范例
功能描述
使用launch文件,统一管理工程,实现img转点云,发送到img_pt的topic,然后用reg_pcl节点进行subscribe,进行点云配准处理,输出融合后的点云到map_pt的topic。最后由rviz2进行点云展示。
环境准备
ubuntu18.04+ros2(eloquent此版本需要于Ubuntu对应)+ Python(version=3.6需要于eloquent对应)+PCL+EIGEN+rviz2
具体安装库和依赖不做赘述
代码实现
代码结构
代码结构编译前
pcl_reg
├── CMakeLists.txt
├── config
│ ├── img2pt.yaml
│ └── reg_pcl.yaml
├── include
│ └── pcl_reg
├── launch
│ ├── img2pt.launch.py
│ ├── mapping.launch.py
│ ├── mapping_sub.launch.py
│ ├── reg_pcl.launch.py
│ └── showviz.launch.py
├── package.xml
├── rviz
└── src├── img2pt.cpp├── odom_pre.cpp├── other.txt├── pt_show.cpp└── reg_pcl.cpp
代码内容
img转pt的部分,图像为rgb三通道的语义图,转换为点云,点云为pcl::PointXYZRGB的格式,XYZ为点云位置,RGB对应图像的三通道rgb。其中XY可以通过图像的u,v坐标转换得到,因为是BEV视角,Z坐标统一置零即可。然后由于语义图上的点云数量过多,在后续匹配的过程中中会降低效率。可以做一些预处理,例如下采样,设置权值等。
map2pt.cpp
#include <iostream>
#include <chrono>
#include <memory>
#include <rclcpp/rclcpp.hpp>
#include <sensor_msgs/msg/point_cloud2.hpp>
#include "pcl_conversions/pcl_conversions.h"//for pcl::toROSMsg
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>#include <pcl/common/common.h>
#include <pcl/common/transforms.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/kdtree/kdtree_flann.h>#include <opencv2/opencv.hpp>
#include <Eigen/Dense>
// typedef pcl::PointXYZRGB pcl::PointXYZRGB;
using namespace std::chrono_literals;class PointCloudPublisher : public rclcpp::Node
{
public:PointCloudPublisher() : Node("point_cloud_publisher"){count = 1380;param_respond();//参数初始化// timer_param_ = this->create_wall_timer(500ms, std::bind(&PointCloudPublisher::param_respond, this));// 创建一个Publisher,发布PointCloud2消息到名为"pt"的topicpublisher_ = this->create_publisher<sensor_msgs::msg::PointCloud2>("img_pt", 10);// 创建一个定时器,每秒钟发布一次PointCloud2消息 std::chrono::seconds(1)timer_ = this->create_wall_timer(1s, std::bind(&PointCloudPublisher::publishPointCloud, this));}private://使用yaml进行参数配置,此处参数只会在初始化时生效一次。如果需要参数随时变化,需要做其他处理void param_respond(){//定义可配置参数,与yaml文件或launch文件中参数名需要对应,需要注意的是参数类型需要匹配,否则会报错。并给出参数默认值。this->declare_parameter<float>("voxel_grid_x", 0.05);this->declare_parameter<float>("voxel_grid_y", 0.05);this->declare_parameter<float>("voxel_grid_z", 0.05);//获取参数,并将参数值赋值到对应变量this->get_parameter("voxel_grid_x", voxel_grid_x_);this->get_parameter("voxel_grid_y", voxel_grid_y_);this->get_parameter("voxel_grid_z", voxel_grid_z_);//打印RCLCPP_INFO(this->get_logger(), "Hello voxel_grid_x:%f, voxel_grid_y:%f, voxel_grid_z:%f", voxel_grid_x_,voxel_grid_y_,voxel_grid_z_);//将参数统一放到std::vector<rclcpp::Parameter>中并set到节点里,此时参数文件yaml或launch文件中的数值开始生效。std::vector<rclcpp::Parameter> all_new_parameters{rclcpp::Parameter("voxel_grid_x", voxel_grid_x_),rclcpp::Parameter("voxel_grid_y", voxel_grid_y_),rclcpp::Parameter("voxel_grid_z", voxel_grid_z_)};this->set_parameters(all_new_parameters);}void publishPointCloud(){// 创建一个PointCloud对象pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_src(new pcl::PointCloud<pcl::PointXYZRGB>);std::string path_img = "/home/apollo/zr/code/data/sim_data/camera1-230829-164731_Lanes/"+std::to_string(count)+".jpg";cv::Mat image = cv::imread(path_img);// 检查图片是否成功加载if (image.empty()) {std::cout << "无法加载图片" << std::endl;// return -1;}RCLCPP_INFO(this->get_logger(), "Publishing: '%d'", count);count=count+12;pcl::PointCloud<pcl::PointXYZRGB>::Ptr pointCloud(new pcl::PointCloud<pcl::PointXYZRGB>);Eigen::Matrix3f matK_ipm_inverse = Eigen::Matrix3f::Identity(3, 3);//bias表示车后轴中心在图像像素位置//k_cam表示图像像素和实际尺度m的比例关系float k_cam = 0.0325;float x_bias = 480*4.0/5.0*k_cam;float y_bias = 640/2.0*k_cam;matK_ipm_inverse << 0,-k_cam,x_bias,-k_cam,0,y_bias,0,0,1;pointCloud = ipmToPointCloud(image,matK_ipm_inverse);// /*// 点云降采样// create new keyFrame, and add pointCloud to global mapbool make_global_map = true;pcl::PointCloud<pcl::PointXYZRGB>::Ptr downsampled_cloud(new pcl::PointCloud<pcl::PointXYZRGB>);if(make_global_map){// 创建 VoxelGrid 对象pcl::VoxelGrid<pcl::PointXYZRGB> voxel_grid;voxel_grid.setInputCloud(pointCloud);voxel_grid.setLeafSize(voxel_grid_x_, voxel_grid_y_, voxel_grid_z_); // 设置体素大小// 执行下采样voxel_grid.filter(*downsampled_cloud);// *globalFeatureCloud=globalMapDS;RCLCPP_INFO(this->get_logger(), "globalFeatureCloud size is: '%d'", (int)downsampled_cloud->size());}// */// 创建一个PointCloud2消息sensor_msgs::msg::PointCloud2::UniquePtr cloud_msg(new sensor_msgs::msg::PointCloud2);pcl::toROSMsg(*downsampled_cloud, *cloud_msg);// pcl::toROSMsg(*pointCloud, *cloud_msg);cloud_msg->header.frame_id = "base_link"; // 设置坐标系cloud_msg->header.stamp = this->now();// 设置PointCloud2消息的时间戳// 发布PointCloud2消息到"pt"的topicpublisher_->publish(std::move(cloud_msg));}pcl::PointCloud<pcl::PointXYZRGB>::Ptr ipmToPointCloud(const cv::Mat& ipmImage,const Eigen::Matrix3f matK_ipm_inv){pcl::PointCloud<pcl::PointXYZRGB>::Ptr pointCloudOut(new pcl::PointCloud<pcl::PointXYZRGB>);for (int y = 0; y < ipmImage.rows; ++y) {for (int x = 0; x < ipmImage.cols; ++x) {cv::Vec3b pixel = ipmImage.at<cv::Vec3b>(y, x);if (!(pixel[0]==0 && pixel[1]==0 && pixel[2]==0)) {pcl::PointXYZRGB pclPoint;Eigen::Vector3f uv1(x,y,1);Eigen::Vector3f xyz=matK_ipm_inv*uv1;pclPoint.x = xyz(0);pclPoint.y = xyz(1);pclPoint.z = 0;pclPoint.r = pixel[0];pclPoint.g = pixel[1];pclPoint.b = pixel[2];pointCloudOut->push_back(pclPoint);// if(pixel[0]==233, pixel[1]==238, pixel[2]==12)// {// std::cout<<"u,v:["<<x<<","<<y<<"] x,y:["<<pclPoint.x<<","<<pclPoint.y<<"]"<<std::endl;// }}}}return pointCloudOut;}int count;rclcpp::Publisher<sensor_msgs::msg::PointCloud2>::SharedPtr publisher_;rclcpp::TimerBase::SharedPtr timer_;float voxel_grid_x_;float voxel_grid_y_;float voxel_grid_z_;// rclcpp::TimerBase::SharedPtr timer_param_;
};int main(int argc, char** argv)
{rclcpp::init(argc, argv);auto node = std::make_shared<PointCloudPublisher>();rclcpp::spin(node);rclcpp::shutdown();/*打开图片: 单独实线功能,不使用ros2系统 */// cv::Mat image = cv::imread("/home/apollo/zr/code/data/sim_data/camera1-230829-164731_Lanes/1440.jpg");// // 检查图片是否成功加载// if (image.empty()) {// std::cout << "无法加载图片" << std::endl;// return -1;// }// pcl::PointCloud<pcl::PointXYZRGB>::Ptr pointCloud(new pcl::PointCloud<pcl::PointXYZRGB>);// Eigen::Matrix3f matK_ipm = Eigen::Matrix3f::Identity(3, 3);// matK_ipm << 0,40,1.798070000000000057e+00,// -40,0,0,// 0,0,1;// pointCloud = ipmToPointCloud(image,matK_ipm);// // 创建窗口并显示图片// cv::namedWindow("Image", cv::WINDOW_NORMAL);// cv::imshow("Image", image);// // 等待按键退出// cv::waitKey(0);return 0;
}
reg_pcl.cpp
#include <rclcpp/rclcpp.hpp>
#include <sensor_msgs/msg/point_cloud2.hpp>
#include <geometry_msgs/msg/transform_stamped.hpp>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl_conversions/pcl_conversions.h>#include <iostream>
#include <pcl/registration/icp.h>
#include <pcl/registration/ndt.h>
#include <pcl/common/common.h>
#include <pcl/common/transforms.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/kdtree/kdtree_flann.h>// 处理点云的函数class PointCloudProcessor : public rclcpp::Node
{
public:PointCloudProcessor() : Node("point_cloud_processor"){param_respond();//参数初始化init_flag = true;//第一帧标志位,第一帧无法进行点云配准count = 0;//匹配次数,为了保存结果点云计数,可选用map_RT = Eigen::Matrix4f::Identity();//建图功能累计的位姿矩阵cloud_local_map = pcl::PointCloud<pcl::PointXYZRGB>::Ptr(new pcl::PointCloud<pcl::PointXYZRGB>);// 创建订阅者,订阅 'img_pt' 话题的点云消息subscription_ = this->create_subscription<sensor_msgs::msg::PointCloud2>("img_pt", rclcpp::QoS(10),std::bind(&PointCloudProcessor::pointCloudCallback, this, std::placeholders::_1));// 创建发布者,发布处理后的点云到 'map_pt' 话题publisher_ = this->create_publisher<sensor_msgs::msg::PointCloud2>("map_pt", rclcpp::QoS(10));}private://使用yaml进行参数配置,此处参数只会在初始化时生效一次。如果需要参数随时变化,需要做其他处理void param_respond(){//定义可配置参数,与yaml文件或launch文件中参数名需要对应,需要注意的是参数类型需要匹配,否则会报错。并给出参数默认值。this->declare_parameter<bool>("use_icp", true);this->declare_parameter<int>("icpMaximumIterations", 1);this->declare_parameter<double>("icpMaxCorrespondenceDistance", 1);this->declare_parameter<double>("icpTransformationEpsilon", 1e-10);this->declare_parameter<double>("icpEuclideanFitnessEpsilon", 0.001);this->declare_parameter<double>("icpFitnessScoreThresh", 0.3);this->declare_parameter<double>("ndtTransformationEpsilon", 1e-10);this->declare_parameter<double>("ndtResolution", 0.1);this->declare_parameter<double>("ndtFitnessScoreThresh", 0.3);//获取参数,并将参数值赋值到对应变量this->get_parameter("use_icp", use_icp_);this->get_parameter("icpMaximumIterations", icpMaximumIterations_);this->get_parameter("icpMaxCorrespondenceDistance", icpMaxCorrespondenceDistance_);this->get_parameter("icpTransformationEpsilon", icpTransformationEpsilon_);this->get_parameter("icpEuclideanFitnessEpsilon", icpEuclideanFitnessEpsilon_);this->get_parameter("icpFitnessScoreThresh", icpFitnessScoreThresh_);this->get_parameter("ndtTransformationEpsilon", ndtTransformationEpsilon_);this->get_parameter("ndtResolution", ndtResolution_);this->get_parameter("ndtFitnessScoreThresh", ndtFitnessScoreThresh_);//调试过程中,如果怀疑参数文件有问题,可以使用下方直接赋值方法,确认其他部分没有问题,定位问题到参数文件yaml或launch文件上// icpTransformationEpsilon_ = 1e-10;// ndtTransformationEpsilon_ = 1e-10;RCLCPP_INFO(this->get_logger(), "Hello use_icp:%d, icpMaximumIterations:%d, icpMaxCorrespondenceDistance:%f", use_icp_,icpMaximumIterations_,icpMaxCorrespondenceDistance_);将参数统一放到std::vector<rclcpp::Parameter>中并set到节点里,此时参数文件yaml或launch文件中的数值开始生效。std::vector<rclcpp::Parameter> all_new_parameters{rclcpp::Parameter("use_icp", use_icp_),rclcpp::Parameter("icpMaximumIterations", icpMaximumIterations_),rclcpp::Parameter("icpMaxCorrespondenceDistance", icpMaxCorrespondenceDistance_),rclcpp::Parameter("icpTransformationEpsilon", icpTransformationEpsilon_),rclcpp::Parameter("icpEuclideanFitnessEpsilon", icpEuclideanFitnessEpsilon_),rclcpp::Parameter("icpFitnessScoreThresh", icpFitnessScoreThresh_),rclcpp::Parameter("ndtTransformationEpsilon", ndtTransformationEpsilon_),rclcpp::Parameter("ndtResolution", ndtResolution_),rclcpp::Parameter("ndtFitnessScoreThresh", ndtFitnessScoreThresh_)};this->set_parameters(all_new_parameters);}void pointCloudCallback(const sensor_msgs::msg::PointCloud2::SharedPtr input_msg){std::cout<<"rcv pt msg"<<std::endl;// 将接收到的点云消息转换为 pcl::PointCloud<pcl::PointXYZRGB> 类型pcl::PointCloud<pcl::PointXYZRGB>::Ptr cameraCloudIn(new pcl::PointCloud<pcl::PointXYZRGB>);pcl::fromROSMsg(*input_msg, *cameraCloudIn);if(init_flag){//第一帧不做匹配,仅保存cloud_src = cameraCloudIn;cloud_local_map = cameraCloudIn;init_flag = false;return ; }else{cloud_tgt = cloud_src;cloud_src = cameraCloudIn;//计时开始rclcpp::Clock steady_clock_{RCL_STEADY_TIME};auto start_time = steady_clock_.now();// 点云配准mapping_local(cloud_src,cloud_tgt);// 计时结束并计算costauto cycle_duration = steady_clock_.now() - start_time;std::cout<<"icp cost time:"<<cycle_duration.seconds()<<" s"<<std::endl;RCLCPP_INFO(get_logger(), "Cost %.4f s", cycle_duration.seconds());}// 将处理后的点云转换为 sensor_msgs::msg::PointCloud2 类型sensor_msgs::msg::PointCloud2::UniquePtr result_msg(new sensor_msgs::msg::PointCloud2);pcl::toROSMsg(*cloud_local_map, *result_msg);// pcl::toROSMsg(*cloud_src, *result_msg);result_msg->header.frame_id = "base_link2"; // 设置坐标系result_msg->header.stamp = this->now();// 设置PointCloud2消息的时间戳// 发布处理后的点云到 'map_pt' 话题publisher_->publish(std::move(result_msg));}void mapping_local(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr& src_cloud,const pcl::PointCloud<pcl::PointXYZRGB>::Ptr& tgt_cloud){Eigen::Matrix4f transWorldCurrent = Eigen::Matrix4f::Identity();transWorldCurrent(0,3)=1;// printMat4(transWorldCurrent);pcl::PointCloud<pcl::PointXYZRGB>::Ptr currentFeatureCloudInWorld(new pcl::PointCloud<pcl::PointXYZRGB>());if(use_icp_){static pcl::IterativeClosestPoint<pcl::PointXYZRGB, pcl::PointXYZRGB> icp;icp.setMaxCorrespondenceDistance(icpMaxCorrespondenceDistance_); icp.setMaximumIterations(icpMaximumIterations_);icp.setTransformationEpsilon(icpTransformationEpsilon_);icp.setEuclideanFitnessEpsilon(icpEuclideanFitnessEpsilon_);icp.setInputSource(src_cloud);icp.setInputTarget(tgt_cloud);pcl::PointCloud<pcl::PointXYZRGB>::Ptr transCurrentCloudInWorld(new pcl::PointCloud<pcl::PointXYZRGB>());icp.align(*transCurrentCloudInWorld,transWorldCurrent.matrix());//迭代效果不理想,原因尚未定位到???if (icp.hasConverged() == false || icp.getFitnessScore() > icpFitnessScoreThresh_) {std::cout << "ICP locolization failed the score is " << icp.getFitnessScore() << std::endl;return ;} else {transWorldCurrent = icp.getFinalTransformation();printMat4(transWorldCurrent);}}else{pcl::NormalDistributionsTransform<pcl::PointXYZRGB, pcl::PointXYZRGB> ndt;ndt.setTransformationEpsilon(ndtTransformationEpsilon_);ndt.setResolution(ndtResolution_);ndt.setInputSource(src_cloud);ndt.setInputTarget(tgt_cloud);pcl::PointCloud<pcl::PointXYZRGB>::Ptr transCurrentCloudInWorld(new pcl::PointCloud<pcl::PointXYZRGB>());ndt.align(*transCurrentCloudInWorld, transWorldCurrent.matrix());//会直接退出程序,原因尚未定位到???if (ndt.hasConverged() == false || ndt.getFitnessScore() > ndtFitnessScoreThresh_) {std::cout << "ndt locolization failed the score is " << ndt.getFitnessScore() << std::endl;return ;} else{ transWorldCurrent =ndt.getFinalTransformation();printMat4(transWorldCurrent);}} map_RT = map_RT*transWorldCurrent;pcl::transformPointCloud (*src_cloud, *currentFeatureCloudInWorld, map_RT);/*// 保存pcd文件,方便pcl_viewer <pcdfile.pcd>count++;std::string filename1 = "/home/apollo/zr/code/resultpcd/src_tgt"+std::to_string(count)+".pcd";pcl::PointCloud<pcl::PointXYZRGB>::Ptr show_cloud1(new pcl::PointCloud<pcl::PointXYZRGB>);*show_cloud1 = *show_cloud1+*src_cloud;*show_cloud1 = *show_cloud1+*tgt_cloud;pcl::io::savePCDFileBinary(filename1, *show_cloud1);std::string filename2 = "/home/apollo/zr/code/resultpcd/tgt_trans"+std::to_string(count)+".pcd";pcl::PointCloud<pcl::PointXYZRGB>::Ptr show_cloud2(new pcl::PointCloud<pcl::PointXYZRGB>);*show_cloud2 = *show_cloud2+*tgt_cloud;*show_cloud2 = *show_cloud2+*currentFeatureCloudInWorld;pcl::io::savePCDFileBinary(filename2, *show_cloud2);*/// 创建新的帧,并将src点云(后续需要换成匹配点云点对)添加进map点云*cloud_local_map = *cloud_local_map+*currentFeatureCloudInWorld;RCLCPP_INFO(this->get_logger(), "cloud_local_map size is: '%d'", (int)cloud_local_map->size());//}rclcpp::Subscription<sensor_msgs::msg::PointCloud2>::SharedPtr subscription_;rclcpp::Subscription<geometry_msgs::msg::TransformStamped>::SharedPtr subscription_odom_;rclcpp::Publisher<sensor_msgs::msg::PointCloud2>::SharedPtr publisher_;Eigen::Matrix4f map_RT;pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_local_map;pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_src; //不需要初始化,后面会赋值pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_tgt;//不需要初始化,后面会赋值bool init_flag;int count;bool use_icp_ = true;double icpMaxCorrespondenceDistance_=1;//100int icpMaximumIterations_=1;//100double icpTransformationEpsilon_=1e-10;double icpEuclideanFitnessEpsilon_=0.001;double icpFitnessScoreThresh_=0.3;//0.3double ndtTransformationEpsilon_=1e-10;double ndtResolution_=0.1;double ndtFitnessScoreThresh_=0.3;void printMat4(Eigen::Matrix4f mat){std::cout<<"matrix is :"<<std::endl;for(int i=0;i<mat.rows();i++){for(int j=0;j<mat.cols();j++){std::cout<<mat(i,j)<<" , ";}std::cout<<std::endl;}}
};int main(int argc, char** argv)
{rclcpp::init(argc, argv);rclcpp::spin(std::make_shared<PointCloudProcessor>());rclcpp::shutdown();return 0;
}
对CMakeLists.txt进行适当修改
cmake_minimum_required(VERSION 3.5)
project(pcl_reg)# Default to C99
if(NOT CMAKE_C_STANDARD)set(CMAKE_C_STANDARD 99)
endif()# Default to C++14
if(NOT CMAKE_CXX_STANDARD)set(CMAKE_CXX_STANDARD 14)
endif()if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")add_compile_options(-Wall -Wextra -Wpedantic)
endif()# 寻找依赖库(标准库)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(sensor_msgs REQUIRED)# 寻找依赖库(外部库)
find_package(Eigen3 REQUIRED)
# 针对PCL库版本不适配会出现warning,做的补丁,其实没有解决问题
if(NOT DEFINED CMAKE_SUPPRESS_DEVELOPER_WARNINGS)set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE INTERNAL "No dev warnings")
endif()
find_package(PCL REQUIRED)
find_package(rviz2 REQUIRED)
find_package(OpenCV 3.2.0 REQUIRED)# 添加包含路径
include_directories(/usr/include${EIGEN3_INCLUDE_DIRS}${PCL_INCLUDE_DIRS}${RVIZ2_INCLUDE_DIRS}/usr/include/OGRE${OpenCV_INCLUDE_DIRS}
)# 添加可执行文件
add_executable(reg_pcl src/reg_pcl.cpp)
ament_target_dependencies(reg_pcl rclcpp sensor_msgs)
target_link_libraries(reg_pcl${PCL_LIBRARIES}# ${OpenCV_LIBS}
)
add_executable(img2pt src/img2pt.cpp)
ament_target_dependencies(img2pt rclcpp sensor_msgs)
target_link_libraries(img2pt${PCL_LIBRARIES}${OpenCV_LIBS}
)add_executable(odom_pre src/odom_pre.cpp)
ament_target_dependencies(odom_pre rclcpp sensor_msgs)
# target_link_libraries(odom_pre
# ${PCL_LIBRARIES}
# ${OpenCV_LIBS}
# )# add_executable(pt_show src/pt_show.cpp)
# ament_target_dependencies(pt_show rclcpp sensor_msgs)
# target_link_libraries(pt_show
# ${PCL_LIBRARIES}
# ${RVIZ2_LIBRARIES}
# # ${OpenCV_LIBS}
# )
##安装可执行文件
install(TARGETS reg_pcl img2ptodom_pre# pt_show# EXPORT export_${PROJECT_NAME}DESTINATION lib/${PROJECT_NAME})##安装launch文件,无论该功能包的launch目录下有多少个launch文件,launch相关配置只需要设置一次即可。ros2 launch <包名> <launch文件名,无需带上launch文件夹地址>
install(DIRECTORY launchconfigDESTINATION share/${PROJECT_NAME}/
)if(BUILD_TESTING)find_package(ament_lint_auto REQUIRED)ament_lint_auto_find_test_dependencies()
endif()ament_package()
对package.xml进行适当修改
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3"><name>pcl_reg</name><version>0.0.0</version><description>TODO: Package description</description><maintainer email="apollo@todo.todo">apollo</maintainer><license>TODO: License declaration</license><depend>rclcpp</depend><depend>sensor_msgs</depend><depend>EIGEN3</depend><depend>PCL</depend><depend>OpenCV</depend><!-- ros2 launch 使得launch file可以被识别 --><exec_depend>ros2launch</exec_depend> <buildtool_depend>ament_cmake</buildtool_depend><test_depend>ament_lint_auto</test_depend><test_depend>ament_lint_common</test_depend><export><build_type>ament_cmake</build_type></export>
</package>
launch文件
img2pt.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
import os
from ament_index_python.packages import get_package_share_directorydef generate_launch_description():config = os.path.join(get_package_share_directory('pcl_reg'),'config','img2pt.yaml')return LaunchDescription([Node(package='pcl_reg',node_executable='img2pt',name='point_cloud_publisher',output="screen",emulate_tty=True,parameters=[config],# parameters=[# {"voxel_grid_x":0.08},# {"voxel_grid_y":0.12},# {"voxel_grid_z":0.66}# ]),])
reg_pcl.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
import os
from ament_index_python.packages import get_package_share_directorydef generate_launch_description():config = os.path.join(get_package_share_directory('pcl_reg'),'config','reg_pcl.yaml')return LaunchDescription([Node(package='pcl_reg',node_executable='reg_pcl',name='point_cloud_processor',output="screen",emulate_tty=True,parameters=[config],# parameters=[# {"voxel_grid_x":0.08},# {"voxel_grid_y":0.12},# {"voxel_grid_z":0.66}# ]),])
mapping.launch.py
from launch import LaunchDescription
from launch_ros.actions import Nodedef generate_launch_description():return LaunchDescription([Node(package='pcl_reg',node_executable='img2pt',name='point_cloud_publisher',output="screen",emulate_tty=True,),Node(package='pcl_reg',node_executable='reg_pcl',name='point_cloud_processor',output="screen",emulate_tty=True,),##ExecuteProcess是针对有终端输入的情况# ExecuteProcess()])# def generate_launch_description():
# ld = LaunchDescription()# node1 = Node(
# package='pcl_reg',
# eloquent版本不能用executable,要使用node_executable
# node_executable='img2pt',
# # name='point_cloud_publisher',
# # output='screen'
# )# ld.add_action(node1)# return ld
showviz.launch.py
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Nodedef generate_launch_description():# rviz_config = os.path.join(# get_package_share_directory('pcl_reg'),# 'rviz2',# 'map_pt_conf.rviz'# )rviz_config = os.path.join('/home','apollo','.rviz2','map_pt_conf.rviz')return LaunchDescription([Node(package='rviz2',node_executable='rviz2',# name='rviz2', arguments=['-d', rviz_config])])
mapping_sub.launch.py
import osfrom ament_index_python.packages import get_package_share_directoryfrom launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSourcedef generate_launch_description():img2pt = IncludeLaunchDescription(PythonLaunchDescriptionSource([os.path.join(get_package_share_directory('pcl_reg'), 'launch'),'/img2pt.launch.py']))reg_pcl = IncludeLaunchDescription(PythonLaunchDescriptionSource([os.path.join(get_package_share_directory('pcl_reg'), 'launch'),'/reg_pcl.launch.py']))rviz_node = IncludeLaunchDescription(PythonLaunchDescriptionSource([os.path.join(get_package_share_directory('pcl_reg'), 'launch'),'/showviz.launch.py']))return LaunchDescription([img2pt,reg_pcl,# rviz_node])
img2pt.yaml
point_cloud_publisher: #节点名、不是excutable文件名ros__parameters: #固定形式use_sim_time: false #是否使用仿真时间,一般为falsevoxel_grid_x: 0.05voxel_grid_y: 0.05voxel_grid_z: 0.85
reg_pcl.yaml
point_cloud_processor:ros__parameters:use_sim_time: falseuse_icp_: trueicpMaximumIterations: 1 #100 int型请务必写整数icpMaxCorrespondenceDistance: 1.0005 #double类型不要直接写1,要写带小数点的icpTransformationEpsilon: 1e-10 #支持科学计数法icpEuclideanFitnessEpsilon: 0.001icpFitnessScoreThresh: 0.3ndtTransformationEpsilon: 1e-10ndtResolution: 0.1ndtFitnessScoreThresh: 0.3
使用rviz2订阅topic,查看点云
编写代码订阅topic,查看点云
报错经验总结
ros1系统性卡死
rosnode list #查看节点
rosnode kill #杀死节点
rosnode cleanup #清除无法访问节点的注册信息:杀死kill杀不死的节点
空间或内存或log空间不够时(也是gazebo相关报错,使用gazebo时需要内存和空间)
conda clean --all #清除conda缓存
top #或者top查看进程中谁占用内存较大,并kill掉
rm -rf ~/.ros #清除ros缓存/也可以避免~/.ros/log权限问题
ros1和ros2切换
source /opt/ros/eloquent/setup.bash #ROS2对应ubuntu18版本为eloquent
source /opt/ros/melodic/setup.bash #ROS1对应ubuntu18版本为melodic
一个终端内尽量不要来回切换版本,如果出现ROS_DISTRO相关提示,请关闭终端重新打开
相关文章:
ros2 学习launch文件组织工程 yaml配置文件
简单范例 功能描述 使用launch文件,统一管理工程,实现img转点云,发送到img_pt的topic,然后用reg_pcl节点进行subscribe,进行点云配准处理,输出融合后的点云到map_pt的topic。最后由rviz2进行点云展示。 …...
奇舞周刊第 505 期:实践指南-前端性能提升 270%!
记得点击文章末尾的“ 阅读原文 ”查看哟~ 下面先一起看下本期周刊 摘要 吧~ 奇舞推荐 ■ ■ ■ 实践指南-前端性能提升 270% 当我们疲于开发一个接一个的需求时,很容易忘记去关注网站的性能,到了某一个节点,猛地发现,随着越来越多…...
【C++】泛型编程 | 函数模板 | 类模板
一、泛型编程 泛型编程是啥? 编写一种一般化的、可通用的算法出来,是代码复用的一种手段。 类似写一个模板出来,不同的情况,我们都可以往这个模板上去套。 举个例子: void Swap(int& a, int& b) {int tmp …...
web前端——简单的网页布局案列
✨博主:命运之光 🌸专栏:Python星辰秘典 🐳专栏:web开发(简单好用又好看) ❤️专栏:Java经典程序设计 ☀️博主的其他文章:点击进入博主的主页 目录 问题背景 解决样例 …...
线程安全问题(3)--- wait(),notify()
前言 在多线程的环境下,我们常常要协调多个线程之间的执行顺序,而为了实现这一点,Java提供了一些方法来帮助我们完成这一点。 一,wait() 作用: 使当前线程进入等待状态 释放当前的锁 (即该方法必须和 synchrnized 关键…...
【Android知识笔记】进程通信(一)
一、Android Framework 用到了哪些 IPC 方式 Linux 的 IPC 方式有: 管道Socket共享内存信号信号量消息队列管道通信 管道是基于pipefs文件系统实现的,也就是多个进程通过对同一个文件进行读写来实现进程间通信。半双工,单向的,通过 pipe(fds) 系统函数调用可得到一对文件描…...
存储空间压缩6倍 ,多点DMALL零售SaaS场景降本实践
🧑💼 作者简介 冯光普:多点 DMALL 数据库团队负责人,负责数据库稳定性建设与 DB PaaS 平台建设,在多活数据库架构、数据同步方案等方面拥有丰富经验。 杨家鑫:多点高级 DBA,擅长故障分析与性能…...
BGP路由属性
任何一条BGP路由都拥有多个路径属性(Path Attributes),当路由器通告BGP路由给它的对等体时,该路由将会携带多个路径属性,这些属性描述了BGP路由的各项特征,同时在某些场景下也会影响BGP路由优选的决策。 一…...
Java面试常用函数
1. charAt() 方法用于返回字符串指定索引处的字符。索引范围为从 0 到 length() - 1。 map.getOrDefault(num, 0) :如果map存在num这个key,则返回num对应的value,否则返回0. Arrays.sort(nums); 数组排序 Arrays.asList("a","b",&q…...
linux编译curl库(支持https)
openssl下载和编译 https://www.openssl.org/source/old/ 解压 tar -xvf openssl-3.0.1.tar.gz cd openssl-3.0.1/配置 ./config如果是编译静态库加入 -fPIC no-shared 如果指定安装路径,使用 --prefix=/usr/local/openssl/选项指定特定目录 编译和安装 make sodu make i…...
Ei Scopus检索 | 2024年第三届能源与环境工程国际会议(CFEEE 2024)
会议简介 Brief Introduction 2024年第三届能源与环境工程国际会议(CFEEE 2024) 会议时间:2024年9月1日-3日 召开地点:新西兰奥克兰 大会官网:https://www.cfeee.org/ 2024年第三届能源与环境工程国际会议(CFEEE 2024) 将于2024年12月12日至1…...
thinkphp6(tp6)创建定时任务
使用 thinkphp6 框架中提供的命令行形式实现定时任务 一、创建一个自定义命令类文件 php think make:command Hello 会生成一个 app\command\Hello.php 命令行指令类,我们修改内容如下: <?php declare (strict_types1);namespace app\command;use …...
【学习笔记】C++ 中 static 关键字的作用
目录 前言static 作用在变量上static 作用在全局变量上static 作用在局部变量上static 作用在成员变量上 static 作用在函数上static 作用在函数上static 作用在成员函数上 前言 在 C/C 中,关键字 static 在不同的应用场景下,有不同的作用,这…...
攻防世界-web-file_include
1. 题目描述 打开界面,如下代码: 代码很简单,从参数中获取到filename然后include这个filename 2. 思路分析 2.1 首先参考常见做法,将参数设置为php://filter/readconvert.base64-encode/resourceflag.php,看是否有…...
C语言的函数指针、指针函数, 函数数组
函数指针 是指向函数的指针,它允许您在程序运行时动态选择要调用的函数。函数指针可以像普通变量一样传递、存储和使用,这使得它们在许多编程场景中非常有用,如回调函数、函数表、插件架构等。 以下是一个简单的例子来说明函数指针的概念&a…...
笔记本开启WiFi
笔记本开启WiFi 为了节省流量:笔记本开启WiFi 条件 支持热点的电脑;我的是华硕飞行堡垒7。 注意事项 笔记本连接公司网络,公司网络通常都在监管下的,手机连接wifi后,刷抖音、购物网站,公司后台会捕获你…...
力扣第37天----第322题、第279题
力扣第37天----第322题、第279题 文章目录 力扣第37天----第322题、第279题一、第322题--零钱兑换二、第279题--组合总和 Ⅳ 一、第322题–零钱兑换 整体思路,跟前面的几道完全背包差不多,就不具体解释了。有一些细节要注意,见代码注释。…...
【ArcGIS Pro二次开发】(67):处理面要素空洞
这个一个简单的小功能。 有些面要素可能会存在空洞,这个工具的目的就是获取面要素的空洞,或者去除空洞获取要素的边界。 这个功能其实在之前做拓扑功能的时候就已经有了,这次只是单独把它提取出来。因为有时候会单独用到这个功能。 一、要实…...
FPGA-结合协议时序实现UART收发器(一):UART协议、架构规划、框图
FPGA-结合协议时序实现UART收发器(一):UART协议、架构规划、框图 记录FPGA的UART学习笔记,以及一些细节处理,主要参考奇哥fpga学习资料。 本次UART主要采用计数器方法实现,实现uart的稳定性发送和接收功能…...
web请求cookie中expires总结
用意 cookie 有失效日期 "expires",如果还没有过失效期,即使重新启动电脑,cookie 仍然不会丢失 注意:如果没有指定 expires 值,那么在关闭浏览器时,cookie 即失效。 设置 如果cookie存储时间大…...
如何学习Java核心知识
Java作为一门广泛应用于软件开发的编程语言,拥有着强大的生态系统和丰富的资源,是值得投入时间和精力去学习的。以下是一些建议,帮助你系统地学习Java核心知识。 1. 学习Java语言基础: 学习Java语言基础是学习Java的第一步&…...
【AWS】如何用SSH连接aws上的EC2实例(虚拟机)?
目录 0.环境 1.连接结果示例 2.SSH连接思路 3.具体步骤 1)安装并运行ssh服务 2)启动ssh服务 3)在AWS上找到正在运行的EC2实例,并且根据提供的ssh连接语句进行连接 0.环境 windows 11 64位 前提: 有aws账户&…...
数据结构——看完这篇保证你学会队列
数据结构——队列 一、队列的概念二、队列的实现方式三、队列所需要的接口四、接口的详细实现4.1初始化4.2销毁4.3入队4.5出队4.6获取队头元素4.7获取队尾元素4.8获取队列元素个数4.9判空 五、完整代码5.1Queue.h5.2Queue.c5.3test.c 一、队列的概念 队列:只允许在…...
开源免费缺陷管理工具:对比6款
在软件开发环境中,缺陷管理工具是关键的基础设施。例如,在构建一个电商平台时,这些工具能系统地跟踪从发现到解决的各个问题阶段。它们支持多用户协作,实现信息和状态的实时共享。通过数据分析,这些工具还能帮助团队识…...
Weblogic反序列化漏洞
文章目录 1、搭建环境2、漏洞特征3、漏洞利用1)获取用户名密码2)后台上传shell 4、检测工具 1、搭建环境 漏洞环境基于vulhub搭建–进入weak_password的docker环境 sudo docker-compose up -d拉取靶场 2、漏洞特征 404特征Weblogic常用端口:7001 3、漏洞利用…...
element-ui el-table 滚动到底部,进行加载下一页
使用element-ui 自带的InfiniteScroll 无限滚动组件无法使用在table里面,所以项目只能组件写一个 俺的方法是写了一个自定义组件,进行监听滚动条是否拉到最底部进行一个处理。方法如下 直接复制完事了, loadTableMore: { bind(el, binding…...
线性代数的学习和整理19,特征值,特征向量,以及引入的正交化矩阵概念(草稿)
目录 1 什么是特征值和特征向量? 1.1 特征值和特征向量这2个概念先放后 1.2 直观定义 1.3 严格定义 2 如何求特征值和特征向量 2.1 方法1:结合图形看,直观方法求 2.1.1 单位矩阵的特征值和特征向量 2.1.2 旋转矩阵 2.2 根据严格定义…...
初步了解android如何锁键
百年三万六千日,光阴只有瞬息间。 手机下面的三个图形,正方形,园形,三角形分别的什么建?都起到什么功能? 三角形的那个叫返回键,就是可以返回你的上一个操作; 圆形是HOME键,按一下可…...
行业追踪,2023-09-13
自动复盘 2023-09-13 凡所有相,皆是虚妄。若见诸相非相,即见如来。 k 线图是最好的老师,每天持续发布板块的rps排名,追踪板块,板块来开仓,板块去清仓,丢弃自以为是的想法,板块去留让…...
$nextTick和setTimeout区别(宏任务微任务)
nextTick 在vue 源码中是利用 Promise.resolve()实现的。该问题实际就是Promise与setTimeout的区别,本质是Event Loop中微任务与宏任务的区别。 nextTick:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。…...
绵阳网站建设怎么做/网站建设的意义和目的
页面重构经常会做字体大小调整,有时字体会小于12px,当然如果你用firefox、opera、ie浏览我们的游戏页面,这些都是正常的,但有没有试过chrome呢?这时你会发现原本小于12px字体它却显示12px大小了,就要用到 -…...
做网站服务器怎么用/全球网络营销公司排行榜
一、Nginx 常用命令 cd 到 nginx/sbin目录下 1、查看版本 ./nginx -v2、查看版本详情 nginx -V3、启动 ./nginx4、重新加载nginx,一般是修改了配置 ./nginx -s reload5、关闭 ./nginx -s stop6、检查配置文件 ./nginx -t https配置以及多服务使用同一个端口&…...
东莞做营销网站建设/我赢网提供的高水平网页设计师
各种云计算虚拟机大比拼 我们一直想对国内能用的公有云计算平台做一个性能上的比较,我很高兴看到我们的团队在这方面已经做出了许多重要的工作。今天先把我们对国内几种IaaS平台选择的测试机器拿出来做一个最基本的比较。我们都选择了2核的机器,他们在最…...
想开网店做丝绸生意去哪个网站批发/百度收录入口在哪里
水刺无纺布不锈钢烧结网圆柱滤芯是将五层不锈钢丝网按顺序叠放在一起,经过真空烧结而成的一种新型过滤材料。一般为五层结构,分为保护层、过滤控制层、分散层、支撑骨架层、骨架层五部分。该材料具有过滤精度稳定,强度好,易于反清…...
谁告诉你j2ee是做网站的/网站优化的方法与技巧
使用Ansible的Playbook批量部署多台LAMP环境 Playbook的使用步骤 playbook是一个不同于使用ansible命令行执行方式的模式,功能更强大更灵活。 1、在playbook中定义任务: - name: task description # 任务描述信息module_name:module_args # 需要…...
纺织品服装网站建设优化/今日头条极速版官网
央视网消息:今年《政府工作报告》提出,对拖欠民营企业的款项年底前要清偿一半以上,决不允许增加新的拖欠。年终将至,现在各地的执行进展如何,“清欠”工作又面临着哪些难题呢?根据国务院第六次大督查和第三…...