ROS2软件架构全面解析-rmw软件框架

前言

本章是详细介绍ROS2通信中间件中rmw模块软件框架。
不了解背景的同学请先看:

  • ROS2软件架构全面解析-学习如何设计通信中间件框架: link

rmw框架

  • rmw是为兼容各种DDS组件而设计的中间件抽象层:the middleware abstraction layer called rmw (ROS MiddleWare)
  • 用户可以根据性能、软件许可或支持的平台等各种约束条件,选择不同的RMW 实现,也就是基于DDS协议的组件
  • 提供丰富的自由度让用户选择DDS协议实现组件,只要实现了rmw Layer规定的接口就可以装载到ROS2系统中完成消息传递

rmw软件架构

  • rmw Layer本人划分是主要两个文件夹:rmw、rmw_implementation
    在这里插入图片描述
  • rmw Layer主要的内容是规定DDS组件的功能接口:rmw.h、init.h 头文件,本身逻辑功能不多。rmw_validate_node_name实现在rmw Layer validate_node_name.c文件中,对node name 有效性进行验证,算逻辑代码多的文件了。
  • rmw_implementation模块中有一个动态函数调用框架,能够把DDS实现组件的函数接口直接提供给rcl Layer调用,能够让rcl Layer调用到DDS组件中。
//function.cpp
RMW_INTERFACE_FN(
  rmw_send_response,
  rmw_ret_t, RMW_RET_ERROR,
  3, ARG_TYPES(const rmw_service_t *, rmw_request_id_t *, void *))
  • rmw_send_response就是在rcl Layer service.c文件中调用的,rmw implementation通过RMW_INTERFACE_FN进行封装动态调用到选择的DDS组件。主要功能是在RMW_INTERFACE_FN Macro中。
