ROS/PCL学习笔记(一)

1.移动硬盘 Ubuntu 16.04系统安装

【尚未成功2333待补充】

2. Ubuntu 16.04基操

文件目录

/ (根目录) >> / (home目录) >> ~ (当前用户目录) >> /下载 /桌面等

终端命令

命令格式:
command  [-options]  [parameter] 

sudo加在命令前面表示以管理员身份执行,如:
sudo apt install/remove/upgrade *
sudo apt-get update /upgrade

cd (change directory) 相对/绝对路径(~ /)      cd .. 返回上层目录
ls (list)/ll
rm (remove)  删除之后无法恢复
clear 
mkdir

3. ROS 安装

http://wiki.ros.org/kinetic/Installation/Ubuntu

4. ROS 基操

记录一下学习过程中动手的比较好的文章方便日后忘记了寻找。
官方学习文档:
http://pointclouds.org/documentation/tutorials/
http://wiki.ros.org/

4.1. ROS概念

https://blog.csdn.net/AdamShan/article/details/79653378
文中介绍了ROS的重点概念: 节点, master, topic, subscribe, publisher,消息。以及ROS工程目录的组织。 其建议将 ROS 接口节点(订阅,发布)和算法结点分开。

初始化环境变量:

$ echo "source /opt/ros/kinetic/setup.bash" >> ~/.bashrc
$ source ~/.bashrc
1)MOOC ROS入门视频:ROS工程结构

ROS的软件使用package(包)进行组织,包下通常包含一下内容:
/src: 源代码
/msg: 定义一些message
/srv: 定义一些service
/launch:包含用于启动节点的launch file
/config:包含配置文件
/test: Unit/ROS tests
/include/package_name: C++ include头文件
/doc:包含文档文件
package.xml: package 信息
CMakeLists.txt: CMake构建文件

【CMakeLists.txt文件格式】
【topic发布与订阅】

2) ros指令

roslaunch 启动master和多个node程序
roslaunch [pkg_name] [file_name.launch]

rostopic
rostopic list 列出当前所有topic
rostopic info / topic_name 显示某个topic属性
rostopic echo / topic_name显示某个topic内容
rostopic pub /topic_name ... 向某个topic发布内容

rosmsg
rosmsg list列出系统上所有消息msg
rosmsg show /msg_name 显示某个消息msg内容

4.2. ROS:流程 hello world

ros::Rate 循环刷新频率10HZ
ros::ok() 节点运行结束这返回false
ros::spin(); ros::spinOnce() 不断查询订阅的话题,执行回调函数
Logging 不推荐使用std::cout

ROS_INFO("Hello World %d", count);
ROS_INFO_STREAM("Hello World " << count);

流程:
创建工作空间 catkin_ws/src
创建 catkin_create_pkg package_name depend1 depend2 depend3(pcl_ros roscpp sensor_msgs)
创建节点node *.cpp
修改CMakeList和package.xml
编译 catkin_make, source /devel/setup.bash
终端命令:roscore; rosrun package node; rosrun rviz rviz;
其他常用命令:rosnode list; rostopic list; roscd

4.3. PCL:点云数据格式bin转pcd

注意cMakeList.txt中变量名和路径的统一. 在ROS中表示点云的数据结构有 pcl::PointCloud < T >, 而msg中常用pcl::PointCloud2. 他们之间的转换使用命令pcl::fromROSMsgpcl::toROSMsg

     pcl::PCDReader reader;
     reader.read<pcl::PointXYZ> ("/home/lijie/bin2pcd_ws/src/sor_filter/src/table_scene_lms400.pcd", *cloud);
     
   	 pcl::io::loadPCDFile ("/home/lijie/catkin_ws/src/pcd_load/13.pcd", cloud);

4.4. ROS:CMakeList详细解读

4.5. ROS:依赖文件和环境

