ROS学习04.ROS中的常用组件

4.1 launch启动文件

启动文件(Launch File)是ROS中一种同时启动多个节点的途径,它还可以自动启动ROS Master节点管理器,并且可以实现每个节点的各种配置,为多个节点的操作提供很大便利。

4.1.1 基本元素

一个简单而完整的launch文件,采用XML的形式进行描述,包含一个根元素<launch> 和两个节点元素 <node>

 <launch>
    <node pkg="turtlesim" type="turtlesim_node" name="sim1"/>
    <node pkg="turtlesim" type="turtlesim_node" name="sim2"/>
  </launch>
  1. <launch>
    XML文件必须包含一个根元素,launch文件的根元素采用<launch>标签定义,文件中的其他内容必须包含在这个标签中。
  2. <node>
    启动文件的核心:是启动ROS节点。采用<node>标签定义。
    • pkg:定义节点所在的功能包名称。
    • type:定义节点的可执行文件名称
    • name:定义节点运行的名称,将覆盖节点中init()赋予节点的名称
    • output="screen":将节点的标准输出打印到终端屏幕,默认输出为日志文档。
    • respawn="true":复位属性,该节点停止时,会自动重启,默认为false。
    • required="true":必要节点,当该节点终止时,launch文件中的其他节点也别终止。
    • ns="namespace":命名空间,为节点内的相对名称添加命名空间前缀。
    • args="arguments":节点需要的输入参数。

在实际应用的launch文件中往往会更加复杂,使用的标签也会更多。除了上面介绍的<launch><node>外,<arg><param><remap>都是常用的标签元素。

4.1.2 参数设置

launch文件支持参数设置的功能。关于参数设置的标签元素有两个:<param>代表parameter、<arg>代表argument。

<param>

  • parameter是ROS系统运行中的参数,存储在参数服务器中。在launch文件中通过<param>元素加载parameter;在launch文件执行后,parameter就加载到ROS的参数服务器上。每个活跃的节点都可以通过ros::param::get()接口来获取parameter的值,用户也可以在终端中通过rosparam命令获取parameter的值。

  • 语法:

    <param name="output_frame" value="odom" />
    

    运行launch文件后,output_frame这个parameter的值设置为odom,并且加载到ROS参数服务器上了。
    但是,在复杂系统中参数很多,一个一个设置会非常麻烦,ROS也提供了另外一种类似的参数(<rosparam>)加载方式:

    <rosparam file="$(find 2dnav_pr2)/config/costmap_common_params.yaml" command="load"  ns="local_costmap" />
    

    <rosparam>可以将一个YAML格式文件中的参数全部加载到ROS参数服务器中,需要设置command属性为“load”,还可以选择设置命名空间“ns”。

<arg>

  • argument是另外一个概念,类似于launch文件内部的局部变量,仅限于launch文件使用,便于launch文件的重构,与ROS节点内部的实现没有关系。

  • 语法:

    <arg name="arg-name" default="arg-value" />
    

    launch文件中需要使用argument时,使用如下方式调用:

    <param name="foo" value="$(arg arg-name)" />
    <node name="node" pkg="package" type="type" args="$(arg arg-name)" />
    

4.1.3 重映射机制

ROS的设计目的:提高代码的复用率。
面对别人的功能包接口和自己的系统不兼容的问题,ROS提供了一种重映射机制。
简单说就是取别名:不需要修改别人的功能包接口,只需要将接口名称重映射一下,取一个别名,我们的系统就认识了(接口的数据类型必须相同)。
重映射功能的实现:launch文件中的<remap>标签。
例如:turtlebot的键盘控制节点发布的速度控制指令的话题可能是/turtlebot/cmd_vel,但是我们自己的机器人订阅的速度控制话题是/cmd_vel。这时使用<remap>就可以轻松解决问题,将/turtlebot/cmd_vel重映射为/cmd_vel,我们的机器人就可以接受到速度控制指令了:

