ROS相关学习
一、ROS中的标准计量单位和坐标规定
单位和坐标规定概念from–官网
Quantity | Unit |
---|---|
length | meter |
mass | kilogram |
time | second |
current (电流) | ampere ( 安,安培 ) |
angle | radian |
frequency | hertz |
force | newton |
power ( 功,能 ) | watt |
voltage | volt |
temperature | Celsius ( 摄氏度 ) |
magnetism | Tesla ( 磁感应强度单位 ) |
二、ROS库中的类
1、ros::nodehandle
创建订阅器、发布器、计时器和服务器、服务客户端的roscpp的接口。此类用于写入节点。它为该进程的节点提供了一个 RAII 接口,因为当创建第一个 NodeHandle 时,它会实例化此节点所需的所有内容,当最后一个 NodeHandle 超出范围时,它将关闭该节点。
请点击–> ROS中NodeHandle nh 与 NodeHandle nh(“~“) 区别
ros::init(argc, argv, "ist_node");
//初始化节点名字必须在最前面,如果ROS系统中出现重名,则之前的节点会被自动关闭
//如果想要多个重名节点而不报错,可以在init中添加ros::init_options::AnonymousName参数
//该参数会在原有节点名字的后面添加一些随机数来使每个节点独一无二
//ros::init(argc, argv, "my_node_name", ros::init_options::AnonymousName);
1.1 请点击–> ROS系列之Nodelet—基础知识
请点击–> ros-nodelet-from官网
nodelet简介:
使用ROS中nodelet包可以实现在同一个进程内同时运行多种算法,且算法之间通信开销零拷贝。这个包有2个重要的class:
1)提供了实现nodelet插件所必须的基类nodelet::Nodelet;
2)提供了NodeletLoader类用以实例化nodelet插件。由于nodelets实现了零拷贝,所以常常应用于大数据吞吐量场景,避免了多node通过ROSTCP通信带来的延时问题。
nodelets动态加载nodelet插件类到同一个node中实现了零拷贝, 加入进来的各个nodelet虽然在同一个进程内,但是由于nodelet拥有自己的命名空间,所以看似是一个个独立的node在存在。
nodelet技术原理:
1)nodelet包定义了一个基类nodelet::Nodelet,所有的nodelet插件类会继承这个基类,并通过pluginlib实现nodelet插件的动态加载;
2)存在一个nodelet_manager进程,可以把nodelet到加载到该manager内进行管理;
3)任何nodelet之间的通信可以使用零拷贝的roscpp publish完成,这种零拷贝实质上是使用了boost shared_ptr;
子类中使用的受保护成员和方法(如下):
std::string getName() //获取节点名称
ros::NodeHandle& getNodeHandle () // 获取节点句柄
ros::NodeHandle& getPrivateNodeHandle () //获取私有节点句柄(在其私有名称空间中提供此nodelets自定义重映射)
ros::NodeHandle& getMTNodeHandle () // 使用Multi Threaded获取节点句柄
ros::NodeHandle& getMTPrivateNodeHandle () //使用Multi Threaded回调队列获取私有节点句柄。 (在其私有命名空间中提供此nodelets自定义重映射)
ros::CallbackQueue& getMTCallbackQueue () // 获取回调队列(可从管理器获取线程池)。
std::vector<std::string> getMyArgv() //获取分离了ROS和nodelet特定args的nodelet命令行参数。
2、ros::master与ros::node
主节点(master)
负责节点到节点的连接和消息通信(节点管理器),类似于名称服务器(Name Server)。roscore是它的运行命令,当您运行主节点时,可以注册每个节点的名字,并根据需要获取信息。没有主节点,就不能在节点之间建立访问和消息交流(如话题和服务)。
主节点使用XML远程过程调用(XMLRPC,XML-Remote Procedure Call)与节点进行通信。XMLRPC是一种基于HTTP的协议,主节点不与连接到主节点的节点保持连接。换句话说,节点只有在需要注册自己的信息或向其他节点发送请求信息时才能访问主节点并获取信息。通常情况下,不检查彼此的连接状态。由于这些特点,ROS可用于非常大而复杂的环境。XMLRPC也非常轻便,支持多种编程语言,使其非常适合支持各种硬件和语言的ROS。
当启动ROS时,主节点将获取用户设置的ROS_MASTER_URI变量中列出的URI地址和端口。除非另外设置,默认情况下,URI地址使用当前的本地IP,端口使用11311。
普通节点(node)
它是指在ROS中运行的最小处理器单元。可以把它看作一个可执行程序。在ROS中,建议为一个目的创建一个节点,建议设计时注重可重用性。例如,在移动机器人的情况下,为了驱动机器人,将每个程序细分化。也就是说,使用传感器驱动、传感器数据转换、障碍物判断、电机驱动、编码器输入和导航等多个细分节点。 节点在运行的同时,向主节点注册节点的名称,并且还注册发布者(publisher)、订阅者(subscriber)、服务服务器(service server)、服务客户端(service client)的名称,且注册消息形式、URI地址和端口。基于这些信息,每个节点可以使用话题和服务与其他节点交换消息。 节点使用XMLRPC与主站进行通信,并使用TCP/IP通信系列的XMLRPC或TCPROS进行节点之间的通信。节点之间的连接请求和响应使用XMLRPC,而消息通信使用TCPROS,因为它是节点和节点之间的直接通信,与主节点无关。URI地址和端口则使用存储于运行当前节点的计算机上的名为ROS_HOSTNAME的环境变量作为URI地址,并将端口设置为任意的固有值。 ros节点是整个机器人控制系统的一个功能单元,运行起来一个ros节点,即运行一个ros程序包中的一个可执行文件。例如rosrun turtlesim turtle_teleop_key
ros系统在启动之前,首先需要运行rosore,我们可以将node看做ros操作系统上的应用软件。
3、ros::ParameterAdapter< M >
一般不宜外用。将函数参数类型调整为消息类型、事件类型和参数。允许您从事件类型中检索参数类型。
4、ros::package
包含头文件: #include <ros/package.h>
4.1 ros::📦:getPath()
作用:ros中用于获取某个功能包的绝对路径,当功能包不存在时,该函数返回一个空的字符串。其函数原型如下:
std::string ros::package::getPath (const std::string &package_name)
5、rosparam和ROS参数服务
请点击–> rosparam和ROS参数服务
三、ROS工具
1、rosbag
1.1、rosbag写入文件
rosbag::Bag bag;
bag.open("test.bag", rosbag::bagmode::Write);
std_msgs::String str;
str.data = std::string("foo");
std_msgs::Int32 i;
i.data = 42;
bag.write("chatter", ros::Time::now(), str);
//从ros::Time实例中获得当前时间ros::Time::now()
bag.write("numbers", ros::Time::now(), i);
bag.close();
1.2、rosbag读取文件
rosbag::Bag bag;
bag.open("test.bag", rosbag::bagmode::Read);
std::vector<std::string> topics;
topics.push_back(std::string("/chatter"));
topics.push_back(std::string("/numbers"));
//创建view,用于读取bag中的topic
rosbag::View view(bag, rosbag::TopicQuery(topics));//note:TopicQuery;TypeQuery
//rosbag::View view_all(view); //读取全部topic
//使用迭代器的方式遍历,注意:每一个迭代器为一帧数据
//rosbag::View::iterator it = view.begin();
foreach(rosbag::MessageInstance const m, view)
{
std_msgs::String::ConstPtr s = m.instantiate<std_msgs::String>();
if (s != NULL)
ASSERT_EQ(s->data, std::string("foo"));
std_msgs::Int32::ConstPtr i = m.instantiate<std_msgs::Int32>();
if (i != NULL)
ASSERT_EQ(i->data, 42);
}
bag.close();
1.3 改变ros bag 中消息的frame_id 和话题名
请点击–> 改变ros bag 中消息的frame_id 和话题名
示例:
rosbag play file.bag /foo:=/bar # /foo是原topic,/bar是新topic
步骤:
1.打开终端, 运行: roscore
2.打开终端, 运行: rosbag record -a
3.打开终端, 运行: rosbag play demo_hdl.bag /apollo/sensor/velodyne64/compensator/PointCloud2:=/velodyne_points
4.待bag播放完, 结束record: ctrl+c, 会在文件夹下生成新的bag包
1.4 rosbag record
请点击–> rosbag record 录包
2、roslaunch
2.1、launch文件相关知识
请点击-> ROS入门之——浅谈launch
2.2 roslaunch相关命令
roslaunch命令
我们知道,rosrun命令用于运行一个ROS节点,这个在简单程序中使用比较方便。但是在规模比较大的程序中,常常有几个或者几十个节点,这些节点之间彼此互有联系,协同达到软件正确执行的目的。这时候再使用rosrun命令的话,就会比较麻烦。此时,roslaunch命令闪亮登场了,它可以运行多个节点。并且roslaunch命令在运行节点时,还可以附加一些ROS命令选项,比如修改参数或节点的名称,设置节点的命名空间,设置ROS_ROOT及ROS_PACKAGE_PATH,以及环境变量修改等选项的ROS命令。
roslaunch命令的使用,需要先创建一个XML格式的xxx.launch文件,将要运行的节点以及系统中相关参数设置信息写在这个launch文件中,然后执行这个launch文件就可以了。【这里可以理解为launch文件就是一个脚本文件,要执行的操作都写在脚本文件中,执行脚本文件就OK了。】
roslaunch命令执行格式: roslaunch 功能包名称 launch文件 [参数设置]
这里roslaunch命令会在对应的功能包中找到名称匹配的launch文件,并执行这个launch文件。如果设置了参数的话,会将参数传入到launch文件中赋给对应的参数。
例如,执行vins_estimator功能包中的euroc.launch文件,命令如下:
roslaunch vins_estimator euroc.launch
如果在launch文件所在路径下执行该launch文件的话,就不需要加功能包名称了,因为此时是能直接找到launch文件的。
如果运行launch文件时需要设置参数,如下所示。arg为参数名称,value为给参数的赋值。
roslaunch my_file.launch arg:=value
注意:在执行roslaunch命令时,一定要先执行source命令:source /devel/setup.bash命令,否则找不到对应的包名称。
2.3 roslaunch 遇到的错误
出现问题:
RLException: [simple_launch] is neither a launch file in package [learning_launch] nor is [learning_launch] a launch file name
The traceback for the exception was written to the log file
解决办法 请点击–> 链接链接链接。
3、rosmsg
rosmsg是用于显示有关 ROS消息类型的 信息的命令行工具。
请点击–>ROS自定义msg类型及使用
rosmsg 演示
rosmsg show 显示消息描述 //例如:rosmsg show turtlesim/Pose
rosmsg info 显示消息信息
rosmsg list 列出所有消息
rosmsg md5 显示 md5 加密后的消息
rosmsg package 显示某个功能包下的所有消息
rosmsg packages 列出包含消息的功能包
4、 调参
dynamic_reconfigure
rqt_reconfigure
5、ROS_INFO与ROS_INFO_STREAM
请点击-> ROS_INFO与ROS_INFO_STREAM
四、坐标转换 tf(transform)
ROS中的坐标系及固定坐标姿态角(roll, pitch, yaw),右手坐标系。
RPY角,绕定轴 X ( Roll ) — Y ( Pitch ) — Z ( Yaw ) 旋转
~~~~~~~~-翻滚角~~~俯仰角~~~偏航角~~~
请点击-> 机器人RPY角和Euler角 – 基本公式(及转换)
1、tf相关知识
请点击-> ROS学习–轻松使用tf …vvvvv……ROS之 tf 空间坐标变换(tf)完全详解
tf中的类及函数 | 描述说明 | |
---|---|---|
Class tf::Matrix3x3 --from 官网 需包含头文件:#include <Matrix3x3.h> 该类的作用:Matrix3x3类实现了一个3x3旋转矩阵,用于结合四元数、变换和向量3执行线性代数。确保只包含一个没有缩放的纯正交矩阵。 | void tf::Matrix3x3::setRPY() | Set the matrix using RPY about XYZ fixed axes. Parameters: roll : Roll about X axis pitch: Pitch around Y axis yaw: Yaw aboud Z axis |
class tf::TransformBroadcaster --from官网 需包含头文件:#include <tf/transform_broadcaster.h> 该类的作用:帮助简化tf发布转换的任务 | ||
tf::Transform | ||
2、Rviz中 URDF,TF,base_link, map,odom和odom 主题的关系
请点击–> RViz中移动机器人来学习 URDF,TF,base_link, map,odom和odom 主题的关系------–from官网
3、rviz显示多传感器图像(坐标转换)
rosbag数据回放与rviz可视化tf设置及时间戳问题“Message removed because it is too old”:第(1)种 、第(2)种
请点击–> 多传感器ROS rviz显示,TF转换(如雷达和激光雷达)
请点击–> ROS tf工具与消息查看命令
五、通信机制-【订阅/发布、服务端/客户端】
ROS通信结构如下:
1、ros中message_filter类
1.1、请点击-> ros中message_filter类常用的使用方法
订阅者过滤器是对ROS订阅的封装,为其他过滤器提供源代码,订阅者过滤器无法将另一个过滤器的输出作为其输入,而是使用ROS主题作为其输入。
1. message_filters::Subscriber<std_msgs::UInt32> sub(nh, "my_topic", 1);
2. sub.registerCallback(myCallback);
可以认为等价于:
ros::Subscriber sub = nh.subscribe("my_topic", 1, myCallback);
请点击-> message_filter类使用(from官网)
请点击-> ROS中使用message_filters进行多传感器消息同步( 其中用到message_filters::Synchronizer )
注 意: 对齐传感信息时间戳有两种方式,一种是时间戳完全对齐 ExactTime Policy ,
另一种是时间戳相近 ApproximateTime Policy ,前者更为严格。
请点击-> ROS中的message_filter中不同传感器的时间同步
请点击-> message_filters 对齐多种传感器数据的时间戳
2、ros中 image_transport
请点击-> image_transport–from官网–可点击
头文件:image_transport/image_transport.h,这个头文件包括了所有的东西,无论是我们想要发布或者是订阅一个图像。
image_transport 与ros发布器的不同
image_transport 发布器为每个可用的传输,发布单独的ROS主题,而ROS publishers则为单个(单一)主题发布。主题名称遵循下面概述的标准命名约定。但是,请注意,所有代码接口都只使用“基本主题”名称(传输类型自动附加到该名称);通常,您不应该使用特定插件来直接引用特殊传输的主题。
2.1 image_transport::ImageTransport
新建一个ImageTransport实例,并使用NodeHandle进行初始化。我们使用ImageTransport的方法创建发布者和订阅者,就如我们使用ROS建立发布者和订阅者一样。
ros::NodeHandle nh;
image_transport::ImageTransport it(nh);
image_transport::Subscriber sub = it.subscribe("in_image_base_topic", 1, imageCallback);
image_transport::Publisher pub = it.advertise("out_image_base_topic", 1);
3、ros中的ros::Publisher类
3.1 ros::Publisher::getNumSubscribers
示例:
ros::Publisher pubOriginCloud = nh.advertise<sensor_msgs::PointCloud2>("lidar_cloud_origin", 2);
if(pubOriginCloud.getNumSubscribers()>0)
{
pcl::toROSMsg(lidar.gettotalorigincloud(), cloudmsg);
LOG(INFO)<<" time:"<<(ros::Time::now() - ros::Time(cloudmsg.header.stamp)).toSec();
if(fixframe)
cloudmsg.header.frame_id = "global_init_frame";
else
cloudmsg.header.frame_id = "vehicle_frame";
pubOriginCloud.publish(cloudmsg);
}
4、ROS多线程订阅消息
请点击-> ros::AsyncSpinner
六、消息、类、话题
1、sensor_msgs
请点击-> sensor_msgs中各类数据格式解析from官网
1.1 请点击-> sensor_msgs::LaserScan
sensor_msgs::LaserScan::ConstPtr
1.2 请点击-> sensor_msgs::CameraInfo的理解
区别并解释
sensor_msgs::CameraInfoConstPtr
sensor_msgs::CameraInfoPtr
2、image_geometry
image_geometry命名空间有两个类,分别为:PinholeCameraModel来自官网 和 StereoCameraModel来自官网
2.1 image_geometry::PinholeCameraModel
//示例
void getCameraRay(const image_geometry::PinholeCameraModel& model,
const cv::Point2d& pt, cv::Point3d* ray)
{
cv::Point2d rect_point;
rect_point = model.rectifyPoint(pt);
ROS_DEBUG("Rect Point: %f, %f",rect_point.x,rect_point.y);
*ray = model.projectPixelTo3dRay(rect_point);
}
2.2 image_geometry:: StereoCameraModel
3、visualization_msgs
请点击 -->visualization_msgs --from官网
3.1 visualization_msgs::Marker
(2)visualization_msgs::Marker消息数据格式from官网
4、geometry_msgs
请点击 -->geometry_msgs --from官网
此消息是与运动几何学相关的消息类型,包括速度,加速度等。
常用消息 geometry_msgs/TransformStamped
geometry_msgs::TransformStamped–from官网
5、pcl_msgs
请点击 -->from官网
pcl_msgs::ModelCoefficients :定义一个pcl转ros的模态系数类对象。
pcl::ModelCoefficients coefficients; //申明模型的参数
// 示例:把提取出来的内点形成的平面模型的参数发布出去
pcl_msgs::ModelCoefficients ros_coefficients;
pcl_conversions::fromPCL(coefficients, ros_coefficients);
pub.publish (ros_coefficients);
6、ros::topic
七、感知处理(相机与点云)
ROS相关函数总结
ROS相关函数总结 | 描述 |
---|---|
bool ros::NodeHandle::param() 动态换取参数 | 默认情况下,从参数服务器分配值。此方法尝试从参数服务器检索指定的参数值,并将结果存储在param_val中。如果无法从服务器检索该值,则使用默认值。 静态获取参数的话,可将配置参数存放在yaml文件中。 |
X、零碎知识汇总
1、编译error或fatal error
1.1 rosrun无法发现可执行文件
解决办法:CMakeLists.txt文件添加catkin_package() 或者修改执行文件的权限。
1.2 无法发现安装包或者fatal error:xxx.h no such file or directory
解决办法:缺少所依赖的安装包,通过如下指令进行安装:
sudo apt-get install ros-noetic-tf2-sensor-msgs
// 说明:noetic为对应ros版本,与本地相配
2、rqt–ROS GUI开发工具
请点击–> ROS学习(六):ROS GUI开发工具(rqt)
2.1 查看Image图像命令
命令:
rosrun rqt_image_view rqt_image_view
// 或者直接输入:rqt_image_view
2.2 如何看可视化的话题与节点
rosrun rqt_graph rqt_graph
// 可以打开一个界面观察节点与话题的关系 绿色和蓝色的是节点 红色的是话题
// 或者直接输入:rqt_graph
2.3 ROS中查看变量时间趋势线
命令:
rosrun rqt_plot rqt_plot
// 或者直接输入:rqt_plot
2.4 rqt_bag
3、 本地ros与远程ros通信
对本地的~/.bashrc(隐藏文件)进行修改,修改如下:
提示::使用时,注释其中一个。
source /opt/ros/melodic/setup.bash
#本地主机
export ROS_HOSTNAME=127.0.0.1
export ROS_MASTER_URI=http://127.0.0.1:11311 #11311为端口号
#远程主机
export ROS_HOSTNAME=190.10.10.1 #190.10.10.1为远程主机ip地址
export ROS_MASTER_URI=http://190.10.10.1:11311 #11311为端口号
4、ROS 中setup.bash
4.1 请点击–> source devel/setup.bash
5、从rosbag中提取(解析)数据
C++:从rosbag中提取图片和数据(内部另有github和csdn指导教程)
python:解析rosbag文件,得到带有时间戳的.jpg图片数据和.pcd点云数据
6、V-Rep虚拟机器人实验平台
下载完,解压到对应文件夹下,终端输入:./coppeliaSim.sh 。
7、 PlotJuggler绘图工具
请点击–> 【ROS学习】- PlotJuggler绘图工具的安装使用