· roscpp/Overview/Publishersand Subscribers
1.发布到主题
另请参阅:ros :: NodeHandle :: advertise()API文档,ros :: Publisher API文档,ros :: NodeHandle API文档
创建一个将消息发布到主题的句柄是使用ros :: NodeHandle类完成的,NodeHandles概述中详细介绍了该类。
该NodeHandle::advertise()方法用于创建一个ros::Publisher是用来在一个主题,如发布:
1ros::Publisherpub = nh.advertise<std_msgs::String>("topic_name", 5);
2std_msgs::Stringstr;
3str.data = "helloworld";
4pub.publish(str);
注意:NodeHandle :: advertise()可能(尽管很少)返回一个空的ros :: Publisher。将来这些案例可能会引发异常,但现在他们只是打印一个错误。您可以通过以下方式检查:
1if (!pub)
2{
3...
4}
1.1内部处理发布Intraprocess Publishing
当相同主题的发布者和订阅者都存在于同一个节点内时,roscpp可以跳过序列化/反序列化步骤(可能会节省大量处理和延迟)。它只能做到这一点,尽管如果消息发布为shared_ptr:
1ros::Publisherpub = nh.advertise<std_msgs::String>("topic_name", 5);
2std_msgs::StringPtrstr(newstd_msgs::String);
3str->data = "helloworld";
4pub.publish(str);
发布的这种形式是什么可以让nodelets这么大的战胜在单独的进程节点。
请注意,以这种方式发布时,您和roscpp之间存在隐式合同:您可能不会修改发送后发送的信息,因为该指针会直接传递给任何内部进程订阅者。如果您想发送另一条消息,则必须分配一个新消息并发送该消息。
1.2发布商选项PublisherOptions
advertise()的简单版本的签名是:
1template<classM>
2ros::Publisheradvertise(conststd::string& topic, uint32_tqueue_size, boollatch = false);
- M [必填]
这是一个模板参数,指定要在主题上发布的消息类型
topic [必填]
这是要发布的主题。
queue_size [必需]
这是传出消息队列的大小。如果你发布的速度比roscpp更快,那么roscpp会开始删除旧的消息。这里的值为0意味着无限的队列,这可能是危险的。有关更多信息,请参阅rospy文档,了解如何选择合适的queue_size。
latch [可选]
启用连接上的“锁定”。当连接锁定时,最后发布的消息将被保存并自动发送给将来连接的任何用户。这对于缓慢更改静态数据(如地图)很有用。请注意,如果同一主题上存在多个发布者,并在同一个节点上实例化,则只会发送该节点上次发布的消息,而不是每个发布者上一次发布的单个主题发布的消息。
1.3发布者手柄上的其他操作OtherOperations on the Publisher Handle
ros :: Publisher是内部引用计数----这意味着复制它们非常快,并且不会创建ros :: Publisher的“新”版本。一旦ros :: Publisher的所有副本都被破坏,主题将被关闭。这有一些例外:
1. ros :: shutdown()被调用---这会关闭所有发布者(以及其他所有内容)。
2. ros:: Publisher :: shutdown()被调用。这将关闭这个话题,除非有......
3. 对同一主题多次调用NodeHandle :: advertise(),并使用相同的消息类型。在这种情况下,关于特定主题的所有ros :: Publisher都被视为彼此的副本。
ros :: Publisher实现==,!=和<运算符,并且可以在std :: map,std :: set等中使用它们
您可以使用ros :: Publisher :: getTopic()方法检索出版商的主题。
1.4.publish()行为和排队publish()behavior and queueing
roscpp中的publish()是异步的,并且只有在该主题上连接了订阅者时才起作用。 publish()本身意味着速度非常快,所以它尽可能地做到尽可能少的工作:
1. 将消息序列化到缓冲区
- 将该缓冲区推入队列以供稍后处理
然后通过roscpp的内部线程之一尽快为其推送的队列进行服务,在该队列中,每个连接的订阅者都将其放入队列中 - 第二组队列是大小设置为queue_size参数的队列()。 如果其中一个队列填满,则在将下一条消息添加到队列之前,最旧的消息将被丢弃。
请注意,传输级别上可能还有一个OS级别的队列,例如TCP / UDP发送缓冲区。
2.订阅主题
另请参见:ros :: NodeHandle :: subscribe()API文档,ros ::订阅者API文档,ros :: NodeHandle API文档,ros :: TransportHints API文档
订阅主题也使用ros :: NodeHandle类完成(在NodeHandles概述中有更详细的介绍)。使用全局函数的简单订阅将如下所示:
1voidcallback(conststd_msgs::StringConstPtr& str)
2{
3...
4}
6...
7ros::Subscribersub = nh.subscribe("my_topic", 1, callback);
2.1订户选项
有很多不同版本的ros :: NodeHandle ::subscribe(),但简单的版本归结为:
1template<classM>
2ros::Subscribersubscribe(conststd::string& topic, uint32_tqueue_size, <callback, whichmayinvolvemultiplearguments>, constros::TransportHints& transport_hints = ros::TransportHints());
M[通常不需要]----这是一个模板参数,指定要在主题上发布的消息类型。对于这个subscribe()的大多数版本,你不需要明确地定义它,因为编译器可以从你指定的回调中推断出它。
Topic---要订阅的主题
queue_size----这是roscpp将用于您的回调的传入消息队列大小。如果邮件到达太快而你无法跟上,roscpp将开始丢弃邮件。这里的值0意味着无限的队列,这可能是危险的。
<callback>----根据您使用的subscribe()版本,这可能是几类。最常见的是一个类方法指针和一个指向类实例的指针。这在后面会有更详细的解释。
transport_hints----传输提示允许您为roscpp的传输层指定提示。这使您可以指定喜欢使用UDP传输,使用tcp nodelay等方式,这在后面会有更详细的介绍。
2.2回调签名CallbackSignature
回调的签名是:
1void callback(const boost :: shared_ptr < Message const >&);
每个生成的消息都提供了共享指针类型的typedef,因此您也可以使用,例如:
1void callback(const std_msgs :: StringConstPtr&);
要么
1void callback(const std_msgs :: String :: ConstPtr&);
其他有效签名[ROS 1.1+]
从ROS 1.1开始,我们也支持上述回调的变体:
1void callback(boost :: shared_ptr < std_msgs :: String const >);
2void callback(std_msgs :: StringConstPtr);
3void callback(std_msgs :: String :: ConstPtr);
4void callback(const std_msgs :: String&);
五void callback(std_msgs :: String);
6void callback(const ros :: MessageEvent < std_msgs :: String const >&);
你也可以请求一个非const的消息,在这种情况下,如果需要的话,将会创建一个副本(即在一个节点中有多个同一主题的订阅):
1void callback(const boost :: shared_ptr < std_msgs :: String >&);
2void callback(boost :: shared_ptr < std_msgs :: String >);
3void callback(const std_msgs :: StringPtr&);
4void callback(const std_msgs :: String :: Ptr&);
五void callback(std_msgs :: StringPtr);
6void callback(std_msgs :: String :: Ptr);
7void callback(const ros :: MessageEvent < std_msgs :: String >&);
该MessageEvent的版本描述如下。
2.3回调类型
roscpp支持boost :: function支持的任何回调函数:
- 功能
- 类方法
- 函子对象(包括boost :: bind)
2.3.1功能
函数是最容易使用的:
1voidcallback(conststd_msgs::StringConstPtr& str)
2{
3...
4}
6...
7ros::Subscribersub = nh.subscribe("my_topic", 1, callback);
2.3.2类方法
类方法也很容易,但它们需要额外的参数:
1void Foo :: callback(const std_msgs :: StringConstPtr&message)
2{
3}
5...
6Foo foo_object ;
7ros :: Subscriber sub = nh。subscribe(“ my_topic ”,1,&Foo :: callback,&foo_object);
2.3.3Functor对象
函子对象是声明operator()的类,例如:
1classFoo
2{
3public:
4 voidoperator()(conststd_msgs::StringConstPtr& message)
5 {
6 }
7};
传递给subscribe()的函子必须是可复制的。在foo函子可以搭配使用subscribe()像这样:
1ros::Subscribersub = nh.subscribe<std_msgs::String>("my_topic", 1, Foo());
注意:当使用函数对象(例如boost :: bind)时,必须明确指定消息类型作为模板参数,因为在这种情况下编译器不能推导出它。
2.4MessageEvent [ROS 1.1+]
该MessageEvent的类允许您检索从订阅回调中的消息的元数据:
1void callback(const ros :: MessageEvent < std_msgs :: String const >&event)
2{
3 const std :: string&publisher_name = event。getPublisherName();
4 const ros :: M_string&header = event。getConnectionHeader();
五 ros :: Time receipt_time = event。getReceiptTime();
7 const std_msgs :: StringConstPtr&msg = event。getMessage();
8}
(有关连接头中字段的详细信息,请参阅ROS / Connection Header)
2.5排队和懒惰的反序列化Queueingand Lazy Deserialization
当消息首次到达某个主题时,它将被放入一个队列,其大小由subscribe()中的queue_size参数指定。如果队列已满并且有新消息到达,则最旧的消息将被丢弃。此外,消息实际上并未反序列化,直到需要它的第一个回调即将被调用。
2.6运输提示Transport Hints
另请参阅:ros :: TransportHints API文档
ros :: TransportHints用于指定您希望传输层为此主题行为的提示。例如,如果您想要指定“unreliable”连接(并且不允许“可靠”连接作为后退):
1ros :: Subscriber sub = nh.subscribe(“ my_topic ”,1,callback,ros :: TransportHints().unreliable());
请注意,ros ::TransportHints使用命名参数成语,这是一种方法链接形式。这意味着您可以执行以下操作:
1ros::TransportHints()
2 .unreliable()
3 .reliable()
4 .maxDatagramSize(1000)
5 .tcpNoDelay();