<remap from="/turtlebot/cmd_vel"  to="/cmd_vel"/>\

注意:重映射机制在ROS中的使用非常广泛,也非常重要,方法不止一种,可以在终端实现重映射(参考03.ROS基础 3.8.3节)。

4.1.4 嵌套复用

在复杂系统中,launch文件很多,这些launch文件之间也会存在依赖关系。
如果直接复用一个已有launch文件中的内容,可以使用<include>标签包含其他launch文件:

<include file="$(dirname)/other.launch" />

launch是ROS框架中非常实用、灵活的功能,它类似于一种高级编程语言,可以帮助我们管理启动系统时的方方面面。在使用ROS的过程中,很多情况下我们并不需要编写大量代码,仅需要使用已有的功能包,编辑一下launch文件就可以完成很多机器人功能。

注意:更多高级的标签元素可以访问 roslaunchXML 来学习。

4.2 TF坐标变换

机器人本体和机器人的工作环境中往往存在大量的组件元素,在机器人设计和机器人应用中都会涉及不同组件的位置和姿态,这就需要引入坐标系以及坐标系变换的概念。
坐标变换时机器人系统中常用的基础功能,ROS中的坐标变换系统由TF功能包维护。

4.2.1 TF功能包

TF是一个让用户随时间跟踪多个坐标系的功能包,它使用树形数据结构,根据时间缓冲并维护多个坐标系之间的坐标变换关系,可以帮助开发者在任意时间、在坐标系间完成点、向量等坐标的变换。
TF可以在分布式系统中进行操作,也就是说,一个机器人系统中所有的坐标变换关系,对于所有的节点组件都是可用的,所有订阅TF消息的节点都会缓冲一份所有坐标系的变换关系数据,所有这种结构不需要中心服务器来存储任何数据。
使用TF功能包,总体来说需要以下两个步骤:

  • 监听TF变换
    接收并缓存系统中发布的所有坐标变换数据,并从中查询所需要的坐标变换关系。
  • 广播TF变换
    向系统中广播坐标系之间的坐标变换关系。系统中可能会存在多个不同部分的TF变换广播,每个广播都可以直接将坐标变换关系插入TF树中,不需要再进行同步。

4.2.2 TF工具

坐标系统虽然是一个基础理论,但是由于涉及多个空间之间的变换,不容易进行想象,所有TF提供了丰富的终端工具来帮助开发者调试和创建TF变换。

  1. tf_monitor
    功能:打印TF树中所有坐标系的发布状态,也可以输入参数来查看指定坐标系之间的发布状态。

    roslaunch learning_tf start_demo.launch 
    rosrun tf tf_monitor
    #可以查看指定坐标系之间的发布状态
    rosrun tf tf_monitor <source_frame> <target_frame>
    

    在这里插入图片描述图4-1 使用tf_monitor查看TF树中所有坐标系的发布状态

  2. tf_echo
    功能:查看指定坐标系之间的变换关系。

    rosrun tf tf_echo <source_frame> <target_frame>
    
  3. static_transform_publisher
    功能:发布两个坐标系之间的静态坐标变换,这两个坐标系不发生相对位置变化。

    rosrun tf static_transform_publisher x y z yaw pitch roll frame_id child_frame_id period_in_ms
    
    rosrun 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文件中使用:

    <launch>
    <node pkg="tf" type="static_transform_publisher" name="link1_broadcaster" args="1 0 0 0 0 0 1 link1_parent link1 100" />
    </launch>
    
  4. view_frames
    view_frames是可视化的调试工具,可以生成pdf文件,显示整颗TF树的信息。

    rosrun tf view_frames
    #使用如下命令,或者使用PDF阅读器查看生成的PDF文件
    evince frames.pdf
    

    在这里插入图片描述图4-2 使用view_frames工具生成TF树的信息

    在这里插入图片描述图4-3 可视化的TF树信息

    除此之外,rviz中还提供TF可视化显示的插件。

