您正在阅读的是开发版本的文档。有关最新发布的版本,请访问 Jazzy.

释放快速 DDS 中间件的潜力 [社区贡献]

目标 本教程将介绍如何在 ROS 2 中使用快速 DDS 的扩展配置功能。

辅导水平: 高级

时间 20 分钟

背景介绍

ROS 2 堆栈与 快速 DDS 由 ROS 2 中间件实现提供 rmw_fastrtps.所有 ROS 2 发行版中都有该实现,既有二进制文件,也有源代码。

ROS 2 RMW 只允许配置某些中间件 QoS(见 ROS 2 QoS 策略).然而、 rmw_fastrtps 提供扩展的配置功能,以充分利用 快速 DDS.本教程将通过一系列示例向您解释如何使用 XML 文件解锁此扩展配置。

为了获取更多有关使用 快速 DDS 请查看 下列文件.

先决条件

本教程假定您知道如何 创建软件包.它还假定您知道如何编写 简单的发布者和订阅者 和一个 简单的服务和客户.虽然示例是用 C++ 实现的,但同样的概念也适用于 Python 包。

在同一节点中混合同步和异步出版物

在第一个示例中,将创建一个有两个发布者的节点,其中一个采用同步发布模式,另一个采用异步发布模式。

rmw_fastrtps 默认使用同步发布模式。

在同步发布模式下,数据直接在用户线程的上下文中发送。这意味着在写入操作过程中发生的任何阻塞调用都会阻塞用户线程,从而阻止应用程序继续运行。不过,这种模式通常能以较低的延迟获得较高的吞吐率,因为线程之间不存在通知或上下文切换。

另一方面,在异步发布模式下,发布者每次调用写操作时,数据都会被复制到一个队列中,一个后台线程(异步线程)会收到队列中新增数据的通知,并在数据实际发送前将线程的控制权返回给用户。后台线程负责消耗队列,并将数据发送给每个匹配的阅读器。

使用发布者创建节点

首先,创建一个名为 sync_async_node_example_cpp 新工作区:

mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
ros2 pkg create --build-type ament_cmake --license Apache-2.0 --dependencies rclcpp std_msgs -- sync_async_node_example_cpp

然后,添加一个名为 src/sync_async_writer.cpp 的内容如下。请注意,同步发布者将在主题 同步主题,而异步将按主题发布 异步主题.

#include 时间顺序<chrono>;
#include 功能强大;
#include <内存>;
#include <字符串>;

#include "rclcpp/rclcpp.hpp";
#include "std_msgs/msg/string.hpp";

使用 命名空间 标准::计时器;

 SyncAsyncPublisher :  rclcpp::节点
{
:
    SyncAsyncPublisher()
        : 节点("sync_async_publisher";), count_(0)
    {
        // 在主题 'sync_topic' 上创建同步发布器;
        sync_publisher_ = ->;创建出版商<;std_msgs::信息::字符串>;("sync_topic";, 10);

        // 在主题 'async_topic' 上创建异步发布器;
        async_publisher_ = ->;创建出版商<;std_msgs::信息::字符串>;("async_topic";, 10);

        // 每次定时器到期时都要运行的操作
        汽车 定时器回调 = [](){

            // 创建要发送的新信息
            汽车 同步消息 = std_msgs::信息::字符串();
            同步消息.数据 = SYNC:你好,世界!"; + 标准::to_string(count_);

            // 将信息记录到控制台以显示进度
            RCLCPP_INFO(->;get_logger(), "同步发布:'%s'";, 同步消息.数据.c_str());

            // 使用同步发布器发布信息
            sync_publisher_->;发布(同步消息);

            // 创建要发送的新信息
            汽车 异步消息 = std_msgs::信息::字符串();
            异步消息.数据 = ASYNC:你好,世界!"; + 标准::to_string(count_);

            // 将信息记录到控制台以显示进度
            RCLCPP_INFO(->;get_logger(), "异步发布:'%s'";, 异步消息.数据.c_str());

            // 使用异步发布器发布消息
            async_publisher_->;发布(异步消息);

            // 为下一条信息准备计数
            count_++;
        };

        // 该计时器将每半秒触发一次新数据的发布
        定时器 = ->;创建隔离墙计时器(500毫秒, 定时器回调);
    }

私人:
    // 该计时器将每半秒触发一次新数据的发布
    rclcpp::定时器基数::SharedPtr 定时器;

    // 异步发布的发布者
    rclcpp::出版商<;std_msgs::信息::字符串>::SharedPtr async_publisher_;

    // 同步发布的发布者
    rclcpp::出版商<;std_msgs::信息::字符串>::SharedPtr sync_publisher_;

    // 目前已发送的信息数量
    size_t count_;
};

