ROS中topic、service、action、parameter实现数据的传递,关键是通过其本身的名称来实现,而与节点名无直接关系,但是topic、service、action的名称定义是在节点的代码中定义的,而节点的可执行文件进行迁移使用时,有可能与别的节点的可执行文件中的对topic、service、action、parameter的名称定义重名,虽然ROS允许在重名的条件下实现topic等通信机制,但是也容易出现混乱,因此在重名的情况下进行改名,就成为开发者需要做的工作了。当然,最基本的方法就是打开代码,直接修改topic等通信机制的名称。
ROS在launch文件中提供remappings设置项,可以在不修改代码的条件下实现对topic、service、action的名称的改名,这种方式更加快捷、方便。
关于launch文件中namespace与topic名关系的实例:
publish节点1代码:
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
from std_msgs.msg import Int32
class PublisherNode(Node):
def __init__(self, name):
super().__init__(name)
self.pub = self.create_publisher(String, "chatter1", 10)
self.i=0
self.timer = self.create_timer(0.5, self.timer_callback)
def timer_callback(self):
msg = String()
s='hello world'+str(self.i)
msg.data = s
self.i+=1
self.pub.publish(msg)
self.get_logger().info('Publishing: "%s"' % msg.data)
def main(args=None):
rclpy.init(args=args)
node = PublisherNode("topic_helloworld_pub")
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
publish节点2代码:
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
from std_msgs.msg import Int32
class PublisherNode(Node):
def __init__(self, name):
super().__init__(name)
self.pub = self.create_publisher(String, "chatter1", 10)
self.i=0
self.timer = self.create_timer(0.5, self.timer_callback)
def timer_callback(self):
msg = String()
s='how are u'+str(self.i)
msg.data = s
self.i+=1
self.pub.publish(msg)
self.get_logger().info('Publishing: "%s"' % msg.data)
def main(args=None):
rclpy.init(args=args)
node = PublisherNode("topic_helloworld_pub")
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
subscription节点代码:
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class SubscriberNode(Node):
def __init__(self, name):
super().__init__(name)
self.sub = set.create_subscription(\
String, "chatter1", self.listener_callback, 10)
def listener_callback(self, msg):
self.get_logger().info('I heard: "%s"' % msg.data)
def main(args=None):
rclpy.init(args=args)
node = SubscriberNode("topic_helloworld_sub")
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
第1个publish节点发布的消息是“hello world”,第2个publish节点发布的消息是“how are u”,2个节点的topic名都为chatter1,subscription节点则订阅名为chatter1的话题。
定义的launch文件为:
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
node0 = Node(package='pkg_test_py',executable='tp_hellopub_node',
namespace='ns_test_1', name='node_pub')
node1 = Node(package='pkg_test_py',executable='tp_hellopub_node',
namespace='ns_test_2', name='node_pub')
node2 = Node(package='pkg_test_py',executable='tp_hellosub_node',
namespace='ns_test_1', name='node_sub')
return LaunchDescription([node0,node1,node2])
通过这个launch文件可以看到,启动了2个node_pub节点,namespace分别为ns_test_1和ns_test_2,启动了1个node_sub节点,namespace为ns_test_1。运行launch文件,启动节点的结果如图所示:
从这个结果中可以看到3个节点都启动了,特别是topic list,这里显示的topic名称附加上了namespace的名字了,而subscription只接收到“hello world”,这是因为publish节点1与subscription节点在同一个namespace中,二者的topic名称是一致的,而publish节点2则在另外一个namespace中,经过launch文件运行后topic名称不再与subscription节点的topic名称一致,因此subscription节点无法接收到publish节点2所发出的消息。
将launch文件中这一句代码修改为:
node2 = Node(package='pkg_test_py',executable='tp_hellosub_node',
namespace='ns_test_2', name='node_sub')
也就意味着subscription节点将于publish节点2在同一namespace中,下面再看一下运行结果:
可以看到通过改变node2的namespace与node1一致,现在接收到的是 “how are u”。
使用remappings的实例
在上面那个实例中,更改launch文件代码,如下:
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
node0 = Node(package='pkg_test_py',executable='tp_hellopub_node',
namespace='ns_test_1', name='node_pub',
remappings=('chatter1','newtopic'))
node1 = Node(package='pkg_test_py',executable='tp_hellopub_node',
namespace='ns_test_2', name='node_pub')
node2 = Node(package='pkg_test_py',executable='tp_hellosub_node',
namespace='ns_test_2', name='node_sub',
remappings=('chatter1','newtopic'))
return LaunchDescription([node0,node1,node2])
运行的结果如下:
从结果中可以看到,只是通过launch文件的remappings设置,node0和node1的topic改为了新的topic名称:newtopic,并且实现了数据传递,而node1的topic名称保持不变,实现了同名topic的区分。
总结remappings设置项的使用:
(1) 在remapping设置项的使用中,只要将节点代码中原来的topic(service,action)名称,和新指定的topic(service,action)名称放在一个括号中(实际上是Python的tuple数据类型),需要修改多个topic(service,action)名称就需要多个tuple,就可以完成设置;
(2) 通过remapping新指定的topic名,在launch文件运行后,会自动加上namespace。