4.2.3 乌龟例程中的TF

安装乌龟仿真器中的turtle_tr功能包:

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、turtle1、turtle2。world是世界坐标系,作为系统的基础坐标系,其他坐标系都是相对该坐标系建立的,所以world是TF树的根节点。相对于world坐标系,又分别针对两只乌龟创建了两个乌龟坐标系,这两个坐标系的原点就是乌龟在世界坐标系下的坐标位置。

现在要让turtle2跟随turtle1运动,等价于turtle2坐标系需要向turtle1坐标系移动,这就需要知道turtle1和turtle2之间的坐标变换。三个坐标系之间的变换关系可以使用如下公式描述:

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_{turtle1\_turtle2}=T_{turtle1\_world}\times T_{world\_turtle2 } Tturtle1_turtle2=Tturtle1_world×Tworld_turtle2
使用tf_echo 工具在TF树中查找乌龟坐标系之间的变换关系:

rosrun tf tf_echo turtle1 turtle2

在这里插入图片描述图4-5 乌龟坐标系之间的变换关系

也可以通过rviz的图形界面更加形象地看到这三者之间的坐标关系:

rosrun rviz rviz -d 'rospack find turtle_tf' //rviz/turtle_rviz.rviz

在打开的rviz界面中,将Global Options选项下的Fixed Frame后面的坐标系改成world,然后通过左下角add按键,在By display type下面找到TF并添加。即可显示两只乌龟和世界坐标系之间的坐标关系。
在得到turtle2与turtle1之间的坐标变换后,就可以计算两只乌龟间的距离和角度,即可控制turtle2向turtle1移动了。
接下来,我们以这个例程为目标,学习如何实现TF的广播和监听功能。

4.2.4 创建TF广播器

首先,我们需要创建一个发布乌龟坐标系与世界坐标系之间TF变换的节点,实现源码/ros_primary/learning_tf/src/turtle_tf_broadcaster.cpp如下:

#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <turtlesim/Pose.h>

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消息的回调函数poseCallback,在广播TF消息之前需要定义tf::TransformBroadcaster广播器,然后根据乌龟当前的位姿设置tf::Transform类型的坐标变换,包含setOrigin设置的平移变换以及setRotation设置的旋转变换。
然后使用广播器将坐标变换插入TF树并进行发布,这里发布的TF消息类型是tf::StampedTransform,不仅包含tf::Transform类型的坐标变换、时间戳、而且需要指定坐标变换的源坐标系(parent)和目标坐标系(child)。

4.2.5 创建TF监听器

TF消息广播之后,其他节点就可以监听该TF消息了,从而获取需要的坐标变换了。目前我们已经将乌龟相对于world坐标系的TF变换进行了广播,接下来需要监听TF消息,并从中获取turtle2相对于turtle1坐标系的变换,从而控制turtle2移动。实现源码/ros_primary/learning_tf/src/turtle_tf_listener.cpp的详细内容如下:

#include <ros/ros.h>
#include <tf/transform_listener.h>
#include <geometry_msgs/Twist.h>
#include <turtlesim/Spawn.h>

int main(int argc, char** argv)
{
    // 初始化节点
    ros::init(argc, argv, "my_tf_listener");

    ros::NodeHandle node;

    // 通过服务调用,产生第二只乌龟turtle2
    ros::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;
};

该节点首先通过服务调用产生乌龟turtle2,然后声明控制turtle2速度的Publisher。在监听TF消息之前,需要创建一个tf::TransformListener类型的监听器,创建成功后监听器会自动接受TF树的消息,并且缓存10秒。然后在循环中就可以实时查找TF树中的坐标变化了。这里需要调用的是tf::TransformListener中的两个接口:

  • waitForTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration &timeout):给定源坐标系(source_frame)和目的坐标系(target_frame),等待两个坐标系之间指定时间(time)的变换关系,该函数会阻塞程序运行,所以要设置超时时间(timeout);
  • lookupTransform(const std::string & target_frame, const std::string & source_frame, const ros::Time & time, StampedTransform & transform):给定源坐标系(source_frame)和目标坐标系(target_frame),得到两个坐标系之间指定时间(time)的坐标变换(transform),ros::Time(0)表示我们想要的是最新一次的坐标变换。

