RealSense RealDDS Flexible 消息主题完全指南IDL 结构、JSON/CBOR 编解码与 QoS 策略【免费下载链接】librealsenseRealSense SDK项目地址: https://gitcode.com/GitHub_Trending/li/librealsense本文围绕 LibreRealSense 仓库中 RealDDS 子系统third-party/realdds的Flexible 消息主题展开。Flexible 是一种万能载荷型 DDS 消息格式设备发现device-info、控制control、通知notification、元数据metadata等所有非流式话题都复用它。读完本文你将掌握 Flexible 消息的 IDL 数据结构、JSON/CBOR/CUSTOM 三种数据格式的编码规则、C 封装flexible_msg的读写用法、其 QoS 约定以及如何通过官方脚本在 DDS 网络上直接发送 Flexible 消息进行联调验证。什么是 Flexible 消息在 RealDDS 的话题体系中数据流图像、IMU走 ROS2 兼容的专用消息类型而大量控制面信息——设备信息、客户端请求、服务端通知、帧元数据——格式各异、演进频繁为每种消息单独定义结构体成本过高。Flexible 消息正是为此设计只要数据体积不超过 IDL 规定的上限它可以承载任意格式的任意数据。依据 flexible/readme.md该目录下的文件绝大部分由 IDL 自动生成因此理解 Flexible 消息的第一步就是阅读其 IDL 定义。IDL 数据结构与字段语义Flexible 消息的权威定义位于 flexible.idl其核心结构如下仓库内实际 IDL注意与 readme 中示例的差异见下文大小上限一节module realdds { module topics { module raw { enum flexible_data_format { FLEXIBLE_DATA_JSON, FLEXIBLE_DATA_CBOR, FLEXIBLE_DATA_CUSTOM }; struct flexible { flexible_data_format data_format; octet version[4]; // in decreasing importance, so version[0] is highest sequenceoctet,32768 data; // bound to 32KB }; }; }; };结构体包含三个字段字段类型语义data_format枚举flexible_data_format声明data载荷的编码格式取值FLEXIBLE_DATA_JSON/FLEXIBLE_DATA_CBOR/FLEXIBLE_DATA_CUSTOMversionoctet[4]4 字节数组消息格式版本号按重要性递减排列version[0]为最高位字节datasequenceoctet, 32768实际载荷字节序列上限 32768 字节32KB由 IDL 生成的 C 类型realdds::topics::raw::flexible位于 flexible.h枚举以uint32_t为底层类型结构体则通过data_format()、version()、data()三组访问器暴露成员并附带 CDR 序列化/反序列化接口serialize/deserialize、最大序列化尺寸计算getMaxCdrSerializedSize等 FastDDS 生成代码的标配方法可直接用于 FastDDS 的DataWriter/DataReader。大小上限readme 与 IDL 的差异说明readme 中给出的示例将data序列上限写为40964K 字节并声称当前上限为 4K 字节而仓库中实际的 flexible.idl 已将上限定为3276832KB。撰写代码时请以仓库内的 IDL 文件为准——该上限直接决定了单条 Flexible 消息可携带的最大字节数超出部分在序列化阶段即会失败。这也解释了为何 metadata、device-info 这类 JSON 消息体积虽小但控制/通知类消息仍被约束在数十 KB 以内。版本字段的约定按 readme 说明当前所有 Flexible 消息的版本一律为0。不过在 C 封装层见下文中版本号以uint32_t形式传入并在序列化时被拆分为 4 个八位字节version[0]对应最高字节——这一高位在前的字节序约定在跨端解析版本号时务必保持一致。三种数据格式JSON、CBOR 与 CUSTOMreadme 明确指出格式通常是 JSON但也可以是其他格式CUSTOM 和 CBOR 当前已定义但并未真正投入使用。三种格式的语义如下JSONdata是 JSON 文本的字符表示每字符 1 字节即 UTF-8/ASCII 文本字节流。这是当前 RealDDS 控制面消息的事实标准格式。CBORdata是同一份 JSON 数据的二进制表示Concise Binary Object Representation体积更小、解析更快适合对载荷大小敏感的场景。CUSTOM字节由客户端使用自己的数据结构自行解释RealDDS 不提供任何内置解析逻辑。源码级的编解码实现C 封装类 flexible_msg 通过构造函数与访问方法将上述语义落地其实现位于 flexible-msg.cppJSON 编码flexible_msg( rsutils::json const j, uint32_t version 0 )将 JSON 对象j.dump()为字符串后逐字节拷入std::vectoruint8_tdata_format固定为JSON。CBOR 编码flexible_msg( data_format format, rsutils::json const j, uint32_t version 0 )中当format CBOR时调用rsutils::json::to_cbor( j )生成二进制载荷若传入CUSTOM与 JSON 组合实现会直接抛出runtime_errorinvalid format for json flexible message印证了 CUSTOM 目前仅支持原始字节、不支持 JSON 转换。解码json_data()根据_data_format分发——JSON 载荷用rsutils::json::parse( begin, end )解析文本CBOR 载荷用rsutils::json::from_cbor( ... )反解而对非 JSON 数据如 CUSTOM则抛出non-json flexible data is still unsupported异常。从源码结构看CUSTOM 载荷目前主要面向custom_dataT()模板方法——它把_data缓冲区按reinterpret_castT const*直接映射为自定义结构体指针适用于发送方与接收方共享同一套内存布局定义的场景。版本号的字节序处理to_raw()将flexible_msg转回原始raw::flexible展示了版本号的完整打包逻辑raw_msg.version()[0] _version 24 0xFF; raw_msg.version()[1] _version 16 0xFF; raw_msg.version()[2] _version 8 0xFF; raw_msg.version()[3] _version 0xFF;反向解包则发生在flexible_msg( raw::flexible )构造函数中将 4 个字节重新拼回uint32_t。这一整型版本号 ↔ 4 字节大端数组的双向转换是阅读或扩展 Flexible 消息时最容易踩坑的细节。话题类型与 DDS 命名Flexible 消息对应的 DDS topic type 为realdds::topics::raw::flexible在实际使用中话题名称并不固定为 flexible——Flexible 是一种被复用的消息格式而非单一话题。依据 topics/readme.md 的话题层级以下话题全部使用 Flexible 消息格式realsense/ ├── device-info — 设备发现广播Flexible/JSON ├── model_serial/ — 每台设备的话题根目录 │ ├── notification — 服务端通知、响应、日志Flexible/JSON │ ├── control — 客户端对服务端的请求Flexible/JSON │ └── metadata — 可选的流元数据Flexible/JSONQoS 例外 rt/realsense/ — ROS2 兼容的数据流非 Flexible典型载荷示例设备发现device-info——见 discovery.mdJSON 中的name与topic-root为必填字段{ name: Intel RealSense D405, serial: 123622270732, product-line: D400, topic-root: realsense/D405_123622270732 }服务端通知notification——见 notifications.md所有通知必须是 JSON 对象并以id字段标识类型未识别的字段和通知会被客户端忽略{ id: some-message-id, message: this is a field value }帧元数据metadata——见 metadata.mdtimestamp是客户端与图像帧同步的关键字段{ stream-name: Color, header: {frame-number: 1234, timestamp: 123456789, timestamp-domain: 0}, metadata: {Exposure: 123, Gain: 456} }metadata 的消息格式完全由 Flexible 承载——这既是灵活的体现也带来了协议约定成本metadata 的字段名必须与rs2_frame_metadata_to_string返回的名字一致、值必须为整型long long否则会被忽略或标记为缺失。QoS 策略可靠传输与一个例外依据 flexible/readme.md所有 Flexible 话题通常使用可靠reliable传输与采用 best-effort 的数据流形成对比除非另有说明Reliability可靠性RELIABLEDurability持久性VOLATILE唯一的例外是 metadata 话题由于元数据体积小、频率高、丢失后不影响图像本身客户端仅失去与该帧关联的元数据metadata.md 将其 QoS 定为BEST_EFFORTVOLATILE。设计权衡在于best-effort 下消息可能丢失但图像流不会因元数据缺失而中断而 device-info、control、notification 属于必须送达的控制面消息因此坚持 RELIABLE。从 IDL 到代码FastDDSGen 生成流程Flexible 消息的 C 头文件、PubSubTypes、TypeObject 均由 FastDDS 的FastDDSGen工具从 IDL 生成。由于该工具依赖 Java 且版本挑剔官方推荐的流程是使用 Docker 镜像离线生成详见 topics/readme.md当前仓库生成所使用的是 FastDDS 2.10.6从 eProsima 下载 FastDDS 套件 Docker 镜像并加载docker load -i /mnt/c/work/ubuntu-fastdds-suite\ v2.10.6.tar在third-party/realdds/目录下对每个 topic此处为flexible执行容器内生成for topic in flexible do cd include/realdds/topics/${topic} ciddocker run -itd --privileged ubuntu-fastdds:v2.10.6 docker exec $cid mkdir /idl /idl/out docker cp *.idl $cid:idl/ docker exec -w /idl/out $cid fastddsgen -cs -typeobject /idl/ls -1 *.idl docker cp $cid:/idl/out . docker kill $cid cd out for cxx in *.cxx; do mv -- $cxx ../../../../../src/topics/${cxx%.cxx}.cpp; done mv -- *TypeObject.h ../../../../../src/topics/ mv * .. cd .. rmdir out cd ../../../.. done该脚本自动完成.cxx→.cpp重命名、输出文件归位等操作。生成后仍需手工处理更新.cpp中的#include例如#include flexible.h需改为#include realdds/topics/flexible/flexible.h并将版权头替换为 LibRealSense 的版权声明。仓库内 flexible.h 文件头部的// This file was generated by the tool gen.注释即为上述流程的产物标记对应的 flexiblePubSubTypes.h、flexibleTypeObject.cpp 等文件分布在include/realdds/topics/flexible/与 src/topics 中。实战用 topic-send.py 收发 Flexible 消息RealDDS 提供了 Python 绑定pyrealdds与两个脚本工具可直接在 DDS 网络上收发 Flexible 消息非常适合验证话题连通性与 JSON 载荷格式。发送脚本位于 scripts/topic-send.py接收脚本为同目录下的topic-sink.py。向任意话题发送 JSON Flexible 消息python topic-send.py --topic /my/topic --message {data:value}脚本内部调用dds.message.flexible.create_topic( participant, topic_path )创建话题、以dds.message.flexible( message ).write_to( writer )发送——即将 JSON 对象按上文描述的 JSON 编码规则序列化为 Flexible 载荷。发送成功后write_to返回该样本的唯一序列号若传入--ack参数脚本会调用writer.wait_for_acks(...)等待对端确认可靠传输下写入返回不代表对方已收到等待 ack 才能确保投递。向真实设备发送控制消息python topic-send.py --device /realsense/D555_serial_number --message {id:ping}该模式先以dds.device( participant, info )构造设备代理、等待其就绪再通过device.send_control( message, wait_for_reply )将请求发送到设备的control话题并等待回复——回复同样是 Flexible 格式的 JSON。关键命令行参数参数说明--device path设备话题根目录如/realsense/D555_serial指定后消息发往该设备的 control 话题--topic path任意 DDS 话题路径与--device二选一互斥--message json内联 JSON 消息--message-file file从 JSON 文件读取消息-表示 stdin与--message互斥--blob file以 blob 消息发送二进制文件需配合--topic--domain 0-232DDS 域编号默认 0不同域之间互不可见--ack发送后等待对端确认--debug/--quiet开启调试输出 / 静默模式脚本中对 Flexible/控制类消息使用默认的可靠 QoSdds.topic_writer.qos()返回 reliable 配置而对 blob 大文件则额外配置了流控参数max-bytes-per-period256 × 1470 字节、周期 250ms用于避免大块数据瞬时打爆接收端缓冲——这是理解 Flexible 话题与流式话题在传输策略上差异的又一佐证。总结Flexible 消息是 RealDDS 控制面的通用信封以 flexible.idl 中格式枚举 4 字节版本号 32KB 上限字节序列的三段式结构承载了设备发现、控制请求、服务端通知与帧元数据四类话题。其默认 QoS 为RELIABLE/VOLATILEmetadata 话题则降级为BEST_EFFORT以换取流式场景的鲁棒性JSON 是当前事实标准编码CBOR 为二进制备选CUSTOM 留给自定义结构体直读。无论是阅读 flexible-msg.cpp 的编解码实现、复用 FastDDSGen 生成新 IDL还是用 topic-send.py 在网络上直接发送载荷进行调试本文给出的结构、字节序与 QoS 约定都能作为最直接的参照。【免费下载链接】librealsenseRealSense SDK项目地址: https://gitcode.com/GitHub_Trending/li/librealsense创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考