int 主要(int 参数, 烧焦 * 参数[])
{
    rclcpp::启动(参数, 参数);
    rclcpp::后旋(标准::共享<;SyncAsyncPublisher>;());
    rclcpp::关闭();
    返回 0;
}

现在打开 CMakeLists.txt 文件,并添加一个新的可执行文件,将其命名为 SyncAsyncWriter 这样您就可以使用 玫瑰2 运行:

添加可执行(SyncAsyncWriter src/sync_async_writer.cpp)
ament_target_dependencies(SyncAsyncWriter rclcpp std_msgs)

最后,添加 install(TARGETS...) 因此 玫瑰2 运行 能找到你的可执行文件:

安装(目标
    SyncAsyncWriter
    目的地 lib/${项目名称})

您可以清理您的 CMakeLists.txt 删除了一些不必要的部分和注释,所以看起来像这样:

cmake_minimum_required(版本 3.8)
项目(sync_async_node_example_cpp)

# 默认为 C++14
如果(不是 cmake_cxx_standard)
  设置(cmake_cxx_standard 14)
endif()

如果(cmake_compiler_is_gnucxx  cmake_cxx_compiler_id 比赛 "Clang";)
  添加编译选项(-墙 -Wextra -Wpedantic)
endif()

查找软件包(ament_cmake 要求)
查找软件包(rclcpp 要求)
查找软件包(std_msgs 要求)

添加可执行(SyncAsyncWriter src/sync_async_writer.cpp)
ament_target_dependencies(SyncAsyncWriter rclcpp std_msgs)

安装(目标
    SyncAsyncWriter
    目的地 lib/${项目名称})

ament_package()

如果现在构建并运行该节点,两个发布器的行为都将相同,都将以异步方式在两个主题中发布,因为这是默认发布模式。默认发布模式配置可在节点启动时使用 XML 文件进行更改。

创建包含配置文件配置的 XML 文件

创建一个文件,文件名为 SyncAsync.xml 以及以下内容:

<?xml version="1.0" encoding="UTF-8" ?>;
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles";>;

    默认出版商配置文件 -->;
    <publisher profile_name="default_publisher"; is_default_profile="true";>;
        历史内存政策<historyMemoryPolicy>;动态</historyMemoryPolicy>;
    </publisher>;

    <!-- 默认用户配置文件 -->;
    订阅者 profile_name="default_subscriber"; is_default_profile="true";>;
        历史内存政策<historyMemoryPolicy>;动态</historyMemoryPolicy>;
    /订阅者>;

    <!-- 主题 sync_topic 的发布者简介 -->;
    <publisher profile_name="/sync_topic";>;
        历史内存政策<historyMemoryPolicy>;动态</historyMemoryPolicy>;
        qos>;
            <publishMode>;
                <种类>;同步</kind>;
            </publishMode>;
        </qos>;
    </publisher>;

    <!-- 主题 async_topic 的发布者简介 -->;
    <publisher profile_name="/async_topic";>;
        历史内存政策<historyMemoryPolicy>;动态</historyMemoryPolicy>;
        qos>;
            <publishMode>;
                <种类>;ASYNCHRONOUS</kind>;
            </publishMode>;
        </qos>;
    </publisher>;

 </profiles>;

请注意,已为发布者和订阅者定义了多个配置文件。定义的两个默认配置文件设置了 is_default_profile以及两个名称与之前定义的主题名称一致的配置文件: 同步主题 和另一个 异步主题.最后两个配置文件将发布模式设置为 同步ASYNCHRONOUS 因此。还请注意,所有配置文件都指定了 历史内存政策 值,该值是示例运行所必需的,本教程稍后将解释其原因。

执行发布节点

您需要导出以下环境变量才能加载 XML:

export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
export RMW_FASTRTPS_USE_QOS_FROM_XML=1
export FASTRTPS_DEFAULT_PROFILES_FILE=path/to/SyncAsync.xml

最后,确保设置文件的来源,并运行节点:

source install/setup.bash
ros2 run sync_async_node_example_cpp SyncAsyncWriter