通过以上两个接口的调用,就可以获得turtle2相对于turtle1的坐标变换了。然后根据坐标系之间的位置关系,计算得到turtle2需要运动的线速度和角速度,并发布速度控制指令使turtle2向turtle1移动。

4.2.6 实现乌龟跟随运动

以上小乌龟跟随例程的所有代码已经完成,下面来编写一个launch文件,使所有节点运行起来,实现源码learning_tf/launch/start_demo_with_listener.launch的详细内容如下:

<launch>
	<!--海龟仿真器-->
	<node pkg="turtlesim" type="turtlesim_node" name="sim" />
    <!--键盘控制-->
    <node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen" />

	<!--两只海龟的TF广播-->
	<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" />
	
	<!--监听TF广播,并且控制turtle2移动-->
	<node pkg="learning_tf" type="turtle_tf_listener" name="listener" />
</launch>

然后运行该launch文件,就可以看到与之前例程类似的两只乌龟的界面了,在终端中通过键盘控制turtle1移动,turtle2也跟随移动。
通过这个例程的实现,学习了TF广播与监听的实现方法,在实际应用中会产生更多的坐标系,TF树的结构也会更加复杂,但是基本的使用方法依然相同。

4.3 QT工具箱

为了方便可视化调试和显示,ROS提供了一个Qt架构的后台图形工具套件——rqt_common_plugins,其中包含不少实用工具。
安装Qt工具箱:

sudo apt-get install ros-melodic-rqt
sudo apt-get install ros-melodic-rqt-common-plugins

4.3.1 日志输出工具(rqt_console)

rqt_console工具用来图形化显示和过滤ROS系统运行状态中的所有日志消息,包括info、warn、error等级别的日志。使用如下命令启动该工具:

rqt_console

在这里插入图片描述图4-6 rqt_console工具界面

当系统中有不同级别的日志消息时,rqt_console的界面就会依次显示这些日志的相关内容,包括日志内容、时间戳、级别等。当日志较多时,也可以使用该工具进行过滤显示。

4.3.2 计算图可视化工具(rqt_graph)

rqt_graph工具可以图形化显示当前ROS系统中的计算图。在系统运行时,使用如下命令启动该工具:

rqt_graph

在这里插入图片描述图4-7 rqt_graph 工具界面

4.3.3 数据绘图工具(rqt_plot)

rqt_plot是一个二维数值曲线绘制工具,可以将需要显示的数据在xy坐标系中使用曲线描绘。使用如下命令启动该工具:

rqt_plot

然后在界面上方的Topic输入框中输入需要显示的话题消息,如果不确定话题名称,可以在终端中使用“rostopic lsit”命令查看。
在这里插入图片描述图4-8 rqt_plot工具

4.3.4 参数动态配置工具(rqt_reconfigure)

rqt_reconfigure工具可以在不重启系统的情况下,动态配置ROS系统中的参数,但是该功能的使用需要在代码中设置参数的相关属性,从而支持动态配置。使用如下命令启动该工具:

rosrun rqt_reconfigure rqt_reconfigure

在这里插入图片描述图4-9 rqt_reconfigure工具界面

启动后的界面将显示当前系统中所有可动态配置的参数。在界面中使用输入框、滑动条或下拉框进行设置即可实现参数的动态配置。关于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主界面主要包含以下几个部分:

  • 0:3D视图区,用于可视化显示数据,目前没有任何数据,所以显示黑色。
  • 1:工具栏,用于提供视角控制、目标设置、发布地点等工具。
  • 2:显示项列表,用于显示当前选择的显示插件,可以配置每个插件的属性
  • 3:视角设置区,用于选择多种观察视角
  • 4:时间显示区,用于显示当前的系统时间和ROS时间。

