〖ROS2 源码解析〗rclcpp/include/rclcpp/create_generic_subscription.hpp

深入解析ROS 2的通用订阅者创建:create_generic_subscription 函数逐行解析

概述

在 ROS 2 中,订阅者是节点用于接收消息的重要组件。与特定消息类型的订阅者不同,通用订阅者 (GenericSubscription) 允许在运行时动态指定消息类型和处理回调函数。本文将详细解析 create_generic_subscription 函数的实现,逐行解释其工作原理,并展示如何在 ROS 2 中创建一个通用订阅者。

源码

首先,让我们看一下 create_generic_subscription 函数的完整源代码:

// Copyright 2020, Apex.AI Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef RCLCPP__CREATE_GENERIC_SUBSCRIPTION_HPP_
#define RCLCPP__CREATE_GENERIC_SUBSCRIPTION_HPP_

#include <functional>
#include <memory>
#include <string>
#include <utility>

#include "rcl/subscription.h"
#include "rclcpp/generic_subscription.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/subscription_options.hpp"
#include "rclcpp/typesupport_helpers.hpp"

namespace rclcpp
{

/// Create and return a GenericSubscription.
/**
 * The returned pointer will never be empty, but this function can throw various exceptions, for
 * instance when the message's package can not be found on the AMENT_PREFIX_PATH.
 *
 * \param topics_interface NodeTopicsInterface pointer used in parts of the setup.
 * \param topic_name Topic name
 * \param topic_type Topic type
 * \param qos %QoS settings
 * \param callback Callback for new messages of serialized form
 * \param options %Publisher options.
 * Not all publisher options are currently respected, the only relevant options for this
 * publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
 */
template<
  typename CallbackT,
  typename AllocatorT = std::allocator<void>>
std::shared_ptr<GenericSubscription> create_generic_subscription(
  rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr topics_interface,
  const std::string & topic_name,
  const std::string & topic_type,
  const rclcpp::QoS & qos,
  CallbackT && callback,
  const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
    rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
  )
)
{
  auto ts_lib = rclcpp::get_typesupport_library(
    topic_type, "rosidl_typesupport_cpp");

  auto allocator = options.get_allocator();

  using rclcpp::AnySubscriptionCallback;
  AnySubscriptionCallback<rclcpp::SerializedMessage, AllocatorT>
  any_subscription_callback(*allocator);
  any_subscription_callback.set(std::forward<CallbackT>(callback));

  auto subscription = std::make_shared<GenericSubscription>(
    topics_interface->get_node_base_interface(),
    std::move(ts_lib),
    topic_name,
    topic_type,
    qos,
    any_subscription_callback,
    options);

  topics_interface->add_subscription(subscription, options.callback_group);

  return subscription;
}

}  // namespace rclcpp

#endif  // RCLCPP__CREATE_GENERIC_SUBSCRIPTION_HPP_

逐行解析

文件头部

// Copyright 2020, Apex.AI Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

文件头部包含了版权声明和许可证信息。这部分代码明确了该代码的使用受 Apache License 2.0 约束,允许用户在遵循许可证的前提下使用、修改和分发代码。

头文件保护

#ifndef RCLCPP__CREATE_GENERIC_SUBSCRIPTION_HPP_
#define RCLCPP__CREATE_GENERIC_SUBSCRIPTION_HPP_

这是一个常见的 C++ 头文件保护机制,防止头文件被多次包含。#ifndef 宏检查 RCLCPP__CREATE_GENERIC_SUBSCRIPTION_HPP_ 是否已经定义,如果没有定义,则继续定义它并包含文件内容。

包含的头文件

#include <functional>
#include <memory>
#include <string>
#include <utility>

#include "rcl/subscription.h"
#include "rclcpp/generic_subscription.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/subscription_options.hpp"
#include "rclcpp/typesupport_helpers.hpp"

这里包含了创建通用订阅者所需的基础设施:

  • <functional>:用于处理回调函数和函数对象。
  • <memory>:支持智能指针管理。
  • <string>:支持标准字符串类型。
  • <utility>:提供了 std::move 等实用函数。
  • rclcpp 相关头文件:这些头文件为 ROS 2 的订阅者、节点接口、QoS 设置、序列化消息以及类型支持库提供了定义和功能支持。

命名空间声明

namespace rclcpp
{

这行代码声明了 rclcpp 命名空间。rclcpp 是 ROS 2 的核心命名空间,包含了与客户端、服务、节点、发布者、订阅者等相关的功能。

create_generic_subscription 函数

/// Create and return a GenericSubscription.
/**
 * The returned pointer will never be empty, but this function can throw various exceptions, for
 * instance when the message's package can not be found on the AMENT_PREFIX_PATH.
 *
 * \param topics_interface NodeTopicsInterface pointer used in parts of the setup.
 * \param topic_name Topic name
 * \param topic_type Topic type
 * \param qos %QoS settings
 * \param callback Callback for new messages of serialized form
 * \param options %Publisher options.
 * Not all publisher options are currently respected, the only relevant options for this
 * publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
 */
函数头解析
  • 函数声明