你应该会看到发布者从发布节点发送数据,就像这样:

[INFO] [1612972049.994630332] [sync_async_publisher]:同步发布: 'SYNC: Hello, world!0'
[INFO] [1612972049.995097767] [sync_async_publisher]:异步发布: 'ASYNC: Hello, world!0'
[INFO] [1612972050.494478706] [sync_async_publisher]:同步发布: 'SYNC: Hello, world!1'
[INFO] [1612972050.494664334] [sync_async_publisher]:异步发布: 'ASYNC: Hello, world!1'
[INFO] [1612972050.994368474] [sync_async_publisher]:同步发布: 'SYNC: Hello, world!2'
[INFO] [1612972050.994549851] [sync_async_publisher]:异步发布: 'ASYNC: Hello, world!2'

现在,同步发布器和异步发布器已在同一节点内运行。

创建一个节点,其中包含订阅者

接下来,一个带有订阅者的新节点将监听 同步主题异步主题 的出版物。在名为 src/sync_async_reader.cpp 写出以下内容:

#include <内存>;

#include "rclcpp/rclcpp.hpp";
#include "std_msgs/msg/string.hpp";

 SyncAsyncSubscriber :  rclcpp::节点
{
:

    SyncAsyncSubscriber()
        : 节点("sync_async_subscriber";)
    {
        // 每次收到新信息时运行的 Lambda 函数
        汽车 topic_callback = []( std_msgs::信息::字符串 及样品; 信息){
            RCLCPP_INFO(->;get_logger(), "我听说:'%s'";, 信息.数据.c_str());
        };

        // 在主题 'sync_topic' 上创建同步订阅者;
        // 并将其与 topic_callback 绑定
        同步订阅 = ->;创建订阅<;std_msgs::信息::字符串>;(
            "sync_topic";, 10, topic_callback);

        // 在主题 'async_topic' 上创建异步订阅者;
        // 并将其与 topic_callback 绑定
        异步订阅 = ->;创建订阅<;std_msgs::信息::字符串>;(
            "async_topic";, 10, topic_callback);
    }

私人:

    // 监听主题 'sync_topic' 的订阅者;
    rclcpp::订阅<;std_msgs::信息::字符串>::SharedPtr 同步订阅;

    // 监听主题 'async_topic' 的订阅者;
    rclcpp::订阅<;std_msgs::信息::字符串>::SharedPtr 异步订阅;
};

int 主要(int 参数, 烧焦 * 参数[])
{
    rclcpp::启动(参数, 参数);
    rclcpp::后旋(标准::共享<;SyncAsyncSubscriber>;());
    rclcpp::关闭();
    返回 0;
}

打开 CMakeLists.txt 文件,并添加一个新的可执行文件,将其命名为 SyncAsyncReader 根据以前的 SyncAsyncWriter:

添加可执行(SyncAsyncReader src/sync_async_reader.cpp)
ament_target_dependencies(SyncAsyncReader rclcpp std_msgs)

安装(目标
    SyncAsyncReader
    目的地 lib/${项目名称})

执行用户节点

在一个终端中运行发布节点后,打开另一个终端,导出加载 XML 所需的环境变量:

export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
export RMW_FASTRTPS_USE_QOS_FROM_XML=1
export FASTRTPS_DEFAULT_PROFILES_FILE=path/to/SyncAsync.xml

最后,确保设置文件的来源,并运行节点:

source install/setup.bash
ros2 run sync_async_node_example_cpp SyncAsyncReader

你应该看到订阅者从发布节点接收数据,就像这样:

[INFO] [1612972054.495429090] [sync_async_subscriber]:我听到: 'SYNC: Hello, world!10'
[INFO] [1612972054.995410057] [sync_async_subscriber]:我听到: 'ASYNC: Hello, world!10'
[INFO] [1612972055.495453494] [sync_async_subscriber]:我听到: 'SYNC: Hello, world!11'
[INFO] [1612972055.995396561] [sync_async_subscriber]:我听到: 'ASYNC: Hello, world!11'
[INFO] [1612972056.495534818] [sync_async_subscriber]:我听到: 'SYNC: Hello, world!12'
[INFO] [1612972056.995473953] [sync_async_subscriber]:我听到: 'ASYNC: Hello, world!12'

实例分析

配置文件 XML

XML 文件为发布者和订阅者定义了几种配置。可以有一个默认的发布者配置文件和多个特定主题的发布者配置文件。唯一的要求是,所有发布者配置文件都有不同的名称,而且只有一个默认配置文件。订阅者也是如此。

