Ros2 qos自定义策略实现方式(c c++ python)

本文深入探讨了ROS2中的服务质量(QoS)策略,包括历史记录、深度、可靠性及持久性等关键策略,并介绍了如何在C++和Python中自定义QoS策略,以实现高效可靠的数据通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Ros2 qos简介

用于节点之前的数据通信,为了保证数据能够可靠和高校的传输。ROS2提供了一套非常丰富的服务质量(Quality of Service, QoS)策略

Ros2 qos 注意事项

发布器、订阅器、服务端和客户端可以指定Profile,且它们的每个实例都可以单独指定Profile,但不兼容的Profiles可能导致无法通信。

Qos策略

当前,QoS Profile提供了对以下QoS策略的设置:

(1)历史记录(History)

保留近期记录(Keep last):缓存最多N条记录,可通过队列长度选项来配置。

保留所有记录(Keep all):缓存所有记录,但受限于底层中间件可配置的最大资源。

(2)深度(Depth)

队列深度(Size of the queue):只能与Keep last配合使用。

(3)可靠性(Reliability)

尽力的(Best effort):尝试传输数据但不保证成功传输(当网络不稳定时可能丢失数据)。

可靠的(Reliable):反复重传以保证数据成功传输。

(4)持续性(Durability)

局部瞬态(Transient local):发布器为晚连接(late-joining)的订阅器保留数据。

易变态(Volatile):不保留任何数据。

以上每个策略都有系统默认值。这个默认值就是底层中间件的默认值,由DDS供应商工具(如XML配置文件)定义。DDS本身提供了许多可配置的策略。这些策略与ROS1的特征相似,所以在ROS1中是可见的。之后可能会有更多的策略在ROS2中可见。

自定义Ros2 qos 策略

  • c版

  • 首先创建一个default_qos.h,添加自定义的策略


#ifndef RCL_ACTION__DEFAULT_QOS_H_
#define RCL_ACTION__DEFAULT_QOS_H_

#ifdef __cplusplus
extern "C"
{
#endif

#include "rmw/types.h"


static const rmw_qos_profile_t rcl_msg_qos_profile_status_default =
{
  RMW_QOS_POLICY_HISTORY_KEEP_LAST,
  10,
  RMW_QOS_POLICY_RELIABILITY_RELIABLE,
  RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL,
  RMW_QOS_DEADLINE_DEFAULT,
  RMW_QOS_LIFESPAN_DEFAULT,
  RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT,
  RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT,
  false
};

#ifdef __cplusplus
}
#endif

#endif

  • 第二步把定义好策略赋值到qos的结构体中

int start_msg(rcl_node_t* node, rclc_support_t* support)
{
  rcl_node_options_t node_ops = rcl_node_get_default_options();
  RCCHECK(rcl_node_init(node, "char_long_sequence_subscriber_rcl", "", &support->context, &node_ops))
  rcl_subscription_options_t subscription_ops = rcl_subscription_get_default_options();
  rcl_subscription_t subscription = rcl_get_zero_initialized_subscription();
  //设置配置好的qos策略
  subscription_ops.qos = rcl_msg_qos_profile_status_default;
  RCCHECK(rcl_subscription_init(&subscription, node, ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, String), "string data", &subscription_ops))
  rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
  RCCHECK(rcl_wait_set_init(&wait_set, 1, 0, 0, 0, 0, 0, &support->context, rcl_get_default_allocator()))
  std_msgs__msg__String msg;
  msg.data.data = (char * ) malloc(ARRAY_LEN * sizeof(char));
  msg.data.size = 0;
  msg.data.capacity = ARRAY_LEN;
  char test_array[ARRAY_LEN];
  memset(test_array,'z',ARRAY_LEN);
  do {
    RCSOFTCHECK(rcl_wait_set_clear(&wait_set))
    size_t index;
    RCSOFTCHECK(rcl_wait_set_add_subscription(&wait_set, &subscription, &index))
    RCSOFTCHECK(rcl_wait(&wait_set, RCL_MS_TO_NS(1)))
    if (wait_set.subscriptions[index]) {
      rcl_ret_t rc = rcl_take(wait_set.subscriptions[index], &msg, NULL, NULL);
      if (RCL_RET_OK == rc) {
        
        // Check if sequence items matches the know pattern
        bool pass_test = strncmp(test_array, msg.data.data, msg.data.size) == 0;

        printf("I received an %ld array. Test: [%s]\n", msg.data.size, (pass_test) ? "OK" : "FAIL");
      }
    }
  } while ( true );
  RCCHECK(rcl_subscription_fini(&subscription, node))
  RCCHECK(rcl_node_fini(node))
  return 0;
}

  • python 版自定义qos策略添加
import rclpy
from rclpy.node import Node
from rclpy.qos import DurabilityPolicy
from rclpy.qos import QoSProfile
from rclpy.qos_event import SubscriptionEventCallbacks

from std_msgs.msg import String


class MinimalSubscriber(Node):

    def __init__(self):
        #创建qos对象
        qos = QoSProfile(depth=10)
        #设置不同的qos策略
        qos.durability = DurabilityPolicy.RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL

        custom_callback = lambda event: print("Custom Incompatible Callback!")
        callbacks = SubscriptionEventCallbacks()
        callbacks.incompatible_qos = custom_callback

        super().__init__('minimal_subscriber')
        #qos策略传入
        self.subscription = self.create_subscription(
            String,
            'string data',
            self.listener_callback,
            qos,
            event_callbacks=callbacks)

    def listener_callback(self, msg):
        self.get_logger().info('I heard: "%s"' % msg.data)