4.4.2 数据可视化

假设需要可视化的数据以对应的消息类型发布,我们在rviz中使用相应的插件订阅该消息即可实现显示。

  1. 添加需要显示数据的插件。
    点击rviz界面左侧下方的“Add”按钮,rviz会将默认支持的所有数据类型的显示插件罗列出来。
    在这里插入图片描述
    图4-11 rviz默认支持的显示插件

在上图所示的列表中选择需要的数据类型插件,然后在“Display Name”文本框中填入一个唯一的名称,用来识别显示的数据。
2. 添加完成后,rviz左侧的Displays中会列出已经添加的显示插件
点击插件列表前的加号,可以打开一个属性列表,根据需求设置属性。一般情况下,“Topic”属性较为重要,用来声明该显示插件所订阅的数据来源。如果订阅成功,在中间的显示区应该会出现可视化后的数据。
在这里插入图片描述
图4-12 点云数据的详情

  1. 如果显示有问题,请检查属性区域的“Status”状态。Status有四种状态:OK、Warning、Error和Disabled,如果显示的状态不是OK,那么请查看错误信息,并仔细检查数据发布是否正常。
    在这里插入图片描述图4-13 显示插件的Status信息

4.4.3 插件扩展机制

rviz是一个三维可视化平台,默认可以显示如表4-1所示的通用类型数据,其中包含坐标轴、摄像头图像、地图、激光等数据。
rviz默认支持显示的数据类型详见《ROS机器人开发实际》4.4.3节。
并且作为一个平台,rviz支持插件扩展机制,为默认显示的数据提供相应的插件。如果需要添加其他数据的显示,也可以通过编写插件的形式进行添加。我们甚至可以基于rviz打造一款自己的人机交互软件。

4.5 Gazebo仿真环境

Gazebo是一个功能强大的三维物理仿真平台,具备强大的物理引擎、高质量的图形渲染、方便的编程与图形接口,最重要的还有其具备开源免费的特性。虽然Gazebo中的机器人模型与rviz使用的模型相同,但是需要在模型中加入机器人和周围环境的物理属性,例如质量、摩擦系数、弹性系数等。机器人的传感器信息也可以通过插件的形式加入仿真环境、以可视化的方式显示。

4.5.1 Gazebo的特点

Gazebo是一个优秀的开源物理仿真环境,它具备如下特点:

  1. 动力学仿真:支持多种高性能的物理引擎,如ODE、Bullet、SimBody、DART等。
  2. 三维可视化环境:支持显示逼真的三维环境,包括光线、纹理、影子。
  3. 传感器仿真:支持传感器数据的仿真,同时可以仿真传感器噪声。
  4. 可扩展插件:用户可以定制化开发插件以扩展Gazebo的功能,满足个性化的需求。
  5. 多种机器人模型:官方提供PR2、Pioneer2 DX、TurtleBot等机器人模型,当然也可以使用自己创建的机器人模型。
  6. TCP/IP传输:Gazebo的后台仿真处理和前台图形显示可以通过网络通信实现远程仿真。
  7. 云仿真:Gazebo仿真可以在Amazon、Softlayer等云端运行,也可以在自己搭建的云服务器上运行。
  8. 终端工具:用户可以使用Gazebo提供的命令行工具在终端实现仿真控制。

Gazebo的社区维护非常积极,版本变化较大,但是在兼容性方面依然保证得较好。

4.5.2 安装并运行Gazebo

与rviz一样,如果已经安装了桌面完整版的ROS,可以直接跳过这一步。否则,使用如下命令安装:

sudo apt-get install ros-melodic-gazebo-ros-pkgs ros-melodic-gazebo-ros-control

安装完成后,在终端使用如下命令启动ROS和Gazebo:

roscore
rosrun gazebo_ros gazebo

