cartographer订阅话题的函数封装

Posted COCO_PEAK_NOODLE

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cartographer订阅话题的函数封装相关的知识,希望对你有一定的参考价值。

template <typename MessageType>
::ros::Subscriber SubscribeWithHandler(
    void (Node::*handler)(int, const std::string&,
                          const typename MessageType::ConstPtr&),
    const int trajectory_id, const std::string& topic,
    ::ros::NodeHandle* const node_handle, Node* const node) {
  return node_handle->subscribe<MessageType>(
      topic, kInfiniteSubscriberQueueSize,
      boost::function<void(const typename MessageType::ConstPtr&)>(
          [node, handler, trajectory_id,
           topic](const typename MessageType::ConstPtr& msg) {
            (node->*handler)(trajectory_id, topic, msg);
          }));
}

知识点-1:typename MessageType::ConstPtr,我们知道MessageType是模板类型,但是系统不知道MessageType::ConstPtr是类型还是啥?所以加上typename告诉系统这是个类型,所以我们一般用typename告知系统这是个类型。
知识点-2: 函数指针作为参数,它是成员函数指针,所以调用的时候要这么用

(node->*handler)(trajectory_id, topic, msg);

知识点-3:lamda表达式,使用lamda表达式可以构建函数的body,这里的boost::function可以替换为
std::function

参考文章
【C++】std::function与函数指针
C++11新特性:参数绑定——std::bind
C++11 中的std::function和std::bind
C++Lambda表达式

深究篇
我们来看下为什么能这么用?
subscribe是一个模板函数,我们看下它的定义

  /**
   * \\brief Subscribe to a topic, version for arbitrary boost::function object
   *
   * This method connects to the master to register interest in a given
   * topic.  The node will automatically be connected with publishers on
   * this topic.  On each message receipt, callback is invoked and passed a shared pointer
   * to the message received.  This message should \\b not be changed in place, as it
   * is shared with any other subscriptions to this topic.
   *
   * This version of subscribe allows anything bindable to a boost::function object
   *
   * \\param M [template] M here is the message type
   * \\param topic Topic to subscribe to
   * \\param queue_size Number of incoming messages to queue up for
   * processing (messages in excess of this queue capacity will be
   * discarded).
   * \\param callback Callback to call when a message has arrived
   * \\param tracked_object A shared pointer to an object to track for these callbacks.  If set, the a weak_ptr will be created to this object,
   * and if the reference count goes to 0 the subscriber callbacks will not get called.
   * Note that setting this will cause a new reference to be added to the object before the
   * callback, and for it to go out of scope (and potentially be deleted) in the code path (and therefore
   * thread) that the callback is invoked from.
   * \\param transport_hints a TransportHints structure which defines various transport-related options
   * \\return On success, a Subscriber that, when all copies of it go out of scope, will unsubscribe from this topic.
   * On failure, an empty Subscriber which can be checked with:
\\verbatim
void callback(const std_msgs::Empty::ConstPtr& message){...}
ros::NodeHandle nodeHandle;
ros::Subscriber sub = nodeHandle.subscribe("my_topic", 1, callback);
if (sub)  // Enter if subscriber is valid
{
...
}
\\endverbatim
   *  \\throws InvalidNameException If the topic name begins with a tilde, or is an otherwise invalid graph resource name
   *  \\throws ConflictingSubscriptionException If this node is already subscribed to the same topic with a different datatype
   */
  template<class M>
  Subscriber subscribe(const std::string& topic, uint32_t queue_size, const boost::function<void (const boost::shared_ptr<M const>&)>& callback,
                             const VoidConstPtr& tracked_object = VoidConstPtr(), const TransportHints& transport_hints = TransportHints())
  {
    SubscribeOptions ops;
    ops.template init<M>(topic, queue_size, callback);
    ops.tracked_object = tracked_object;
    ops.transport_hints = transport_hints;
    return subscribe(ops);
  }

看到这也回调函数的定义方式和我们的不同啊,这也是知识点-1的原因,为啥要复用typename。因为MessageType::ConstPtr这是啥我们不知道,这个要使用者自己定义ConstPtr,不然使用这个模板函数会出错。

boost::function<void (const boost::shared_ptr<M const>&)>& callback

那我们按照定义方式定义不久可以了吗?所以我们这样改写也是可以的

template <typename MessageType>
::ros::Subscriber SubscribeWithHandler(
    void (Node::*handler)(int, const std::string&,
                          const boost::shared_ptr<MessageType const>&),
    const int trajectory_id, const std::string& topic,
    ::ros::NodeHandle* const node_handle, Node* const node) {
  return node_handle->subscribe<MessageType>(
      topic, kInfiniteSubscriberQueueSize,
      boost::function<void(const boost::shared_ptr<MessageType const>&)>(
          [node, handler, trajectory_id,
           topic](const boost::shared_ptr<MessageType const>& msg) {
            (node->*handler)(trajectory_id, topic, msg);
          }));

我们再来看下ConstPtr的定义,与我们的形参一致

typedef boost::shared_ptr< ::sensor_msgs::LaserScan_<ContainerAllocator> const> ConstPtr;

以上是关于cartographer订阅话题的函数封装的主要内容,如果未能解决你的问题,请参考以下文章

代码修改记录-cartographer_ros Run函数

cartographer 调参-ROS API 文档

cartographer源码解析

cartographer源码解析

cartographer之pose_extrapolator

常用Javascript代码片段集锦