CMakeLists.txt文件是CMake构建系统的输入,在这里我们不会详细讨论CMake的写法(因为它本身可以很复杂),我们大致熟悉一下我们常用的CMake的语法:

cmake_minimum_required:需要的CMake的最低版本
project():包的名称
find_package() 查找建构是需要的其他 CMake/Catkin 包
add_message_files() add_service_files() add_action_files 生成Message/Service/Action
generate_messages() 调用消息生成
catkin_package() 指定包的构建信息
add_library()/add_executable()/target_link_libraries() 用于构建的库,可执行代码

同样的,在CMakeList中,我们通过find_package查找这三个包的路径,然后将三个包添加到 CATKIN_DEPENDS, 在使用pcl库前,需要将PCL库的路径链接,通过link_directories( $ {PCL_LIBRARY_DIRS})来完成,并在最后的target_link_libraries中添加${PCL_LIBRARIES}

package.xml的内容很简单,实际上就是这个包的描述文件, build_dependrun_depend 两个描述符分别指定了程序包编译和运行的依赖项,通常是所用到的库文件的名称。 在这里我们指定了三个编译和运行时依赖项,分别是roscpp(编写C++ ROS节点), sensor_msgs(定义了激光雷达的msg),pcl_ros(连接ROS和pcl库)。

4.6. PCL:PCD文件拼接

4.7. PCL:下采样和地面过滤

5. ROS/PCL 实操

5.1. 数据集的读取和滤波处理

https://www.cnblogs.com/li-yao7758258/p/6651326.html
Q&A:
a)在一个package/src中建立两个*.cpp节点,分别实现数据的读取和发布、数据的预处理两个功能。
需要修改CMakeLists.txt文件。projectName是package的名字而不是节点名,将原本生成可执行文件命令和链接目标命令中的${PROJECT_NAME}_node(即节点名)修改为你的节点名(建议与*.cpp一致或添加*_node)如下:

```
## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
add_executable(**pcd_load_node**  src/pcd_load.cpp )
target_link_libraries(pcd_load_node ${catkin_LIBRARIES} )

add_executable(pcd_pub_node  src/pcd_pub.cpp )
target_link_libraries(pcd_pub_node ${catkin_LIBRARIES} )
```

b)在建立数据读取和发布节点pcd_pub.cpp时:
注意点云数据格式转换:pcl::toROSMsg(pcl::PointXYZI, sensor_msgs::PointCloud2), pcl::formROSMsg( ),他们包含于 pcl_conversions/pcl_conversions.h头文件中。
发布到topic中时若需要在rviz中显示,这需要fix_frame命令:

```
topic.header.frame_id="velodyne";//是后面rviz的 fixed_frame
```

c)在建立数据预处理节点pcd_load.cpp时:
需要注意的依然是数据格式问题:订阅器查询时会调用回调函数(filter),将topic中的msg传递过去,所以输入是PointCloud2类型引用。因为各个滤波器的输入是指针而非点云数据,所以应该转换为指针:

```
pcl::PointCloud<pcl::PointXYZI>::Ptr scan_ptr(new pcl::PointCloud<pcl::PointXYZI>);
pcl::fromROSMsg(*cloud, *scan_ptr);
```
其中`new pcl::PointCloud<pcl::PointXYZI>(scan)`用于初始化指针指向scan类所在地址,也可不申明指向对象。

d)使用直通滤波器时,要分别进行x,y,z方向的输入设置,依然为指针。

  pcl::PassThrough<pcl::PointXYZI> pass;
  pass.setInputCloud(pcd_filtered_ptr);
  pass.setFilterFieldName("x");
  pass.setFilterLimits(-10.0,10.0);
  pass.filter(*pcd_filtered_ptr);

  pass.setInputCloud(pcd_filtered_ptr);
  pass.setFilterFieldName("y");
  pass.setFilterLimits(-5.0,5.0); 
  pass.filter(*pcd_filtered_ptr); 
  std::cerr << "Cloud after RoIfiltering: " << std::endl;
  std::cerr << *pcd_filtered_ptr << std::endl;

