ROS:关于节点和节点句柄以及命名空间
参考资料:ROS官方文档
首先,我们需要明确的是 节点 和 节点句柄 是不同的。一般而言,一个cpp文件只能启动一个ROS节点,但作为该节点的句柄却可以设置多个。
The
ros::NodeHandle
class serves two purposes. First, it provides RAII-style startup and shutdown of the internal node inside a roscpp program. Second, it provides an extra layer of namespace resolution that can make writing subcomponents easier.
如上所言,节点句柄类有两个作用:
- 在一个
roscpp
程序中,节点句柄可以启动或关闭一个ROS内部节点; - 节点句柄可以增加一层命名空间,可以为编写组件提供便利。
1.启动或关闭节点
创建一个节点句柄最简单的方式如下所示:
ros::NodeHandle nh;
在创建节点句柄时,若内部节点还未启动,则创建的句柄会启动该节点。一旦该节点所有的句柄实例(同一个cpp程序下创建的都是同一个节点的句柄)都被销毁,则该节点也会自动关闭。这句话也从侧面说明了,一个节点可以创建多个句柄。
On creation, if the internal node has not been started already,
ros::NodeHandle
will start the node. Once allros::NodeHandle
instances have been destroyed, the node will be automatically shutdown.
2.命名空间
节点句柄的另一个构造函数形式可以让我们自定义命名空间:
ros::NodeHandle nh("my_ns"); // <node_namespace>/my_ns
- 若存在节点命名空间,如在launch文件中启动该节点时加入
ns="node_ns"
,则命名空间为node_ns/my_ns
; - 若不存在节点命名空间,则为
my_ns
。
另外也可以创建多个节点句柄,然后为某个句柄设置父节点句柄:
ros::NodeHandle nh1("ns1"); // <node_namespace>/ns1
ros::NodeHandle nh2(nh1, "ns2"); // <node_namespace>/ns1/ns2
此外,还有两种命名方式:
-
全局命名
ros::NodeHandle nh("/my_global_namespace"); // /my_global_namespace(不受外部命名影响)
注意:在ROS的命名中,加或不加
/
是存在区别的。 若加上/
,说明这是一个全局命名,则无法再被放入一个命名空间当中;若不加/
,则可以通过如launch中设置ns
,使得该命名被放入到该命名空间当中。比如,我定义了两个发布器,发布话题分别为/cmd_vel
与cmd_vel
,此外若外部还存在一个命名空间为dwa_planner
,则它们的命名分别变为/cmd_vel
=>/cmd_vel
cmd_vel
=>/dwa_planner/cmd_vel
-
私有命名
// 1.~+name ros::NodeHandle nh("~my_private_ns"); ros::Subscriber sub = nh.subscribe("my_private_topic", ...); // <node_namespace>/<node_name>/my_private_ns/my_private_topic // 2.~ ros::NodeHandle nh("~"); ros::Subscriber sub = nh.subscribe("my_private_topic", ...); // <node_namespace>/<node_name>/my_private_topic
私有命名与上述提到的命名都不同,它会把原本命名放入到<node_name>下。因此,上面订阅器的话题的命名如下:
<node_namespace>/<node_name>/my_private_ns/my_private_topic
需要注意的是,
<node_name>
指的是节点名字,也就是在cpp程序中初始化节点时的命名。 节点名字最好让程序中初始化的名字和launch文件中启动该节点时设置的"name"保持一致。ros::init(argc, argv, "node_name"); // 节点名字
总结:从上可知,一个cpp文件中可以设置多个节点句柄,但它们的区别只在于命名空间不同,表示的都是同一个节点。