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的软件使用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::fromROSMsg
和 pcl::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_depend
和 run_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;
}