def main(args=None):
    rclpy.init(args=args)

    minimal_subscriber = MinimalSubscriber()

    rclpy.spin(minimal_subscriber)

    minimal_subscriber.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()
  • c++版 自定义Qos策略添加


#include <iostream>
#include <functional>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

int main(int argc, char ** argv)
{
  rclcpp::init(argc, argv);

  auto node = std::make_shared<rclcpp::Node>("qos_callback_listener");
  rclcpp::SubscriptionOptions options;

  rclcpp::QoS qos(0);
  qos.reliable();
  qos.durability(RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL);

  options.use_default_callbacks = false;
  options.event_callbacks.incompatible_qos_callback = [](rclcpp::QOSOfferedIncompatibleQoSInfo & event) {
    std::cout << "Custom Incompatible Callback!" << std::endl;
  };

  auto subscriber = node->create_subscription<std_msgs::msg::String>(
    "/string data",
    qos,
    [](const std_msgs::msg::String::SharedPtr) {
      std::cout << "Heard a message" << std::endl;
    },
    options);

  rclcpp::spin(node);
  return 0;
}

<think>嗯,用户想在PythonROS2实现内存共享。首先,我需要回忆一下ROS2中的共享内存机制。根据引用[3],ROS2可以通过Fast DDS的共享内存中间件来实现进程间通信,这样能减少数据拷贝,提高性能。所以,可能需要配置Fast DDS的参数来启用共享内存。 然后,用户提到了PythonROS2支持Python 3,如引用[4]所说,但Python本身在内存共享方面可能不如C++方便。不过Python有multiprocessing模块,可以创建共享内存变量,比如Value和Array。但这是进程间的共享,可能和ROS2的节点间共享内存不同。 接下来,用户需要教程式的方法。可能需要分步骤说明:首先配置Fast DDS,然后编写发布者和订阅者节点,使用共享内存传输数据。同时,可能需要使用Python的ctypes或共享内存模块来处理内存区域。 另外,引用[1]提到共享物理内存中的队列结构,一个写一个读。在ROS2中,可能需要设置传输配置,让发布者和订阅者使用共享内存传输。例如,在创建Publisher和Subscriber时,设置QoS策略,启用共享内存。 需要注意的是,Python中直接操作共享内存可能较复杂,可能需要结合C++扩展或者使用ROS2提供的中间件配置。或者,使用rclpy的API来设置传输选项,比如在发布时指定传输为共享内存。 总结步骤可能是:1. 安装必要的ROS2和Fast DDS;2. 配置Fast DDS的XML文件,启用共享内存;3. 编写Python节点,设置QoS策略使用共享内存;4. 测试数据传输是否通过共享内存进行。 还要考虑用户可能遇到的常见问题,比如配置错误,或者Python版本兼容性(如引用[4]提到的Python 3.5+)。另外,可能需要验证共享内存是否生效,例如通过性能测试或监控工具查看内存使用情况。</think>### PythonROS2内存共享实现方法 在ROS2实现内存共享主要依赖Fast DDS中间件的共享内存功能。以下是具体实现步骤: #### 一、环境配置 1. 安装支持共享内存的ROS2版本(推荐Humble或Iron) 2. 确认Fast DDS版本(需≥2.3.0) 3. 安装Python共享内存支持库: ```bash pip install shared_memory ``` #### 二、Fast DDS配置 创建`shared_memory.xml`配置文件: ```xml <?xml version="1.0" encoding="UTF-8" ?> <profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles"> <transport_descriptors> <transport_descriptor> <transport_id>SharedMemoryTransport</transport_id> <type>SHM</type> <segment_size>1048576</segment_size> </transport_descriptors> </profiles> ``` #### 三、Python节点实现 ```python import rclpy from rclpy.node import Node from std_msgs.msg import String class SharedMemoryPublisher(Node): def __init__(self): super().__init__('shm_publisher') self.publisher = self.create_publisher( String, 'shm_topic', qos_profile=rclpy.qos.QoSProfile( reliability=rclpy.qos.ReliabilityPolicy.RELIABLE, durability=rclpy.qos.DurabilityPolicy.VOLATILE ) ) class SharedMemorySubscriber(Node): def __init__(self): super().__init__('shm_subscriber') self.subscription = self.create_subscription( String, 'shm_topic', self.listener_callback, qos_profile=rclpy.qos.QoSProfile( reliability=rclpy.qos.ReliabilityPolicy.RELIABLE, durability=rclpy.qos.DurabilityPolicy.VOLATILE ) ) ``` #### 四、启动配置 设置环境变量指定传输层: ```bash export RMW_IMPLEMENTATION=rmw_fastrtps_cpp export FASTRTPS_DEFAULT_PROFILES_FILE=shared_memory.xml ``` #### 五、验证方法 1. 使用`top`命令观察内存占用 2. 通过Fast DDS监控工具检查传输方式: ```bash fastdds discovery --server-id 0 ``` ### 关键技术点 1. **共享内存分配**:使用Fast DDS的SHM传输类型直接分配共享内存段[^3] 2. **零拷贝机制**:发布/订阅使用相同内存区域,避免数据复制[^1] 3. **QoS配置**:必须设置`VOLATILE`耐久性和`RELIABLE`可靠性策略[^2]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值