1 什么情况下会用到namespace(以下简称ns)
当我们需要运行同一个pkg的同一个node,虽然可以在launch文件中给他们命名成不同的name但是,我们希望使用<group ns=""></group>来更加清晰的区分他们之间的不同。但是加上ns后,常常会出现以下问题,需要我们解决。比如,原先不添加ns的时候一切运行正常,但是当我们添加ns后,无法运行等一类问题。
2 理解什么是namespace
ns就是把你原先运行的pkg---node放到一个命名空间中去,这个命名空间就是ns,例如:
<launch>
<group ns="name1">
<node pkg="your_pkg" type="your_node_name" name="whatever" />
</group>
<group ns="name2">
<node pkg="your_pkg" type="your_node_name" name="whatever" />
</group>
</launch>
我们运行的pkg---node---name都可以一样,但是必须在不同的ns中,这样ROS才可以区分他们,否则会认为重复,第二个node会覆盖掉第一个node,这样始终只有一个node在运行。
在rosnode list 你可以看到:
/name1/whatever
/name2/whatever
而在rostopic list中,所有话题也会被追加上name1和name2
3 添加namespace后提示tf,no laser scan data等问题
这就是由于第二2节中的ns改变了原来会话题的名字。例如,在添加ns之前,该node需要订阅 /scan的雷达数据,但是添加ns后,雷达的数据发布的话题追加了ns的命名空间,变成了/name1/scan ,这时候你再订阅/scan,肯定是没有数据的,因为不存在/scan这个话题了,雷达发布的数据话题从/scan变成了/name1/scan。解决办法是使用<remap from="/name1/scan" to="/scan" />,这样的重映射才会使得数据订阅发布之间重新构建正确的关系。
同样,你可以通过查看rqt_graph来确认你的node是否都正确的订阅了你的话题,哪些需要remap的,可以很清晰的查阅到。
4 发现你的话题无论怎么remap,rqt_graph都不发生改变,还是原来的话题
这看起来显示remap失效了,然而运行launch时没有报错,又表明你的话题参数都是存在切正确的。
没错,这个也困扰了我很久。
4.1 在使用remap时。要注意remap的作用范围,remap只能在<node />,<group /><launch />
如果你放在<include />里面不会报错也没有警告,但是命令行会显示说,“无效的remap”仔细看可以看到。
注意这里说的在<node />,<group /><launch />下可以有效的使用remap,是在直接tag标签下,间接地也是不行的。例如:
<launch>
.......
<remap from="xx" to="xx" />
</launch>
这个叫做在<launch>标签下直接使用,是合法有效的。
但是下面这种就是在<launch>标签下间接使用,在<include>下直接使用,这样是无效的。但是运行不会提示error和warnning。这一点要十分注意。
<launch>
.......
<include file="$(find pkg)/.....">
<remap from="xx" to="xx" />
</include>
</launch>
4.2 在解决4.1的正确使用remap后,如果问题仍然没有解决,那么就是你的remap没有正确的寻找到你的话题
这是由于你的话题,你没有使用绝对路径导致的。例如:
<launch>
<node pkg="your_pkg" type="your_node_name" name="whatever">
<remap from="name1/scan" to="scan" />
</node>
</launch>
这样remap后,如果你的话题没有成功的建立订阅关系,即让rqt_graph的图中name1/scan话题还存在,你的订阅没有连接到/scan话题上,那么就是话题的绝对路径导致的ROS系统未能找到指定的话题,这个在运行launch时也不会有error和warnning提示。解决办法就是在话题前加上“/”即可。例如:
<launch>
<node pkg="your_pkg" type="your_node_name" name="whatever">
<remap from="/name1/scan" to="/scan" />
</node>
</launch>
这样添加上“/”,话题的路径就变成绝对路径了。问题就解决了。
5 从yaml文件像launch文件传递参数
5.1 什么是yaml文件
这个概念自行查找。总结来说就是,yaml文件存放的是一个字典(可以粗糙的这样理解,不完全合理!),它有键值对成对出现,同样也可以是嵌套的字典。例如
1.yaml
var1: 12
var2: name
var3: base_link
2.yaml
var1: 2323
var2: {
scan_frame: robot0_laser0
topic: robot0/laser_0
}
var3: robot0
1.yaml是比较典型的没有嵌套,2.yaml中的var2是嵌套,他的值又是由一个字典组成。
5.2 yaml文件中的所有的键都可以理解成变量,值就是这些变量的初始值,是可以通过rosparam set改变的。当我们在launch文件中load这个yaml文件时就是,将这些变量添加到ROS的参数服务器,并且按照yaml文件中的值,给这些变量赋予初始值。
这就不难理解了,yaml文件中的建就是ROS参数服务器中的参数。因此在launch文件中,load一个yaml文件后,可以直接通过<param name=" " value=" " />来修改yaml文件中的值,
<launch>
<rosparam file="$(find your_pkg)/1.yaml" command="load" />
<param name="var1" value="1222222" />
</launch>
这样就实现了yaml文件像launch文件传递参数的功能:
当然你也可以这样:
<launch>
<arg name="var1_value" default="33333" />
<rosparam file="$(find your_pkg)/1.yaml" command="load" />
<param name="var1" value="$(arg var1_value)" />
</launch>
在ROS的官网,官方也给出了一种方法,我测试过和上面的效果一样。
如下所示:
rosparam 有一个属性叫做subst_value,如果设置成true就可以直接修改yaml文件中的参数默认值。
例子如下:
<launch>
<arg name="whitelist" default="[3, 2]"/>
<rosparam commond="load" file="$(find your_pkg)/...">
<rosparam param="whitelist" subst_value="True">$(arg whitelist)</rosparam>
</launch>
这也是完全正确的。