主界面主要包含以下几个部分:

  1. 3D视图区
  2. 工具栏
  3. 模型列表
  4. 模型属性项
  5. 时间显示区

验证Gazebo是否与ROS系统连接成功,可以查看ROS的话题列表:

rostopic list

如果连接成功,应该可以看到Gazebo发布/订阅的话题列表。

当然,还有Gazebo提供的服务列表:

rosservice list

4.5.3 构建仿真环境

在仿真之前需要构建一个仿真环境。Gazebo中有两种创建仿真环境的方法。

  1. 直接插入模型
    在Gazebo左侧的模型列表中,有一个insert选项罗列了所有可使用的模型。选择需要使用的模型,放置在主显示区中,就可以在仿真环境中添加机器人和外部物体等仿真实例。
    备注:模型的加载需要连接国外网站,为了保证模型顺利加载,可以提前将模型文件下载并放置到本地路径“~/.gazebo/models”下,模型文件的下载地址为“https://bitbucket.org/osrf/gazebo_models/downloads/”。

  2. Building Editor
    第二种方法是使用Gazebo提供的Building Editor工具手动绘制地图。在Gazebo菜单栏中选择Edit——>Building Editor,选择左侧的绘制选项,然后在上侧窗口中使用鼠标绘制,下侧窗口中即可实时显示绘制的仿真环境。
    模型创建完成后就可以加载机器人模型并进行仿真了。后续会详细学习机器人仿真的过程,这里先对Gazebo有一个整体的认识即可。

4.6 rosbag数据记录和回放

为了方便调试测试,ROS提供了数据记录与回放的功能包——rosbag,可以帮助开发者收集ROS系统运行时的消息数据,然后在离线状态下回放。
本节通过乌龟例程介绍rosbag数据记录和回放的实现方法。

4.6.1 记录数据

首先启动键盘控制乌龟例程所需的所有节点:

roscore
rosrun turtlesim turtlesim_node
rosrun turtlesim turtle_teleop_key

启动成功后,可以看到界面中的小乌龟,此时可以在终端中通过键盘控制乌龟移动。
查看当前ROS系统中的话题:

rostopic list -v

接下来使用rosbag抓取这些话题的消息,并且打包成一个文件放置到指定文件夹中:

mkdir ~/bagfiles
cd ~/bagfiles
rosbag record -a

rosbag record就是数据记录的命令,-a(all)参数意为记录所有发表的消息。现在,消息记录已经开始,我们可以在终端中控制小乌龟移动一段时间,然后在数据记录运行的终端中按下“Ctrl+C”,即可终止数据记录。新生成的数据记录文件保存在新建的~/bagfiles文件夹中。

4.6.2 回放数据

数据记录完成后,可以使用该数据记录文件进行数据回放。rosbag功能包提供了info命令,可以查看数据记录文件的详细信息,命令的使用格式如下:

rosbag info <your bagfile>

使用该info命令来查看之前生成的数据记录文件。

从以上信息中可以看到,数据记录包中包含的所有话题、消息类型、消息数量等信息。终止之前打开的turtle_teleop_key控制节点并重启turtlesim_node,使用如下命令回放所记录的话题数据:

rosbag play <your bagfile>

在短暂的等待时间后,数据开始回放,小乌龟的运动规矩应该与之前数据记录的状态完全相同。

4.7 本章小结

提问如下:

  1. 如果我们希望一次性启动并配置多个ROS节点,应该使用什么方法?
  2. ROS中的TF是如何管理系统中繁杂的坐标系的,我们又该如果使用TF广播、监听系统中的坐标变化的?
  3. Qt工具箱为我们提供了哪些可视化工具?
  4. rviz是什么,它又可以实现哪些功能?
  5. 如果我们没有真实机器人,那么有没有办法在ROS中通过仿真的方式来学习ROS开发呢?需要用到什么工具?
  6. 机器人往往涉及重复性调试工作,我们有没有办法使用ROS记录调试过程中的数据,并进行离线分析呢?
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页