#define CALL_SYMBOL(symbol_name, ReturnType, error_value, ArgTypes, arg_values) \
  if (!symbol_ ## symbol_name) { \
    /* only necessary for functions called before rmw_init */ \
    symbol_ ## symbol_name = get_symbol(#symbol_name); \
  } \
  if (!symbol_ ## symbol_name) { \
    /* error message set by get_symbol() */ \
    return error_value; \
  } \
  typedef ReturnType (* FunctionSignature)(ArgTypes); \
  FunctionSignature func = reinterpret_cast<FunctionSignature>(symbol_ ## symbol_name); \
  return func(arg_values);

// cppcheck-suppress preprocessorErrorDirective
#define RMW_INTERFACE_FN(name, ReturnType, error_value, _NR, ...) \
  void * symbol_ ## name = nullptr; \
  ReturnType name(EXPAND(ARGS_ ## _NR(__VA_ARGS__))) \
  { \
    CALL_SYMBOL( \
      name, ReturnType, error_value, ARG_TYPES(__VA_ARGS__), \
      EXPAND(ARG_VALUES_ ## _NR(__VA_ARGS__))); \
  }

  • RMW_INTERFACE_FN Macro用于定义一个函数,CALL_SYMBOL Macro调用负责动态加载调用传入名字的函数体
  • 比如rmw implementation设置的cyclonedds就会调入到如下代码实现
// rmw_node.cpp    rmw_cyclonedds_cpp文件夹目录
extern "C" rmw_ret_t rmw_send_response(
  const rmw_service_t * service,
  rmw_request_id_t * request_header, void * ros_response){}

rmw集成方式

  • rmw模组通过CMake会编译为rmw库,然后再rcl CMakeList中引入编译,使用的时候直接引入头文件就可以使用接口函数
// rmw CMakeLists.txt
cmake_minimum_required(VERSION 3.5)

project(rmw)

# Default to C99
if(NOT CMAKE_C_STANDARD)
  set(CMAKE_C_STANDARD 99)
endif()

//rcl CMakeLists.txt
# specific order: dependents before dependencies
ament_target_dependencies(${PROJECT_NAME}
  "rcl_interfaces"
  "rcl_logging_interface"
  "rcl_yaml_param_parser"
  "rcutils"
  "rmw"
  "rmw_implementation"
  ${RCL_LOGGING_IMPL}
  "rosidl_runtime_c"
  "tracetools"
)
  • rmw implementation package.xml支持集成rmw_connextdds、rmw_cyclonedds、rmw_fastrtps几种DDS实现,具体使用是通过RMW_IMPLEMENTATION系统属性设置的。

DDS组件

  • 目前提供三种DDS实现:connextdds、cyclonedds、fastrtps。
  • 还有一个dds_common作为一个共有的DDS模块,提供功能支持对其他差异化DDS。
### 关于轻量级 ROS 或简化版 ROS #### micro-ROSROS) micro-ROS 是一种专为微控制器单元(MCU)设计的轻量级 ROS 实现[^1]。它基于 FreeRTOS 构建,旨在满足资源受限设备的需求。通过使用中间层抽象,micro-ROS 提供了与传统 ROS 类似的 API 接口,从而使得开发人员能够在 MCU 上运行复杂的机器人算法。 以下是 micro-ROS 的一些关键特性: - **跨平台支持**:兼容多种硬件架构和操作系统。 - **低资源消耗**:针对 RAM 和 CPU 使用进行了优化,适合嵌入式系统。 - **实时性能**:利用 FreeRTOS 的调度能力,确保任务间的高效切换。 ```c #include <stdio.h> #include "uros_network_interface.h" int main(void) { setvbuf(stdout, NULL, _IONBF, 0); printf("Starting the uROS demo for ESP32\n"); // Initialize Micro-ROS transport uint8_t buffer[256]; rmw_esp32_serial_transport_init(buffer, sizeof(buffer), "/dev/ttyUSB0", 115200); rcl_allocator_t allocator = rcl_get_default_allocator(); rclc_support_t support; // Create init_options rclc_support_init(&support, 0, NULL, &allocator); return 0; } ``` #### r2r 另一种轻量级解决方案是 `r2r`,这是 ROS 2 的 Rust 绑定项目[^2]。相比传统的 C++/Python 实现,`r2r` 更加现代化且易于维护。由于其独立于 ROS 2 原生构建工具链的设计,开发者可以通过简单的 `cargo build` 来完成项目的编译工作。此外,`r2r` 支持动态生成消息类型绑定,进一步降低了配置复杂度。 以下是 r2r 的核心优势: - **快速迭代**:无需繁琐的 `.msg` 文件转换过程即可直接操作数据结构。 - **高性能**:得益于 Rust 编程语言的安全性和效率保障。 - **模块化扩展**:允许用户灵活定制所需的依赖项以缩短构建周期。 ```rust use std::time::Duration; use r2r::{Context, Node}; fn main() -> Result<(), Box<dyn std::error::Error>> { let context = Context::create()?; let mut node = Node::create(context, "talker_node", "")?; loop { println!("hello world"); node.spin_once(Duration::from_millis(100))?; } } ``` #### 设计权衡与局限性分析 尽管这些轻量化变体提供了诸多便利之处,但在实际应用过程中也面临一定挑战。例如,默认采用 TCP/IP 协议作为主要通信手段可能会增加内存开销并影响整体吞吐率表现[^3]。与此同时,为了适应小型化需求所做的裁剪可能导致部分高级特性的缺失,比如复杂的图形界面调试工具或者分布式计算框架的支持不足等问题。 另外值得注意的是,在某些极端条件下即使经过高度精简后的代码仍然可能存在体积过大风险。对此可通过引入条件编译选项等方式进一步压缩最终产物尺寸[^5]。 --- ### 数据流优化策略 考虑到 XML-RPC 所带来的额外负载并不适用于所有场景尤其是涉及高频次交互场合下,则有必要探索其他更高效的替代方案。在这种背景下诞生了一个专门面向大规模连续型信号传输而制定的标准——即自定义二进制协议[^4]。该方式不仅能够显著降低单条信息所占字节数比例同时还减少了解析环节耗时现象发生几率进而达到提升响应速度的目的。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值