ROS学习04.ROS中的常用组件
目录 4.2 TF坐标变换 4.3 QT工具箱 4.4 rviz三维可视化平台 4.5 仿真环境 4.6 数据记录和回放 4.7 本章小结
4.1 启动文件
启动文件( File)是ROS中一种同时启动多个节点的途径,它还可以自动启动ROS 节点管理器,并且可以实现每个节点的各种配置,为多个节点的操作提供很大便利。
4.1.1 基本元素
一个简单而完整的文件,采用XML的形式进行描述,包含一个根元素 和两个节点元素 :
<launch><node pkg="turtlesim" type="turtlesim_node" name="sim1"/><node pkg="turtlesim" type="turtlesim_node" name="sim2"/>launch>
XML文件必须包含一个根元素,文件的根元素采用标签定义,文件中的其他内容必须包含在这个标签中。
启动文件的核心:是启动ROS节点。采用标签定义。
在实际应用的文件中往往会更加复杂,使用的标签也会更多。除了上面介绍的和外,、
、都是常用的标签元素。
4.1.2 参数设置
文件支持参数设置的功能。关于参数设置的标签元素有两个:
代表、代表。
:
:
4.1.3 重映射机制
ROS的设计目的:提高代码的复用率。
面对别人的功能包接口和自己的系统不兼容的问题,ROS提供了一种重映射机制。
简单说就是取别名:不需要修改别人的功能包接口,只需要将接口名称重映射一下,取一个别名,我们的系统就认识了(接口的数据类型必须相同)。
重映射功能的实现:文件中的标签。
例如:的键盘控制节点发布的速度控制指令的话题可能是//,但是我们自己的机器人订阅的速度控制话题是/。这时使用就可以轻松解决问题,将//重映射为/,我们的机器人就可以接受到速度控制指令了:
<remap from="/turtlebot/cmd_vel" to="/cmd_vel"/>\
注意:重映射机制在ROS中的使用非常广泛,也非常重要,方法不止一种,可以在终端实现重映射(参考03.ROS基础 3.8.3节)。
4.1.4 嵌套复用
在复杂系统中,文件很多,这些文件之间也会存在依赖关系。
如果直接复用一个已有文件中的内容,可以使用标签包含其他文件:
<include file="$(dirname)/other.launch" />
是ROS框架中非常实用、灵活的功能,它类似于一种高级编程语言,可以帮助我们管理启动系统时的方方面面。在使用ROS的过程中,很多情况下我们并不需要编写大量代码,仅需要使用已有的功能包,编辑一下文件就可以完成很多机器人功能。
注意:更多高级的标签元素可以访问 来学习。
4.2 TF坐标变换
机器人本体和机器人的工作环境中往往存在大量的组件元素,在机器人设计和机器人应用中都会涉及不同组件的位置和姿态,这就需要引入坐标系以及坐标系变换的概念。
坐标变换时机器人系统中常用的基础功能,ROS中的坐标变换系统由TF功能包维护。
4.2.1 TF功能包
TF是一个让用户随时间跟踪多个坐标系的功能包,它使用树形数据结构,根据时间缓冲并维护多个坐标系之间的坐标变换关系,可以帮助开发者在任意时间、在坐标系间完成点、向量等坐标的变换。
TF可以在分布式系统中进行操作,也就是说,一个机器人系统中所有的坐标变换关系,对于所有的节点组件都是可用的,所有订阅TF消息的节点都会缓冲一份所有坐标系的变换关系数据,所有这种结构不需要中心服务器来存储任何数据。
使用TF功能包,总体来说需要以下两个步骤:
4.2.2 TF工具
坐标系统虽然是一个基础理论,但是由于涉及多个空间之间的变换,不容易进行想象,所有TF提供了丰富的终端工具来帮助开发者调试和创建TF变换。
功能:打印TF树中所有坐标系的发布状态,也可以输入参数来查看指定坐标系之间的发布状态。
roslaunch learning_tf start_demo.launch
rosrun tf tf_monitor
#可以查看指定坐标系之间的发布状态
rosrun tf tf_monitor <source_frame> <target_frame>
图4-1 使用查看TF树中所有坐标系的发布状态
功能:查看指定坐标系之间的变换关系。
rosrun tf tf_echo <source_frame> <target_frame>
功能:发布两个坐标系之间的静态坐标变换,这两个坐标系不发生相对位置变化。
rosrun tf static_transform_publisher x y z yaw pitch roll frame_id child_frame_id period_in_msrosrun tf static_transform_publisher x y z qx qy qz qw frame_id child_frame_id period_in_ms
以上两种命令格式,需要设置坐标的偏移参数和旋转参数:偏移参数使用相对于x、y、z三轴的坐标位移;而旋转参数的第一种命令格式使用以弧度为单位的yaw/pitch/roll角度(yaw是围绕z轴旋转的偏航角,pitch是围绕y轴旋转的俯仰角,roll是围绕x轴旋转的翻滚角),第二种命令格式使用四元数表达旋转角度。发布频率以ms为单位。
该命令也可在文件中使用:
<launch>
<node pkg="tf" type="static_transform_publisher" name="link1_broadcaster" args="1 0 0 0 0 0 1 link1_parent link1 100" />
launch>
是可视化的调试工具,可以生成pdf文件,显示整颗TF树的信息。
rosrun tf view_frames
#使用如下命令,或者使用PDF阅读器查看生成的PDF文件
evince frames.pdf
图4-2 使用工具生成TF树的信息
图4-3 可视化的TF树信息
除此之外,rviz中还提供TF可视化显示的插件。
4.2.3 乌龟例程中的TF
安装乌龟仿真器中的功能包:
sudo apt-get install ros-melodic-turtle-tf
安装完成后,可以运行如下命令:
roslaunch turtle_tf turtle_tf_demo.launch
乌龟仿真器打开后会出现两只小乌龟,并且下方的小乌龟会自动向中心位置的小乌龟移动。
打开键盘控制节点,控制中心位置的小乌龟运行:
rosrun turtlesim turtle_teleop_key
另外一只小乌龟总会跟随我们控制的那种乌龟运行。
在这个例程中的TF是如何运用的呢?
首先使用TF工具来查看TF树:
rosrun tf view_frames
图4-4 乌龟跟随例程中的TF树
如上图所示:在当前系统中存在三个坐标系:world、、。world是世界坐标系,作为系统的基础坐标系,其他坐标系都是相对该坐标系建立的,所以world是TF树的根节点。相对于world坐标系,又分别针对两只乌龟创建了两个乌龟坐标系,这两个坐标系的原点就是乌龟在世界坐标系下的坐标位置。
现在要让跟随运动,等价于坐标系需要向坐标系移动,这就需要知道和之间的坐标变换。三个坐标系之间的变换关系可以使用如下公式描述:
T t u r t l e 1 _ t u r t l e 2 = T t u r t l e 1 _ w o r l d × T w o r l d _ t u r t l e 2 T_{\}=T_{\}\times T_{world\ } =×
使用 工具在TF树中查找乌龟坐标系之间的变换关系:
rosrun tf tf_echo turtle1 turtle2
图4-5 乌龟坐标系之间的变换关系
也可以通过rviz的图形界面更加形象地看到这三者之间的坐标关系:
rosrun rviz rviz -d 'rospack find turtle_tf' //rviz/turtle_rviz.rviz
在打开的rviz界面中,将 选项下的Fixed Frame后面的坐标系改成world,然后通过左下角add按键,在By type下面找到TF并添加。即可显示两只乌龟和世界坐标系之间的坐标关系。
在得到与之间的坐标变换后,就可以计算两只乌龟间的距离和角度,即可控制向移动了。
接下来,我们以这个例程为目标,学习如何实现TF的广播和监听功能。
4.2.4 创建TF广播器
首先,我们需要创建一个发布乌龟坐标系与世界坐标系之间TF变换的节点,实现源码///src/r.cpp如下:
#include
#include
#include std::string turtle_name;void poseCallback(const turtlesim::PoseConstPtr& msg)
{// tf广播器static tf::TransformBroadcaster br;// 根据乌龟当前的位姿,设置相对于世界坐标系的坐标变换tf::Transform transform;transform.setOrigin( tf::Vector3(msg->x, msg->y, 0.0) );tf::Quaternion q;q.setRPY(0, 0, msg->theta);transform.setRotation(q);// 发布坐标变换br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", turtle_name));
}int main(int argc, char** argv)
{// 初始化节点ros::init(argc, argv, "my_tf_broadcaster");if (argc != 2){ROS_ERROR("need turtle name as argument"); return -1;};turtle_name = argv[1];// 订阅乌龟的pose信息ros::NodeHandle node;ros::Subscriber sub = node.subscribe(turtle_name+"/pose", 10, &poseCallback);ros::spin();return 0;
};
以上代码的关键部分是处理乌龟pose消息的回调函数,在广播TF消息之前需要定义tf::广播器,然后根据乌龟当前的位姿设置tf::类型的坐标变换,包含设置的平移变换以及设置的旋转变换。
然后使用广播器将坐标变换插入TF树并进行发布,这里发布的TF消息类型是tf::,不仅包含tf::类型的坐标变换、时间戳、而且需要指定坐标变换的源坐标系()和目标坐标系(child)。
4.2.5 创建TF监听器
TF消息广播之后,其他节点就可以监听该TF消息了,从而获取需要的坐标变换了。目前我们已经将乌龟相对于world坐标系的TF变换进行了广播,接下来需要监听TF消息,并从中获取相对于坐标系的变换,从而控制移动。实现源码///src/.cpp的详细内容如下:
#include
#include
#include
#include int main(int argc, char** argv)
{// 初始化节点ros::init(argc, argv, "my_tf_listener");ros::NodeHandle node;// 通过服务调用,产生第二只乌龟turtle2ros::service::waitForService("spawn");ros::ServiceClient add_turtle =node.serviceClient<turtlesim::Spawn>("spawn");turtlesim::Spawn srv;add_turtle.call(srv);// 定义turtle2的速度控制发布器ros::Publisher turtle_vel =node.advertise<geometry_msgs::Twist>("turtle2/cmd_vel", 10);// tf监听器tf::TransformListener listener;ros::Rate rate(10.0);while (node.ok()){tf::StampedTransform transform;try{// 查找turtle2与turtle1的坐标变换listener.waitForTransform("/turtle2", "/turtle1", ros::Time(0), ros::Duration(3.0));listener.lookupTransform("/turtle2", "/turtle1", ros::Time(0), transform);}catch (tf::TransformException &ex) {ROS_ERROR("%s",ex.what());ros::Duration(1.0).sleep();continue;}// 根据turtle1和turtle2之间的坐标变换,计算turtle2需要运动的线速度和角速度// 并发布速度控制指令,使turtle2向turtle1移动geometry_msgs::Twist vel_msg;vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(),transform.getOrigin().x());vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) +pow(transform.getOrigin().y(), 2));turtle_vel.publish(vel_msg);rate.sleep();}return 0;
};
该节点首先通过服务调用产生乌龟,然后声明控制速度的。在监听TF消息之前,需要创建一个tf::类型的监听器,创建成功后监听器会自动接受TF树的消息,并且缓存10秒。然后在循环中就可以实时查找TF树中的坐标变化了。这里需要调用的是tf::中的两个接口:
通过以上两个接口的调用,就可以获得相对于的坐标变换了。然后根据坐标系之间的位置关系,计算得到需要运动的线速度和角速度,并发布速度控制指令使向移动。
4.2.6 实现乌龟跟随运动
以上小乌龟跟随例程的所有代码已经完成,下面来编写一个文件,使所有节点运行起来,实现源码//ener.的详细内容如下:
<launch><node pkg="turtlesim" type="turtlesim_node" name="sim" /><node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen" /><node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle1" name="turtle1_tf_broadcaster" /><node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle2" name="turtle2_tf_broadcaster" /><node pkg="learning_tf" type="turtle_tf_listener" name="listener" />
launch>
然后运行该文件,就可以看到与之前例程类似的两只乌龟的界面了,在终端中通过键盘控制移动,也跟随移动。
通过这个例程的实现,学习了TF广播与监听的实现方法,在实际应用中会产生更多的坐标系,TF树的结构也会更加复杂,但是基本的使用方法依然相同。
4.3 QT工具箱
为了方便可视化调试和显示,ROS提供了一个Qt架构的后台图形工具套件——,其中包含不少实用工具。
安装Qt工具箱:
sudo apt-get install ros-melodic-rqt
sudo apt-get install ros-melodic-rqt-common-plugins
4.3.1 日志输出工具()
工具用来图形化显示和过滤ROS系统运行状态中的所有日志消息,包括info、warn、error等级别的日志。使用如下命令启动该工具:
rqt_console
图4-6 工具界面
当系统中有不同级别的日志消息时,的界面就会依次显示这些日志的相关内容,包括日志内容、时间戳、级别等。当日志较多时,也可以使用该工具进行过滤显示。
4.3.2 计算图可视化工具()
工具可以图形化显示当前ROS系统中的计算图。在系统运行时,使用如下命令启动该工具:
rqt_graph
图4-7 工具界面
4.3.3 数据绘图工具()
是一个二维数值曲线绘制工具,可以将需要显示的数据在xy坐标系中使用曲线描绘。使用如下命令启动该工具:
rqt_plot
然后在界面上方的Topic输入框中输入需要显示的话题消息,如果不确定话题名称,可以在终端中使用“ lsit”命令查看。
图4-8 工具
4.3.4 参数动态配置工具()
工具可以在不重启系统的情况下,动态配置ROS系统中的参数,但是该功能的使用需要在代码中设置参数的相关属性,从而支持动态配置。使用如下命令启动该工具:
rosrun rqt_reconfigure rqt_reconfigure
图4-9 工具界面
启动后的界面将显示当前系统中所有可动态配置的参数。在界面中使用输入框、滑动条或下拉框进行设置即可实现参数的动态配置。关于ROS参数动态配置功能的实现,将在后续进行具体讲解。
4.4 rviz三维可视化平台
机器人系统中存在大量数据,比如图像数据中0~255的RGB值。但是这种数据形态的值往往不利于开发者感受数据所描述的内容,所有常常需要将数据可视化显示,例如机器人模型的可视化、图像数据的可视化、地图数据的可视化等。
ROS针对机器人系统的可视化需求,为用户提供了一款显示多种数据的三维可视化平台——rviz。
rviz是一款三维可视化工具,很好地兼容了各种基于ROS软件框架的机器人平台。在rviz中,可以使用XML对机器人、周围物体等任何实物进行尺寸、质量、位置、材质、关节等属性的描述,并且在界面中呈现出来。同时,rviz还可以通过图形化方式,实时显示机器人传感器的信息、机器人的运动状态、周围环境的变化等。总而言之,rviz可以帮助开发者实现所有可监测信息的图形化显示,开发者也可以在rviz的控制界面下,通过按钮、滑动条、数值等方式控制机器人的行为。
4.4.1 安装并运行rviz
rviz已经集成到桌面完整版的ROS中,如果已经成功安装桌面完整版的ROS,可以直接跳过这一步。否则,使用如下命令安装:
sudo apt-get install ros-melodic-rviz
安装完成后,分别在终端运行如下命令,启动ROS和rviz平台:
roscore
rosrun rviz rviz
启动rviz主界面:
图4-10 rviz的主界面
rviz主界面主要包含以下几个部分:
4.4.2 数据可视化
假设需要可视化的数据以对应的消息类型发布,我们在rviz中使用相应的插件订阅该消息即可实现显示。
添加需要显示数据的插件。
点击rviz界面左侧下方的“Add”按钮,rviz会将默认支持的所有数据类型的显示插件罗列出来。
图4-11 rviz默认支持的显示插件
在上图所示的列表中选择需要的数据类型插件,然后在“ Name”文本框中填入一个唯一的名称,用来识别显示的数据。
2. 添加完成后,rviz左侧的中会列出已经添加的显示插件
点击插件列表前的加号,可以打开一个属性列表,根据需求设置属性。一般情况下,“Topic”属性较为重要,用来声明该显示插件所订阅的数据来源。如果订阅成功,在中间的显示区应该会出现可视化后的数据。
图4-12 点云数据的详情
如果显示有问题,请检查属性区域的“”状态。有四种状态:OK、、Error和,如果显示的状态不是OK,那么请查看错误信息,并仔细检查数据发布是否正常。
图4-13 显示插件的信息 4.4.3 插件扩展机制
rviz是一个三维可视化平台,默认可以显示如表4-1所示的通用类型数据,其中包含坐标轴、摄像头图像、地图、激光等数据。
rviz默认支持显示的数据类型详见《ROS机器人开发实际》4.4.3节。
并且作为一个平台,rviz支持插件扩展机制,为默认显示的数据提供相应的插件。如果需要添加其他数据的显示,也可以通过编写插件的形式进行添加。我们甚至可以基于rviz打造一款自己的人机交互软件。
4.5 仿真环境
是一个功能强大的三维物理仿真平台,具备强大的物理引擎、高质量的图形渲染、方便的编程与图形接口,最重要的还有其具备开源免费的特性。虽然中的机器人模型与rviz使用的模型相同,但是需要在模型中加入机器人和周围环境的物理属性,例如质量、摩擦系数、弹性系数等。机器人的传感器信息也可以通过插件的形式加入仿真环境、以可视化的方式显示。
4.5.1 的特点
是一个优秀的开源物理仿真环境,它具备如下特点:
动力学仿真:支持多种高性能的物理引擎,如ODE、、、DART等。三维可视化环境:支持显示逼真的三维环境,包括光线、纹理、影子。传感器仿真:支持传感器数据的仿真,同时可以仿真传感器噪声。可扩展插件:用户可以定制化开发插件以扩展的功能,满足个性化的需求。多种机器人模型:官方提供PR2、 DX、等机器人模型,当然也可以使用自己创建的机器人模型。TCP/IP传输:的后台仿真处理和前台图形显示可以通过网络通信实现远程仿真。云仿真:仿真可以在、等云端运行,也可以在自己搭建的云服务器上运行。终端工具:用户可以使用提供的命令行工具在终端实现仿真控制。
的社区维护非常积极,版本变化较大,但是在兼容性方面依然保证得较好。
4.5.2 安装并运行
与rviz一样,如果已经安装了桌面完整版的ROS,可以直接跳过这一步。否则,使用如下命令安装:
sudo apt-get install ros-melodic-gazebo-ros-pkgs ros-melodic-gazebo-ros-control
安装完成后,在终端使用如下命令启动ROS和:
roscore
rosrun gazebo_ros gazebo
主界面主要包含以下几个部分:
3D视图区工具栏模型列表模型属性项时间显示区
验证是否与ROS系统连接成功,可以查看ROS的话题列表:
rostopic list
如果连接成功,应该可以看到发布/订阅的话题列表。
当然,还有提供的服务列表:
rosservice list
4.5.3 构建仿真环境
在仿真之前需要构建一个仿真环境。中有两种创建仿真环境的方法。
直接插入模型
在左侧的模型列表中,有一个选项罗列了所有可使用的模型。选择需要使用的模型,放置在主显示区中,就可以在仿真环境中添加机器人和外部物体等仿真实例。
备注:模型的加载需要连接国外网站,为了保证模型顺利加载,可以提前将模型文件下载并放置到本地路径“~/./”下,模型文件的下载地址为“”。
第二种方法是使用提供的 工具手动绘制地图。在菜单栏中选择Edit——> ,选择左侧的绘制选项,然后在上侧窗口中使用鼠标绘制,下侧窗口中即可实时显示绘制的仿真环境。
模型创建完成后就可以加载机器人模型并进行仿真了。后续会详细学习机器人仿真的过程,这里先对有一个整体的认识即可。
4.6 数据记录和回放
为了方便调试测试,ROS提供了数据记录与回放的功能包——,可以帮助开发者收集ROS系统运行时的消息数据,然后在离线状态下回放。
本节通过乌龟例程介绍数据记录和回放的实现方法。
4.6.1 记录数据
首先启动键盘控制乌龟例程所需的所有节点:
roscore
rosrun turtlesim turtlesim_node
rosrun turtlesim turtle_teleop_key
启动成功后,可以看到界面中的小乌龟,此时可以在终端中通过键盘控制乌龟移动。
查看当前ROS系统中的话题:
rostopic list -v
接下来使用抓取这些话题的消息,并且打包成一个文件放置到指定文件夹中:
mkdir ~/bagfiles
cd ~/bagfiles
rosbag record -a
就是数据记录的命令,-a(all)参数意为记录所有发表的消息。现在,消息记录已经开始,我们可以在终端中控制小乌龟移动一段时间,然后在数据记录运行的终端中按下“Ctrl+C”,即可终止数据记录。新生成的数据记录文件保存在新建的~/文件夹中。
4.6.2 回放数据
数据记录完成后,可以使用该数据记录文件进行数据回放。功能包提供了info命令,可以查看数据记录文件的详细信息,命令的使用格式如下:
rosbag info <your bagfile>
使用该info命令来查看之前生成的数据记录文件。
从以上信息中可以看到,数据记录包中包含的所有话题、消息类型、消息数量等信息。终止之前打开的控制节点并重启,使用如下命令回放所记录的话题数据:
rosbag play <your bagfile>
在短暂的等待时间后,数据开始回放,小乌龟的运动规矩应该与之前数据记录的状态完全相同。
4.7 本章小结
提问如下:
如果我们希望一次性启动并配置多个ROS节点,应该使用什么方法?ROS中的TF是如何管理系统中繁杂的坐标系的,我们又该如果使用TF广播、监听系统中的坐标变化的?Qt工具箱为我们提供了哪些可视化工具?rviz是什么,它又可以实现哪些功能?如果我们没有真实机器人,那么有没有办法在ROS中通过仿真的方式来学习ROS开发呢?需要用到什么工具?机器人往往涉及重复性调试工作,我们有没有办法使用ROS记录调试过程中的数据,并进行离线分析呢?