要为特定主题定义配置,只需以 ROS 2 主题名称命名配置文件(如 /sync_topic/async_topic 在示例中),以及 rmw_fastrtps 会将此配置文件应用于该主题的所有发布者和订阅者。默认配置文件由属性 is_default_profile 设为 当没有其他名称与主题名称相匹配的配置文件时,该配置文件将作为备用配置文件。

环境变量 fastrtps_default_profiles_file 用于通知 快速 DDS 要加载的配置文件的 XML 文件路径。

rmw_fastrtps_use_qos_from_xml

在所有可配置的属性中 rmw_fastrtps 治疗 发布模式历史内存政策 不同。默认情况下,这些值设置为 ASYNCHRONOUS预分配与重新分配rmw_fastrtps 而在 XML 文件中设置的值将被忽略。要使用 XML 文件中的值,环境变量 rmw_fastrtps_use_qos_from_xml 必须设置为 1.

然而,这需要 另一个注意事项:如果 rmw_fastrtps_use_qos_from_xml 已设置,但 XML 文件没有定义 发布模式历史内存政策,这些属性采用 快速 DDS 默认值,而不是 rmw_fastrtps 默认值。这一点很重要,尤其是对于 历史内存政策因为 快速 DDS 聋值为 预分配 而 ROS2 的主题数据类型则不适用。因此,在示例中,该策略的有效值被明确设置为动态).

rmw_qos_profile_t 的优先级