    • 该函数是一个模板函数,接受一个回调类型 CallbackT 和一个分配器类型 AllocatorT(默认为 std::allocator<void>)。
    • 返回类型为 std::shared_ptr<GenericSubscription>,即一个指向 GenericSubscription 对象的智能指针。
  • 参数解析

    • topics_interface: 指向 NodeTopicsInterface 的共享指针,用于管理节点与话题相关的接口操作。
    • topic_name: 要订阅的话题名称。
    • topic_type: 订阅的消息类型(以字符串形式表示,例如 "std_msgs/msg/String")。
    • qos: 质量服务设置(QoS),控制消息的接收行为,如可靠性、历史记录等。
    • callback: 处理接收到的序列化消息的回调函数。
    • options: 订阅者选项,可以指定回调组、事件回调等配置。

函数实现

{
  auto ts_lib = rclcpp::get_typesupport_library(
    topic_type, "rosidl_typesupport_cpp");
  • 解释
    • 通过调用 rclcpp::get_typesupport_library 函数,根据指定的 topic_type 和类型支持标识符 "rosidl_typesupport_cpp" 来获取消息类型的类型支持库。
  auto allocator = options.get_allocator();
  • 解释
    • 获取 options 中指定的分配器对象,用于后续的内存管理。
  using rclcpp::AnySubscriptionCallback;
  AnySubscriptionCallback<rclcpp::SerializedMessage, AllocatorT>
  any_subscription_callback(*allocator);
  any_subscription_callback.set(std::forward<CallbackT>(callback));
  • 解释
    • 这里使用了 AnySubscriptionCallback 模板类,定义了一个通用的回调对象 any_subscription_callback,它能够处理序列化消息 rclcpp::SerializedMessage
    • 使用分配器对象初始化回调对象,并将传入的回调函数通过 set 方法设置到 any_subscription_callback 中。
    • std::forward<CallbackT>(callback) 保留了传入回调函数的值类别(左值或右值),
  auto subscription = std::make_shared<GenericSubscription>(
    topics_interface->get_node_base_interface(),
    std::move(ts_lib),
    topic_name,
    topic_type,
    qos,
    any_subscription_callback,
    options);
  • 解释
    • 使用 std::make_shared 创建一个 GenericSubscription 对象的共享指针 subscription
    • GenericSubscription 是 ROS 2 中用于处理任意消息类型的通用订阅者。构造函数中传入了以下参数:
      • topics_interface->get_node_base_interface():获取节点的基础接口。
      • std::move(ts_lib):传递类型支持库的所有权给订阅者对象。
      • topic_nametopic_type:订阅的话题名称和消息类型。
      • qos:质量服务设置,用于控制消息传递的行为。
      • any_subscription_callback:设置的通用回调对象,用于处理接收到的消息。
      • options:订阅者选项,包含回调组和其他配置。
  topics_interface->add_subscription(subscription, options.callback_group);
  • 解释
    • 将创建的 subscription 对象添加到 topics_interface 中进行管理。topics_interface->add_subscription 方法将订阅者对象与特定的回调组关联,以便在接收到消息时,能够正确调度回调函数。
    • options.callback_group 用于指定订阅者的回调组,如果未设置则使用节点的默认回调组。
  return subscription;
}
  • 解释
    • 该函数返回创建的 GenericSubscription 对象的共享指针 subscription。这个指针由调用方持有和管理,确保在其生命周期内订阅者对象不会被销毁。
    • 返回的 GenericSubscription 对象允许在运行时动态地订阅任意类型的消息,极大地提高了系统的灵活性。

结束 rclcpp 命名空间与头文件保护

}  // namespace rclcpp

#endif  // RCLCPP__CREATE_GENERIC_SUBSCRIPTION_HPP_
  • 解释
    • 这部分代码关闭了 rclcpp 命名空间,并结束了头文件的防重复包含保护。

总结

create_generic_subscription 函数为 ROS 2 提供了一种在运行时动态创建订阅者的机制。与特定消息类型的订阅者不同,通用订阅者 (GenericSubscription) 允许开发者在运行时指定消息类型和回调函数,从而提高了系统的灵活性和扩展性。函数通过使用 rclcpp::get_typesupport_library 来获取类型支持库,并结合 GenericSubscription 对象和 AnySubscriptionCallback,创建一个强大的工具,满足动态消息订阅的需求。

在 ROS 2 的开发中,理解和使用 create_generic_subscription 函数可以大大简化处理不同消息类型的工作,尤其是在需要处理动态消息类型的复杂应用中。这种通用化的设计使得代码更易于维护和扩展,对于开发者来说是一个非常有用的工具。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值