【FastDDS】Layer DDS之Publisher (06-DataWriterListener)

Fast DDS中的DataWriterListener总结

一、DataWriterListener的基本定义

DataWriterListener是一个抽象类,用于定义在数据写入器(DataWriter)状态发生变化时触发的回调函数。默认情况下,所有回调函数均为不执行任何操作的空实现。用户需通过实现该类的特化版本,重写应用程序所需的回调函数;未被重写的回调函数将保持空实现。

二、核心回调函数及功能

DataWriterListener定义了以下关键回调函数,用于响应DataWriter的各类事件:

  1. on_publication_matched()
    当DataWriter找到与主题(Topic)匹配、分区相同且QoS兼容的DataReader,或与之前匹配的DataReader停止匹配时触发。

  2. on_offered_deadline_missed()
    当DataWriter未能在其DataWriterQos配置的截止期限内提供数据时触发。对于每个截止期限周期和未按时提供数据的数据实例,该回调都会被调用。

  3. on_offered_incompatible_qos()

#include <fastdds/dds/domain/DomainParticipantFactory.hpp> #include <fastrtps/fastdds/dds/domain/DomainParticipant.hpp> #include <fastdds/dds/topic/Topic.hpp> #include <fastdds/dds/publisher/Publisher.hpp> #include <fastdds/dds/publisher/DataWriter.hpp> #include <fastdds/dds/publisher/qos/DataWriterQos.hpp> #include <fastdds/dds/core/status/StatusMask.hpp> #include <fastdds/dds/log/Log.hpp> #include <thread> #include <iostream> #include "PosPubSubTypes.h" using namespace eprosima::fastdds::dds; int main() { // 创建 DomainParticipant DomainParticipant* participant = DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT); if (!participant) { std::cerr << "创建 participant 失败" << std::endl; return 1; } // 注册类型 TypeSupport type(new topic_01::msg::PosPubSubType()); type.register_type(participant); // 创建 Topic Topic* topic = participant->create_topic("rt/pos_topic", "topic_01/msg/Pos", TOPIC_QOS_DEFAULT); if (!topic) { std::cerr << "创建 topic 失败" << std::endl; return 1; } // 创建 Publisher Publisher* publisher = participant->create_publisher(PUBLISHER_QOS_DEFAULT, nullptr); if (!publisher) { std::cerr << "创建 publisher 失败" << std::endl; return 1; } // 创建 DataWriter DataWriter* writer = publisher->create_datawriter(topic, DATAWRITER_QOS_DEFAULT, nullptr); if (!writer) { std::cerr << "创建 writer 失败" << std::endl; return 1; } // 随机数初始化 std::srand(static_cast<unsigned>(std::time(nullptr))); topic_01::msg::Pos msg; for (int i = 0; i < 100000; ++i) { for (int j = 0; j < 4; ++j) { msg.coordinates()[j] = static_cast<float>(std::rand() % 100) / 10.0f; } writer->write(&msg); std::cout << "发送消息: ["; for (int j = 0; j < 4; ++j) { std::cout << msg.coordinates()[j]; if (j != 3) std::cout << ", "; } std::cout << "]" << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } // 清理资源 participant->delete_contained_entities(); DomainParticipantFactory::get_instance()->delete_participant(participant); return 0; } 为什么这样发布的话题,ROS2的订阅者订阅不到?
07-08
<think>我们正在解决一个具体问题:使用Fast DDS API编写的发布者无法被ROS2订阅者接收到消息。我们需要分析可能的原因并提供解决方法。 根据引用[2]和[4],Fast DDS是ROS2默认的中间件,因此理论上使用Fast DDS API编写的发布者应该能够与ROS2节点通信。但是,由于ROS2使用的是Fast DDS的特定版本,并且可能进行了封装,因此直接使用Fast DDS API编写发布者时,需要注意与ROS2的兼容性。 可能的原因: 1. **主题(Topic)名称和类型不匹配**:ROS2使用特定的命名规则和类型系统。如果发布者和订阅者使用的主题名称或消息类型不完全一致,通信将失败。 2. **QoS设置不匹配**:ROS2默认使用特定的QoS策略(例如可靠性为RELIABLE,持久性为VOLATILE)。如果使用Fast DDS API编写的发布者使用了不同的QoS设置(例如BEST_EFFORT),而ROS2订阅者要求RELIABLE,则无法通信。 3. **域ID(Domain ID)不匹配**:ROS2默认使用域ID为0。如果发布者使用了不同的域ID,则订阅者无法接收到消息。 4. **消息定义不一致**:即使消息名称相同,如果发布者和订阅者使用的消息定义(如字段顺序、类型)不同,也会导致通信失败。 5. **安全设置**:如果启用了ROS2的安全功能(如DDS-Security),而Fast DDS发布者未配置相应的安全插件和证书,则通信会被阻止。 解决方法: 1. **检查主题名称和类型**: - 确保发布者和订阅者使用相同的主题名称(包括大小写和命名空间)。 - 确保消息类型完全一致(包括包名、消息名和字段定义)。例如,ROS2订阅者期望的消息类型可能是`std_msgs::msg::String`,而Fast DDS发布者应该发布相同类型的消息。 2. **检查QoS设置**: -Fast DDS发布者端,设置QoS与ROS2默认的QoS兼容。例如,设置可靠性为RELIABLE,持久性为VOLATILE,历史设置为KEEP_LAST。 - 在ROS2订阅者端,可以尝试设置兼容的QoS策略,例如使用`rmw_qos_profile_sensor_data`(该配置文件使用BEST_EFFORT可靠性)或者自定义QoS策略以匹配发布者。 3. **检查域ID**: - 在ROS2中,可以通过设置环境变量`ROS_DOMAIN_ID`来指定域ID。在Fast DDS发布者程序中,也需要设置相同的域ID(通过DomainParticipant的配置)。 4. **验证消息定义**: - 确保Fast DDS发布者使用的消息类型与ROS2订阅者期望的消息类型在IDL定义上完全一致。ROS2的消息类型是由`.msg`文件生成的,而Fast DDS发布者需要使用相同的IDL生成代码。 5. **检查安全设置**: - 如果ROS2启用了安全功能,则需要在Fast DDS发布者端配置相应的安全插件(如PKCS#11)并提供正确的证书。或者,暂时在ROS2端关闭安全功能(不推荐用于生产环境)进行测试。 具体步骤示例(使用Fast DDS API编写发布者): 1. 使用与ROS2相同的IDL文件生成Fast DDS的发布者代码。 2. 在发布者代码中,设置域ID与ROS2环境相同(通过环境变量`ROS_DOMAIN_ID`获取,默认为0)。 3. 配置QoS策略以匹配ROS2的默认QoS: ```cpp eprosima::fastdds::dds::ReliabilityQosPolicy reliability; reliability.kind = eprosima::fastdds::dds::RELIABLE_RELIABILITY_QOS; ``` 4. 确保主题名称与ROS2订阅者订阅的主题名称一致(包括命名空间,如果有)。 另外,引用[1]提到Vulcanexus会更新Fast DDS版本,而ROS2可能使用较旧的Fast DDS版本。因此,版本不兼容也可能导致问题。确保ROS2和Fast DDS发布者使用相同版本的Fast DDS库。 如果问题仍然存在,可以尝试使用Wireshark(配合RTPS协议解析插件)来捕获网络数据包,检查发布者是否在发送数据,以及数据包的结构是否符合RTPS标准。 总结:使用Fast DDS API编写的发布者与ROS2订阅者通信的关键在于确保主题、类型、QoS、域ID和安全设置完全匹配。此外,版本兼容性也是重要因素。 相关问题: 1. ROS 2中如何查看当前使用的DDS实现? 2. 如何配置ROS 2节点的QoS策略? 3. 如何验证ROS 2与Fast DDS之间的通信问题? 4. ROS 2中如何设置域ID? 5. 如何在Fast DDS中启用安全功能?</think>### Fast DDS发布者无法被ROS 2订阅者接收消息的原因及解决方法 #### 核心原因分析 1. **QoS策略不匹配** ROS 2默认使用`RELIABLE`可靠性策略和`VOLATILE`持久性策略[^2],而Fast DDS发布者可能配置了`BEST_EFFORT`策略。当发布者QoS策略与订阅者不兼容时,通信会失败。 2. **域ID冲突** ROS 2默认使用域ID=0。如果Fast DDS发布者设置了不同的域ID(如默认值0以外的值),ROS 2节点将无法发现该发布者[^2]。 3. **消息类型不兼容** ROS 2使用特定格式的TypeObject进行类型发现: ```cpp // ROS 2生成的类型标识符 eprosima::fastrtps::types::TypeObject* ros2_type_object = topic_01::msg::Pos::get_type_object(); ``` 若Fast DDS发布者未使用完全相同的类型定义(包括字段顺序和类型),类型系统将拒绝匹配[^4]。 4. **安全机制冲突** ROS 2默认禁用DDS-Security,而Fast DDS发布者可能启用了PKCS#11等安全插件(引用[1])。安全配置不匹配会导致握手失败。 #### 解决方案 ##### 1. 强制QoS策略匹配(关键步骤) 在Fast DDS发布者端显式设置兼容的QoS: ```cpp eprosima::fastdds::dds::DataWriterQos qos; qos.reliability().kind = eprosima::fastdds::dds::RELIABLE_RELIABILITY_QOS; qos.durability().kind = eprosima::fastdds::dds::VOLATILE_DURABILITY_QOS; qos.history().kind = eprosima::fastdds::dds::KEEP_LAST_HISTORY_QOS; qos.history().depth = 10; // 需与ROS2订阅者一致 writer->set_qos(qos); ``` ##### 2. 统一域ID配置 在ROS 2订阅者启动前设置环境变量: ```bash export ROS_DOMAIN_ID=0 # 确保与Fast DDS发布者相同 ros2 run your_package your_subscriber_node ``` 在Fast DDS代码中显式指定域ID: ```cpp eprosima::fastdds::dds::DomainParticipant* participant = participant_factory->create_participant(0, PARTICIPANT_QOS_DEFAULT); ``` ##### 3. 验证类型一致性 使用ROS 2生成的类型支持代码: ```cpp // 在Fast DDS发布者端包含ROS 2生成的头文件 #include "topic_01/msg/pos.hpp" // 注册完全相同的类型 eprosima::fastdds::dds::TypeSupport ts(new topic_01::msg::PosPubSubType()); ts.register_type(participant); ``` ##### 4. 禁用安全插件(测试阶段) 在Fast DDS发布者中关闭安全特性: ```xml <!-- XML配置示例 --> <profiles> <participant profile_name="disable_security"> <rtps> <useBuiltinTransports>true</useBuiltinTransports> </rtps> </participant> </profiles> ``` #### 诊断工具 1. **ROS 2发现检查** ```bash ros2 topic list --verbose # 检查发布者域ID和GUID ``` 2. **Fast DDS监视器** 使用`fastdds discovery server`工具验证实体发现状态: ```bash fastdds discovery --server-id 0 ``` 3. **Wireshark抓包分析** 过滤RTPS协议包(端口7400-7500),检查`DATA`子消息是否被正确发送和接收。 > **关键提示**:Vulcanexus发行版已集成PKCS#11支持(引用[1]),若需启用安全通信,需在ROS 2中同步配置DDS-Security参数[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ray.so

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值