3、常用命令与工具3.1、启动节点方式3.1.1、launch文件3.1.2、rosrun3.1.3、python3.1.4、启动一个小乌龟3.1.5、启动两个小乌龟3.2、launch文件3.2.1、概述3.2.1、文件的格式1.标签【node】2.标签【remap】3.标签【include】4.标签【arg】5.变量替换6.标签【param】7.标签【rosparam】8.标签【group】3.3、TF坐标变换3.3.1、tf常用工具1.view_frames工具2.rqt_tf_tree工具3.tf_echo工具4.static_transform_publisher5.roswtf plugin3.3.2、常用的坐标系3.4、rqt(QT工具)1.rqt_graph计算图可视化2.rqt_topic 查看话题3.rqt_publisher4.rqt_plot数据绘图6.rqt_console日志输出7.rqt_reconfigure动态参数配置3.5、Rviz3.6、ROS常用命令
用roslaunch命令启动 launch 文件至少有两种方式:
1)、借助 ros package 路径启动
格式如下:
roslaunch package名称 launch文件名称
roslaunch pkg_name launchfile_name.launch
2)、直接给出 launch 文件的绝对路径
格式如下:
xxxxxxxxxx
roslaunch path_to_launchfile
不论用上述哪种方式启动 launch 文件,都可以在后边添加参数,比较常见的参数有
--screen
: 令 ros node 的信息(如果有的话)输出到屏幕上,而不是保存在某个 log 文件中,这样比较方便调试arg:=value
: 如果 launch 文件中有待赋值的变量,可以通过这种方式赋值,例如:xxxxxxxxxx
roslaunch pkg_name launchfile_name model:=urdf/myfile.urdf # launch file 中有参数 “model” 需要赋值
或
xxxxxxxxxx
roslaunch pkg_name launchfile_name model:='$(find urdf_pkg)/urdf/myfile.urdf' # 用 find 命令提供路径
roslaunch 命令运行时首先会检测系统的rosmaster
是否运行,如果已经启动,就用现有的 rosmaster
;如果没有启动,会先启动rosmaster
,然后再执行 launch 文件中的设置,一次性把多个节点按照我们预先的配置启动起来。
需要注意的是, launch 文件不需要编译,设置好之后可以直接用上述方式运行。
必须先启动节点管理器(master),master 是用来管理系统中的很多进程的,每个node启动时都要向master注册管理node之间的通信。master启动后再去通过master注册每一个node节点。在Ubuntu终端中输入命令:
xxxxxxxxxx
roscore
node的启动,rosrun+包名+节点名;rosrun方法每次只能运行一个节点。
xxxxxxxxxx
rosrun [--prefix cmd] [--debug] pkg_name node_name [ARGS]
rosrun将会寻找package的名为executable的可执行程序,将可选参数ARGS传入。
如果是python代码,可以直接在py文件所在目录下直接启动,注意区分python2和python3。
xxxxxxxxxx
roscore
rosrun turtlesim turtlesim_node # 启动小海龟仿真器节点
rosrun turtlesim turtle_teleop_key # 启动小海龟键盘控制器节点
启动完成后,可以通过键盘输入操控小海龟移动,键盘操控时,光标一定要在【rosrun turtlesim turtle_teleop_key】这个命令行下,点击键盘【上】、【下】、【左】、【右】控制小海龟移动。
并且在rosrun turtlesim turtlesim_node 终端会打印一些小海龟的日志信息
xxxxxxxxxx
[ INFO] [1607648666.226328691]: Starting turtlesim with node name /turtlesim
[ INFO] [1607648666.229275030]: Spawning turtle [turtle1] at x=[5.544445], y=[5.544445], theta=[0.000000]
安装功能包
xxxxxxxxxx
sudo apt install ros-melodic-turtle-tf
启动
xxxxxxxxxx
roslaunch turtle_tf turtle_tf_demo.launch
键盘控制节点
xxxxxxxxxx
rosrun turtlesim turtle_teleop_key
此时,按下键盘【上】、【下】、【左】、【右】驱动小乌龟运动;可以观察到一只小乌龟跟随另一只运动。
在ROS中一个节点程序一般只能完成功能单一的任务,但是一个完整的ROS机器人一般由很多个节点程序同时运行、相互协作才能完成复杂的任务,因此这就要求在启动机器人时就必须要启动很多个节点程序,如果一个 node 一个 node 的启动,比较麻烦。通过 launch文件以及 roslaunch 命令可以一次性启动多个 node,方便“一键启动”,并且可以设置丰富的参数。
launch 文件本质上是一种 xml 文件,在某些编辑器中可以高亮显示关键字,方便阅读,可以在头部添加,也可不添加
xxxxxxxxxx
与其他 xml 格式的文件类似,launch 文件也是通过标签 (tag) 的方式书写, 主要的 tag 如下:
xxxxxxxxxx
<launch> <!--根标签-->
<node> <!--需要启动的node及其参数-->
<include> <!--包含其他launch-->
<machine> <!--指定运行的机器-->
<env-loader> <!--设置环境变量-->
<param> <!--定义参数到参数服务器-->
<rosparam> <!--加载yaml文件中的参数到参数服务器-->
<arg> <!--定义变量-->
<remap> <!--设定topic映射-->
<group> <!--设定分组-->
</launch> <!--根标签-->
标签【node】是 launch 文件的核心部分。
xxxxxxxxxx
<launch>
<node pkg="package_name" type="executable_file" name="node_name"/>
<node pkg="another_package" type="another_executable" name="another_node"></node>
...
</launch>
其中
pkg
是节点所在的 package 名称type
是 package 中的可执行文件,如果是 python 编写的,就可能是 .py文件,如果是 c++ 编写的,就是源文件编译之后的可执行文件的名字。name
是节点启动之后的名字, 每一个节点都要有自己独一无二的名字。注意: roslaunch 不能保证 node 的启动顺序,因此 launch 文件中所有的 node 都应该对启动顺序有鲁棒性。
还可以设置更多参数,如下:
xxxxxxxxxx
<launch>
<node
pkg=""
type=""
name=""
respawn="true"
required="true"
launch-prefix="xterm -e"
output="screen"
ns="namespace"
/>
</launch>
上述命令中,
respawn
:若该节点关闭,是否自动重新启动
required
:若该节点关闭,是否关闭其他所有节点
launch-prefix
: 是否新开一个窗口执行。例如,需要通过窗口进行机器人移动控制的时候,应该为控制 node 新开一个窗口;或者当 node 有些信息输出,不希望与其他 node 信息混杂在一起的时候。
output
:默认情况下,launch 启动 node 的信息会存入下面的 log 文件中,可以通过此处参数设置,令信息显示在屏幕上
xxxxxxxxxx
/.ros/log/
ns
:将 node 归入不同的 namespace,即在 node name 前边加 ns
指定的前缀。为了实现这类操作,在 node 源文件中定义 node name 和 topic name 时要采用 relative name, 即不加符号 /
。
计算图源的名称分为:
1)基础名称,例如:topic
2)全局名称,例如:/A/topic
3)相对名称,例如:A/topic
4)私有名称,例如:~topic
在发布或者定阅时,有这么一行代码
xxxxxxxxxx
ros::init(argc, argv, "publish_node");
ros::NodeHandle nh;
ros::Publisher pub = nh.advertise<std_msgs::string>("topic",1000);
经常作为node 标签的子标签出现,可以用来修改topic。在很多rosnode源文件中,可能并没有指定接收的或者发送的topic,而仅仅是用 input_topic
和 output_topic
代替,这样在使用中需要将抽象的topic名字替换成具体场景中的 topic 名字。
简单地说, remap 的作用就是方便同一个 node 文件被应用到不同的环境中,用 remap 从外部修改一下 topic 即可,不需要改变源文件。
remap 常见的使用格式如下:
xxxxxxxxxx
<node pkg="some" type="some" name="some">
<remap from="origin" to="new" />
</node>
这个标签的作用是将另外一个 launch 文件添加到本 launch 文件中,类似 launch 文件的嵌套。基本格式:
xxxxxxxxxx
<include file="path-to-launch-file" />
上边的文件路径可以给具体路径,但是一般来说为了程序的可移植性,最好借助 find
命令给出文件路径:
xxxxxxxxxx
<include file="$(find package-name)/launch-file-name" />
上述命令中,$(find package-name)
等价于本机中相应 package 的路径。这样即使换了其他主控,只要安装了同样的 package,就可以找到对应的路径。
有时,另一个 launch 引入的 node 可能需要统一命名,或者具有类似特征的 node 名字,比如 /my/gps, /my/lidar, /my/imu,即 node 具有统一的前缀,方便查找。这可以通过设置 ns
(namespace)属性来实现,命令如下:
xxxxxxxxxx
<include file="$(find package-name)/launch-file-name " ns="my" />
通过【arg】可以使参数重复使用,也便于多处同时修改。 【arg】三种常用方法:
<arg name="foo">
: 声明一个 【arg】,但不赋值。稍后可以通过命令行赋值,或者通过【include】标签赋值。<arg name="foo" default="1">
: 赋默认值。<arg name="foo" value="1">
: 赋固定值。通过命令行赋值
xxxxxxxxxx
roslaunch package_name file_name.launch arg1:=value1 arg2:=value2
在 launch 文件中常用的变量替换形式有两个
$(find pkg)
: 例如$(find rospy)/manifest.xml
. 如果可能,强烈推荐这种基于 package 的路径设置$(arg arg_name)
: 先设置默认值,如果没有额外的赋值,就用这个默认值了例如:
xxxxxxxxxx
<arg name="gui" default="true" />
<!-- 先设置默认值,如果没有额外的赋值,就用这个默认值了 -->
<param name="use_gui" value="$(arg gui)"/>
另一个例子:
xxxxxxxxxx
<node pkg="package_name" type="executable_file" name="node_name" args="$(arg a) $(arg b)" />
这样设置之后,在启动 roslaunch 时,可以为 args 参数赋值
xxxxxxxxxx
roslaunch package_name file_name.launch a:=1 b:=5
与【arg 】不同,【param】是共享的,并且它的取值不仅限于value,还可以是文件,甚至是一行命令。
格式
xxxxxxxxxx
<param name="param_name" type="type1" value="val"/> # type可以省略,系统自动判断
<param name="param_name" textfile="$(find pkg)/path/file"/> # 读取 file 存成 string
<param name="param_name" command="$(find pkg)/exe '$(find pkg)/arg.txt'"/>
实例:
<param name="param" type="yaml" command="cat '$(find pkg)/*.yaml'"/> # command 的结果存在 param 中
【param】可以是在全局范围中,它的 name 就是原本的 name,也可以在某个更小的范围中,比如 node,那么它在全局的名字就是 node/param 形式.
例如在全局范围中定义如下 param
xxxxxxxxxx
<param name="publish_frequency" type="double" value="10.0" />
再在 node 范围中定义如下 param
xxxxxxxxxx
<node name="node1" pkg="pkg1" type="exe1">
<param name="param1" value="False"/>
</node>
如果用 rosparam list
列出server 中的 【param】,则有
xxxxxxxxxx
/publish_frequency
/node1/param1 # 自动加上了namespace 前缀
注意:虽然 【param】名字前加了 namespace,但是依然全局范围
【param】只能对单个 【param】操作,而且只有三种:value、textfile、command 形式,返回的是单个 【param】的内容。 【rosparam】则可以批量操作,还包括一些对参数设置的命令,如 dump、delete 等
load : 从 YAML 文件中加载一批 param,格式如下:
xxxxxxxxxx
<rosparam command="load" file="$(find rosparam)/example.yaml" />
delete: 删除某个 param
xxxxxxxxxx
<rosparam command="delete" param="my_param" />
类似【param】的赋值操作
xxxxxxxxxx
<rosparam param="my_param">[1,2,3,4]</rosparam>
或者
xxxxxxxxxx
<rosparam>
a: 1
b: 2
</rosparam>
【rosparam】也可以放在【node】中, 此时 【param】名字前边都加上 node namespace.
如果要对多个node进行同样的设置,比如都在同一个特定的namespace,remap相同的topic等,可以用【group】。在【group】中可以使用所有常见的标签进行设置,例如
xxxxxxxxxx
<group ns="rosbot">
<remap from="chatter" to="talker"/> # 对该 group 中后续所有 node 都有效
<node ... />
<node ... >
<remap from="chatter" to="talker1"/> # 各个 node 中可以重新设置 remap
</node>
</group>
tf是一个允许用户随时跟踪多个坐标系的功能包。tf维护实时缓冲的树结构中的坐标帧之间的关系,并允许用户在任意两个坐标帧之间任意时间点上转换点、向量等。
Tf包就是把某个点在某一个坐标系的坐标转换为另外一个坐标系的坐标,传感器可以看做一个坐标系,机器可以看做一个坐标系,障碍物可以看做一个点。
在【3.1.5】启动两个小乌龟后,执行下面操作。
能够监听当前时刻所有通过ROS广播的tf坐标系,并绘制出树状图表示坐标系之间的连接关系,生成名为frame.pdf文件,保存到本地当前位置。
xxxxxxxxxx
rosrun tf view_frames
虽然view_frames能够将当前坐标系关系保存在离线文件中,但是无法实时反映坐标关系,所以可以用rqt_tf_tree实时刷新显示坐标系关系
xxxxxxxxxx
rosrun rqt_tf_tree rqt_tf_tree
使用tf_echo工具可以查看两个广播参考系之间的关系。
xxxxxxxxxx
rosrun tf tf_echo <source_frame> <target_frame>
打印从source_frame到target_frame的旋转平移变换;例如:
xxxxxxxxxx
rosrun tf tf_echo turtle1 turtle2
发布两个坐标系之间的静态坐标变换,这两个坐标系不发生相对位置变化。命令格式:
xxxxxxxxxx
static_transform_publisher x y z yaw pitch roll frame_id child_frame_id period_in_ms
static_transform_publisher x y z qx qy qz qw frame_id child_frame_id period_in_ms
在launch中使用:
xxxxxxxxxx
<launch>
<node pkg="tf" type="static_transform_publisher" name="link1_broadcaster" args="1 0 0 0 0 0 1 link1_parent link1 100" />
</launch>
一个插件,分析你当前的tf配置并试图找出常见问题。
xxxxxxxxxx
roswtf
常用的坐标系也就是frame_id,有map,odom,base_link,base_footprint,base_laser等。
该map坐标系是一个世界固定坐标系,其Z轴指向上方。相对于map坐标系的移动平台的姿态,不应该随时间显著移动。map坐标是不连续的,这意味着在map坐标系中移动平台的姿态可以随时发生离散的跳变。典型的设置中,定位模块基于传感器的监测,不断的重新计算世界坐标中机器人的位姿,从而消除偏差,但是当新的传感器信息到达时可能会跳变。map坐标系作为长期的全局参考是很有用的,但是跳变使得对于本地传感和执行器来说,其实是一个不好的参考坐标。
odom是一个全局坐标系,通过里程计记录机器人当前的运动姿态。在odom 坐标系中移动平台的位姿可以任意移动,没有任何界限,使得odom 坐标系不能作为长期的全局参考。这里要区分开odom topic,这是两个概念,一个是坐标系,一个是根据编码器(或者视觉等)计算的里程计。但是两者也有关系,odom topic 转化得位姿矩阵是odom–>base_link的tf关系。odom和map坐标系在机器人运动开始是重合的。但是,随着时间的推移是不重合的,而出现的偏差就是里程计的累积误差。在一些校正传感器合作校正的package比如amcl会给出一个位置估计(localization),这可以得到map–>base_link的tf,所以估计位置和里程计位置的偏差也就是odom与map的坐标系偏差。如果你的odom计算没有错误,那么map–>odom的tf就是0。odom 坐标系作为短期的本地参考是很有用的,但偏移使得它不能作为长期参考。
机器人本体(基座)坐标系与机器人中心重合,坐标系原点一般为机器人的旋转中心。
base_footprint:原点为base_link原点在地面的投影,有些许区别(z值不同)。
在机器人系统中,我们使用一棵树来来关联所有坐标系,因此每个坐标系都有一个父坐标系和任意子坐标系,如下:map --> odom --> base_link世界坐标系是odom坐标系的父,odom坐标系是base_link的父。虽然直观来说,map和odom应连接到base_link,这是不允许的,因为每坐标系只能有一个父类。
odom到base_link的转换是由里程计源计算和发布的。然而,定位模块不发布map到base_link的转换(transform)。相反,定位模块先接收odom到base_link的 transform,并使用这个信息发布map到odom的transform。
打开命令行窗口输入rosrun rqt
然后双击Tab
键,便可查看ROS中QT工具包含的内容,如下图所示:
接下来我们以小海龟为例简单的介绍一下常用的几种QT工具:
打开命令行窗口输入以下命令,弹出一个对话窗。
xxxxxxxxxx
rosrun rqt_graph rqt_graph
从图像中我们可以很清晰的看得出/teleop_turtle
节点通过/turtle1/cmd_vel
话题给/turtlesim
节点进行数据传递。
/teleop_turtle
为具备Publisher(发布)功能的节点。
/turtlesim
为具备Subscriber(订阅)功能的节点。
/turtle1/cmd_vel
为publisher和subscriber通讯的话题。
xxxxxxxxxx
rosrun rqt_topic rqt_topic
通过该工具,我们可以清楚地看到小海龟的一些实时变化的信息。
rqt_publisher提供了一个GUI插件,用于发布具有固定或计算字段值的任意消息。打开命令行窗口输入以下命令,弹出一个对话窗。
xxxxxxxxxx
rosrun rqt_publisher rqt_publisher
点击Topic
右边的选择框找到我们需要的/turtle1/cmd_vel
话题,点击右侧加号添加,显示如下:
xxxxxxxxxx
rosrun rqt_plot rqt_plot
ROS 日志 (log) 系统的功能是让程序生成一些日志消息,显示在屏幕上、发送到特定 topic 或者储存在特定 log 文件中,以方便调试、记录、报警等。
序号 | 等级 | 解析 |
---|---|---|
1 | DEBUG | 调试日志,供开发测试使用 |
2 | INFO | 常规日志,用户可见级别的信息 |
3 | WARN | 警告信息。 |
4 | ERROR | 错误信息。程序出错后打印的信息 |
5 | FATAL | 致命错误。出现宕机的日志记录 |
ROS 中的日志消息按照严重性由低到高可以分为 5 级:DEBUG、INFO、WARN、ERROR、FATAL。只要程序可以运行就不需要注意,但 ERROR 和 FATAL 出现就表示程序存在着严重问题导致无法运行。
xxxxxxxxxx
rosrun rqt_console rqt_console
日志输出工具属于ROS日志框架(logging framework)的一部分,用来显示节点的输出信息,从图上我们可以看出它再提示小海龟已经撞墙啦。
C++基础API格式 | C++stream API格式 | Python日志API |
---|---|---|
ROS_DEBUG("打印的内容"); | ROS_DEBUG_STREAM("打印的内容" << "hello"); | rospy.logdebug("打印的内容") |
ROS_INFO("打印的内容"); | ROS_INFO_STREAM("打印的内容" << "hello"); | rospy.loginfo("打印的内容") |
ROS_WARN("打印的内容"); | ROS_WARN_STREAM("打印的内容" << "hello"); | rospy.logwarn("打印的内容") |
ROS_ERROR("打印的内容"); | ROS_ERROR_STREAM("打印的内容" << "hello"); | rospy.logerror("打印的内容") |
ROS_FATAL("打印的内容"); | ROS_FATAL_STREAM("打印的内容" << "hello"); | rospy.logfatal("打印的内容") |
xxxxxxxxxx
rosrun rqt_reconfigure rqt_reconfigure
图片来源ROS wiki:
rviz是ros自带的一个图形化工具,可以方便的对ros的程序进行图形化操作。其使用也是比较简单。
【Set initial pose】、【Set target pose】、【Publish location point】:一般在建图导航时使用。
rviz界面主要包含以下几个部分:
1:3D视图区,用于可视化显示数据,目前没有任何数据,所以显示黑色。
2:工具栏,提供视角控制、目标设置、发布地点等工具。
3:显示项列表,用于显示当前选择的显示插件,可以配置每个插件的属性。
4:视角设置区,可以选择多种观测视角。
5:时间显示区,显示当前的系统时间和ROS时间。
第一步:点击【Add】按钮。会弹出一个选框。
第二步:可以通过显示类型【By display type】选择添加,不过需要自己修改对应话题,坐标系才可以显示出来;也可以通过选择话题【By topic】的方式,直接添加就可以正常显示。
第三步:点击【OK】即可。
命令 | 作用 |
---|---|
catin_create_pkg | 创建功能包的信息 |
rospack | 获取功能包的信息 |
catkin_make | 编译工作空间中的功能包 |
rosdep | 自动安装功能包依赖的其他包 |
roscd | 功能包目录跳转 |
roscp | 拷贝功能包中的文件 |
rosed | 编辑功能包中的文件 |
rosrun | 运行功能包中的可执行文件 |
roslaunch | 运行启动文件 |