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

深入解析ROS 2的通用发布者创建:create_generic_publisher 函数逐行解析

概述

在 ROS 2 中,发布者是节点用于发布消息的重要组件。通常情况下,发布者的类型在编译时就已经确定。然而,有时我们需要在运行时动态指定发布者的消息类型。这种需求可以通过通用发布者 (GenericPublisher) 来满足。本文将详细解析 create_generic_publisher 函数的实现,逐行解释其工作原理,并展示如何在 ROS 2 中创建一个通用发布者。

源码

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

// 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_PUBLISHER_HPP_
#define RCLCPP__CREATE_GENERIC_PUBLISHER_HPP_

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

#include "rclcpp/generic_publisher.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/publisher_options.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/typesupport_helpers.hpp"

namespace rclcpp
{

/// Create and return a GenericPublisher.
/**
 * 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 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 AllocatorT = std::allocator<void>>
std::shared_ptr<GenericPublisher> create_generic_publisher(
  rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr topics_interface,
  const std::string & topic_name,
  const std::string & topic_type,
  const rclcpp::QoS & qos,
  const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (
    rclcpp::PublisherOptionsWithAllocator<AllocatorT>()
  )
)
{
  auto ts_lib = rclcpp::get_typesupport_library(topic_type, "rosidl_typesupport_cpp");
  auto pub = std::make_shared<GenericPublisher>(
    topics_interface->get_node_base_interface(),
    std::move(ts_lib),
    topic_name,
    topic_type,
    qos,
    options);
  topics_interface->add_publisher(pub, options.callback_group);
  return pub;
}

}  // namespace rclcpp

#endif  // RCLCPP__CREATE_GENERIC_PUBLISHER_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_PUBLISHER_HPP_
#define RCLCPP__CREATE_GENERIC_PUBLISHER_HPP_

这一部分是头文件保护宏,用于防止头文件被多次包含。#ifndef 检查 RCLCPP__CREATE_GENERIC_PUBLISHER_HPP_ 是否已经定义,如果没有定义,则继续定义它并包含文件内容。这是 C++ 中的一种常见实践,确保同一头文件不会被多次包含,从而避免重复定义的问题。

包含的头文件

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

#include "rclcpp/generic_publisher.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/publisher_options.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/typesupport_helpers.hpp"

这些头文件提供了创建通用发布者所需的基础设施:

  • <memory>:用于智能指针管理。
  • <string>:用于处理字符串。
  • <utility>:提供了一些常用的实用函数,如 std::move
  • rclcpp 相关头文件:这些头文件为 ROS 2 的发布者、节点接口、QoS 设置以及类型支持库提供了定义和功能支持。

命名空间声明

namespace rclcpp
{

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

create_generic_publisher 函数

/// Create and return a GenericPublisher.
/**
 * 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 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 AllocatorT = std::allocator<void>>
std::shared_ptr<GenericPublisher> create_generic_publisher(
  rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr topics_interface,
  const std::string & topic_name,
  const std::string & topic_type,
  const rclcpp::QoS & qos,
  const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (
    rclcpp::PublisherOptionsWithAllocator<AllocatorT>()
  )
)
函数头解析
  • 函数声明

    • 该函数是一个模板函数,默认使用 std::allocator<void> 作为分配器类型 AllocatorT
    • 返回类型为 std::shared_ptr<GenericPublisher>,即一个指向 GenericPublisher 对象的智能指针。
  • 参数解析

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

    • 文档注释说明了函数的行为:返回的指针不会为空,但在某些情况下可能会抛出异常,例如无法找到消息的包时。

函数实现

{
  auto ts_lib = rclcpp::get_typesupport_library(topic_type, "rosidl_typesupport_cpp");
  • 解释
    • 这行代码调用 rclcpp::get_typesupport_library 函数,根据指定的 topic_type 和类型支持标识符 "rosidl_typesupport_cpp" 来获取消息类型的类型支持库(Type Support Library)。
    • rosidl_typesupport_cpp 是 ROS 2 中用于 C++ 的类型支持库的标识符。
  auto pub = std::make_shared<GenericPublisher>(
    topics_interface->get_node_base_interface(),
    std::move(ts_lib),
    topic_name,
    topic_type,
    qos,
    options);
  • 解释
    • 使用 std::make_shared 创建一个 GenericPublisher 对象的共享指针 pub
    • 构造 GenericPublisher 对象时,传入了节点的基础接口(通过 topics_interface->get_node_base_interface() 获取)、类型支持库、话题名称、话题类型、QoS 设置以及发布者选项。
    • 这里使用了 std::move(ts_lib) 将类型支持库的所有权转移给 GenericPublisher,以避免不必要的拷贝。

继续解析 create_generic_publisher 函数的实现部分:

  topics_interface->add_publisher(pub, options.callback_group);
  • 解释
    • 这行代码将刚创建的 GenericPublisher 对象添加到 topics_interface 中进行管理。topics_interface->add_publisher 方法将发布者对象与特定的回调组关联,以便在消息发布过程中,回调函数能够被正确地调度和执行。
    • options.callback_group 是一个回调组,可以为空(nullptr),如果为空,则使用节点的默认回调组。
  return pub;
}
  • 解释
    • 该函数返回创建的 GenericPublisher 对象的共享指针 pub。这个指针由调用方持有和管理,确保在其生命周期内发布者对象不会被销毁。
    • 返回的 GenericPublisher 对象允许在运行时动态地发布任意类型的消息,灵活性非常高。

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

}  // namespace rclcpp

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

总结

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值