5.2.地面分割:

Ray Ground Filter的路面过滤方法。
SAC_RANSAC分割地面

#include<ros/ros.h>
#include<pcl/point_cloud.h>
#include<pcl_conversions/pcl_conversions.h>
#include<sensor_msgs/PointCloud2.h>
#include<pcl/io/pcd_io.h>

int  main(int argc,char **argv)
{
  ros::init (argc, argv, "pcd_pub_node"); 
  ros::NodeHandle nh;

  pcl::PointCloud<pcl::PointXYZI> cloud;
  sensor_msgs::PointCloud2 input;
 
  pcl::io::loadPCDFile ("/home/lijie/catkin_ws/src/pcd_load/13.pcd", cloud); 
  pcl::toROSMsg(cloud,input);

  input.header.frame_id="velodyne";   //是后面rviz的 fixed_frame
  ros::Publisher pcl_pub = nh.advertise<sensor_msgs::PointCloud2> ("pcd_input", 10);
  
  ros::Rate r(1);
  while(ros::ok())
  {
	  pcl_pub.publish(input);
	  ros::spinOnce();
	  r.sleep();
  }
  return 0;
 }

#include<ros/ros.h>
#include<pcl/point_cloud.h>
#include<pcl_conversions/pcl_conversions.h>
#include<sensor_msgs/PointCloud2.h>
#include<pcl/io/pcd_io.h>//which contains the required definitions to load and store point clouds to PCD and other file formats.
#include<pcl/filters/statistical_outlier_removal.h>
#include <pcl/point_types.h>
#include<pcl/filters/voxel_grid.h>

ros::Publisher pcl_pub;

void filter (const sensor_msgs::PointCloud2ConstPtr& cloud)
{
  // pcl::PointCloud<pcl::PointXYZ> scan;
  pcl::PointCloud<pcl::PointXYZI>::Ptr scan_ptr(new pcl::PointCloud<pcl::PointXYZI>);
  pcl::fromROSMsg(*cloud, *scan_ptr);
  std::cerr << "Cloud before filtering: " << std::endl;
  std::cerr << *scan_ptr<< std::endl;

  pcl::VoxelGrid<pcl::PointXYZI> vg;//体素滤波
  vg.setLeafSize (0.1,0.1,0.1);
  vg.setInputCloud(scan_ptr);   //输入为指针!!!!
  
  // pcl::PointCloud<pcl::PointXYZ> pcd_filtered;
  pcl::PointCloud<pcl::PointXYZI>::Ptr pcd_filtered_ptr(new pcl::PointCloud<pcl::PointXYZI>);
  vg.filter (*pcd_filtered_ptr);
  std::cerr << "Cloud after filtering: " << std::endl;
  std::cerr << *pcd_filtered_ptr << std::endl;

  pcl::StatisticalOutlierRemoval<pcl::PointXYZI> sor; //Kmeans滤波,参数临近点数目和距离阈值
  sor.setInputCloud(pcd_filtered_ptr);
  sor.setMeanK (20);
  sor.setStddevMulThresh(1.0);
  pcl::PointCloud<pcl::PointXYZI> pcd_filtereded;
  sor.filter (*pcd_filtered_ptr);

  sensor_msgs::PointCloud2 filter_output;
  pcl::toROSMsg(*pcd_filtered_ptr, filter_output);
  pcl_pub.publish (filter_output);
}


int main(int argc,char** argv)
{
  ros::init (argc, argv, "pcd_fileter_node"); //初始化
  ros::NodeHandle nh;
  ros::Subscriber sub = nh.subscribe ("pcd_input", 5, filter);
  pcl_pub = nh.advertise<sensor_msgs::PointCloud2> ("pcl_fileter_output", 5);
  
  ros::spin();
  return 0;
}
  • 1
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值