ROS 2 QoS 包含在 rmw_qos_profile_t 除非设置为 *系统默认值.在这种情况下,XML 值(或 快速 DDS 如果没有 XML 默认值,则应用默认值。这意味着,如果 rmw_qos_profile_t 设置为 *系统默认值,XML 中的相应值将被忽略。

使用 XML 的其他 FastDDS 功能

虽然我们创建的节点有两个配置不同的发布器,但要检查它们的行为是否不同并不容易。现在,XML 配置文件的基础知识已经介绍完毕,让我们用它们来配置一些对节点有视觉效果的东西。具体来说,我们将在其中一个发布者上设置匹配订阅者的最大数量,在另一个发布者上设置分区定义。请注意,这些只是所有配置属性中非常简单的示例。 rmw_fastrtps 通过 XML 文件。请参考 *快速 DDS* 文档 查看可通过 XML 文件配置的全部属性列表。

限制匹配用户的数量

添加最大匹配用户数量到 /async_topic 出版商简介。它应该是这样的

<!-- 主题 async_topic 的发布者简介 -->;
<publisher profile_name="/async_topic";>;
    历史内存政策<historyMemoryPolicy>;动态</historyMemoryPolicy>;
    qos>;
        <publishMode>;
            <种类>;ASYNCHRONOUS</kind>;
        </publishMode>;
    </qos>;
    <matchedSubscribersAllocation>;
        <initial>;0</initial>;
        <最大>;1</maximum>;
        增量>;1</increment>;
    </matchedSubscribersAllocation>;
</publisher>;

匹配用户数量仅限一个。

现在打开三个终端,不要忘记源设置文件和设置所需的环境变量。在第一个终端上运行发布者节点,在另外两个终端上运行订阅者节点。你会发现,只有第一个订阅者节点会收到来自两个主题的消息。第二个节点无法完成在 /async_topic 因为发布者阻止了它,因为它已经达到了匹配发布者的上限。因此,只有来自 /sync_topic 将在第三终端接收:

[INFO] [1613127657.088860890] [sync_async_subscriber]:我听到: 'SYNC: Hello, world!18'
[INFO] [1613127657.588896594] [sync_async_subscriber]:我听到: 'SYNC: Hello, world!19'
[INFO] [1613127658.088849401] [sync_async_subscriber]:我听到: 'SYNC: Hello, world!20'

在主题内使用分区

分区功能可用于控制哪些发布者和订阅者在同一主题内交换信息。

分区在由域 ID 引起的物理隔离中引入了逻辑实体隔离层概念。发布者要与订阅者通信,他们必须至少属于一个共同的分区。在域和主题之外,分区代表了将发布者和订阅者分开的另一个层次。与域和主题不同,一个端点可以同时属于多个分区。要在不同域或主题上共享某些数据,每个域或主题必须有一个不同的发布者,共享自己的历史变化。不过,单个发布者可通过单个主题数据变更在不同分区共享相同的数据样本,从而减少网络过载。

让我们改变 /sync_topic 出版商分区 第一部分 并创建一个新的 /sync_topic 使用分区的用户 第2部分.他们的个人资料现在应该是这样的:

<!-- 主题 sync_topic 的发布者简介 -->;
<publisher profile_name="/sync_topic";>;
    历史内存政策<historyMemoryPolicy>;动态</historyMemoryPolicy>;
    qos>;
        <publishMode>;
            <种类>;同步</kind>;
        </publishMode>;
        <分区>;
            <名称>;
                <名称>;第一部分</名称>;
            </names>;
        </partition>;
    </qos>;
</publisher>;

<!-- 主题 sync_topic 的用户配置文件 -->;
订阅者 profile_name="/sync_topic";>;
    历史内存政策<historyMemoryPolicy>;动态</historyMemoryPolicy>;
    qos>;
        <分区>;
            <名称>;
                <名称>;第2部分</名称>;
            </names>;
        </partition>;
    </qos>;
/订阅者>;

打开两个终端。不要忘记源设置文件和设置所需的环境变量。在第一个终端运行发布者节点,在另一个终端运行订阅者节点。您会看到只有 /async_topic 信息到达订户。信息 /sync_topic 订阅者接收不到数据,因为它与相应的发布者处于不同的分区。

[INFO] [1612972054.995410057] [sync_async_subscriber]:我听到: 'ASYNC: Hello, world!10'
[INFO] [1612972055.995396561] [sync_async_subscriber]:我听到: 'ASYNC: Hello, world!11'
[INFO] [1612972056.995473953] [sync_async_subscriber]:我听到: 'ASYNC: Hello, world!12'

配置服务和客户端

服务和客户端各有一个发布者和一个订阅者,它们通过两个不同的主题进行通信。例如,对于名为 有:

  • 服务用户在 /rq/ping.

  • 服务发布者在 /rr/ping.

  • 客户端发布者在 /rq/ping.

  • 客户端用户监听 /rr/ping.

虽然您可以使用这些主题名称在 XML 上设置配置文件,但有时您可能希望将相同的配置文件应用到节点上的所有服务或客户端。您可以直接创建一个名为 "发布者 "和 "订阅者 "的配置文件对,而不必复制为所有服务生成的包含所有主题名的同一配置文件。 服务.同样,客户也可以创建一对名为 客户.

创建带有服务和客户端的节点

开始创建服务节点添加一个名为 src/ping_service.cpp 在包装上注明以下内容:

#include <内存>;

#include "rclcpp/rclcpp.hpp";
#include "example_interfaces/srv/trigger.hpp";

/**
 * 服务操作:以 success=true 响应,并在控制台上打印请求
 */
空白 ( 标准::共享_ptr<;接口示例::服务::触发器::要求>; 要求,
        标准::共享_ptr<;接口示例::服务::触发器::回应>; 回应)
{
    // 请求数据未使用
    (空白) 要求;

    // 建立响应
    回应->;成功 = ;

    // 记录到控制台
    RCLCPP_INFO(rclcpp::get_logger(ping_server";), "收到请求";);
    RCLCPP_INFO(rclcpp::get_logger(ping_server";), 发送回复";);
}

int 主要(int 参数, 烧焦 **参数)
{
    rclcpp::启动(参数, 参数);

    // 创建节点和服务
    标准::共享_ptr<;rclcpp::节点>; 网站 = rclcpp::节点::共享(ping_server";);
    rclcpp::服务<;接口示例::服务::触发器>::SharedPtr 服务 =
        网站->;创建服务<;接口示例::服务::触发器>;("ping";, 及样品;);

    // 记录服务已准备就绪
    RCLCPP_INFO(rclcpp::get_logger(ping_server";), 即可食用;);

    // 运行节点
    rclcpp::后旋(网站);
    rclcpp::关闭();
}

在名为 src/ping_client.cpp 内容如下

#include 时间顺序<chrono>;
#include <内存>;

#include "rclcpp/rclcpp.hpp";
#include "example_interfaces/srv/trigger.hpp";

使用 命名空间 标准::计时器;

int 主要(int 参数, 烧焦 **参数)
{
    rclcpp::启动(参数, 参数);

    // 创建节点和客户端
    标准::共享_ptr<;rclcpp::节点>; 网站 = rclcpp::节点::共享("ping_client";);
    rclcpp::客户<;接口示例::服务::触发器>::SharedPtr 客户 =
        网站->;创建客户端<;接口示例::服务::触发器>;("ping";);

    // 创建一个请求
    汽车 要求 = 标准::共享<;接口示例::服务::触发器::要求>;();

    // 等待服务可用
    虽然 (!客户->;等待服务(1s)) {
        如果 (!rclcpp::好的()) {
            RCLCPP_ERROR(rclcpp::get_logger("ping_client";), 等待服务时被中断。退出;);
            返回 0;
        }
        RCLCPP_INFO(rclcpp::get_logger("ping_client";), 服务不可用,请再次等待...";);
    }

    // 现在服务可用,请发送请求
    RCLCPP_INFO(rclcpp::get_logger("ping_client";), 发送请求";);
    汽车 结果 = 客户->;异步发送请求(要求);

    // 等待结果并将其记录到控制台
    如果 (rclcpp::自旋直到未来完成(网站, 结果) ==
        rclcpp::未来返回代码::成功)
    {
        RCLCPP_INFO(rclcpp::get_logger("ping_client";), 收到回复";);
    } 不然 {
        RCLCPP_ERROR(rclcpp::get_logger("ping_client";), 调用 ping 服务失败;);
    }

    rclcpp::关闭();
    返回 0;
}

打开 CMakeLists.txt 文件,并添加两个新的可执行文件 ping_serviceping_client:

查找软件包(接口示例 要求)

添加可执行(ping_service src/ping_service.cpp)
ament_target_dependencies(ping_service 接口示例 rclcpp)

添加可执行(ping_client src/ping_client.cpp)
ament_target_dependencies(ping_client 接口示例 rclcpp)

安装(目标
    ping_service
    目的地 lib/${项目名称})

安装(目标
    ping_client
    目的地 lib/${项目名称})

最后,构建软件包。

为服务和客户端创建 XML 配置文件

创建一个文件,文件名为 ping.xml 内容如下

<?xml version="1.0" encoding="UTF-8" ?>;
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles";>;

    默认出版商配置文件 -->;
    <publisher profile_name="default_publisher"; is_default_profile="true";>;
        历史内存政策<historyMemoryPolicy>;动态</historyMemoryPolicy>;
    </publisher>;

    <!-- 默认用户配置文件 -->;
    订阅者 profile_name="default_subscriber"; is_default_profile="true";>;
        历史内存政策<historyMemoryPolicy>;动态</historyMemoryPolicy>;
    /订阅者>;

    服务发布者为 SYNC;
    <publisher profile_name=服务";>;
        历史内存政策<historyMemoryPolicy>;动态</historyMemoryPolicy>;
        qos>;
            <publishMode>;
                <种类>;同步</kind>;
            </publishMode>;
        </qos>;
    </publisher>;

    <! -- 客户端发布者为 ASYNC -->;
    <publisher profile_name="客户";>;
        历史内存政策<historyMemoryPolicy>;动态</historyMemoryPolicy>;
        qos>;
            <publishMode>;
                <种类>;ASYNCHRONOUS</kind>;
            </publishMode>;
        </qos>;
    </publisher>;

</profiles>;

该配置文件将发布模式设置为 同步 服务,并 ASYNCHRONOUS 在客户端上。请注意,我们只定义了服务和客户端的发布者配置文件,但也可以提供订阅者配置文件。

执行节点

打开两个终端,在每个终端上输入设置文件。然后设置加载 XML 所需的环境变量:

export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
export RMW_FASTRTPS_USE_QOS_FROM_XML=1
export FASTRTPS_DEFAULT_PROFILES_FILE=path/to/ping.xml

在第一个终端上运行服务节点。

ros2 run sync_async_node_example_cpp ping_service

您会看到服务正在等待请求:

[INFO] [1612977403.805799037] [ping_server]:准备就绪。

在第二个终端上运行客户端节点。

ros2 run sync_async_node_example_cpp ping_client

您应该看到客户端发送请求并接收响应:

[INFO] [1612977404.805799037] [ping_client]:发送请求
[INFO] [1612977404.825473835] [ping_client]:收到响应

同时,服务器控制台的输出也已更新:

[INFO] [1612977403.805799037] [ping_server]:准备就绪。
[INFO] [1612977404.807314904] [ping_server]:收到请求
[INFO] [1612977404.836405125] [ping_server]:发回响应