ros2_01

发布于:2025-04-15 ⋅ 阅读:(76) ⋅ 点赞:(0)

note01

ROS2和ROS最大的区别中间件

中间件:

  1. 介于某两个或者多个节点中间的组件;
  2. 提供多个节点中间通信;

ROS1:中间件是ROS组织自己基于TCP机制建立的,随着现在传感器的升级,数据量越来越大,原先的数据拷贝机制就不再适了

ROS2:

  1. 将进程间通信intra-process自己来做
  2. 其他部分的通信就使用来DDS实现
  3. ROS2将DDS服务接口进行了一层抽象,保证了上层应用层调用接口的统一性
  4. ROS2去掉mater节点

DDS

Data Distribution Service:一种用于分布式系统的通信中间件标准

key points:

  1. 发布-订阅模式
    1. 数据生产者(Publisher)发布数据到主题(Topic)
    2. 数据消费者(Subscriber)订阅感兴趣的主题
    3. 发布者和订阅者之间是解耦的,不需要知道彼此的存在
  2. 数据为中心:
    1. DDS以数据为中心,而不是以节点为中心
    2. 数据通过主题进行标识,主题是数据的逻辑分类
  3. 实时性:
    1. DDS设计用于实时系统,支持低延迟和高吞吐量的数据传输

Domain

定义:一个逻辑隔离的通信空间,只有在同一个域中的节点才能互相通信;每个域有一个唯一的 Domain ID,用于标识不同的域

作用:

  1. 隔离通信:不同域中的节点无法互相通信,即使它们在同一个网络中
  2. 灵活性:可以通过 Domain ID 将系统划分为多个独立的通信空间

Fast DDS中的Domain 通过 DomainParticipant 来管理的

#include <fastdds/dds/domain/DomainParticipant.hpp>
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>

int main() {
    // 创建 DomainParticipant
    eprosima::fastdds::dds::DomainParticipant* participant =
        eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->create_participant(0);

    // 检查是否创建成功
    if (participant == nullptr) {
        std::cerr << "Failed to create DomainParticipant!" << std::endl;
        return -1;
    }

    std::cout << "DomainParticipant created successfully!" << std::endl;

    // 清理资源
    eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->delete_participant(participant);
    return 0;
}
  1. DomainParticipantFactory
    1. 用于创建和管理 DomainParticipant
    2. 通过 get_instance() 获取单例对象
  2. create_participant(domain_id)
    1. 创建一个 DomainParticipant,参数 domain_id 指定域的 ID
    2. 返回一个指向 DomainParticipant 的指针
  3. delete_participant(participant)
    1. 删除 DomainParticipant,释放资源
Topic

Topic是数据的逻辑分离,每个 Topic 有一个名称和一个数据类型;

发布者(Publisher)将数据发布到 Topic,订阅者(Subscriber)从 Topic 中订阅数据

作用:

  1. 数据分类:通过 Topic 将数据分类,例如“温度数据”或“位置数据”
  2. 解耦:发布者和订阅者不需要知道彼此的存在,只需要知道 Topic 的名称和数据类型
#include <fastdds/dds/domain/DomainParticipant.hpp>
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
#include <fastdds/dds/topic/Topic.hpp>
#include <fastdds/dds/topic/TypeSupport.hpp>

// 自定义数据类型
class HelloWorld {
public:
    std::string message;
};

int main() {
    // 创建 DomainParticipant
    eprosima::fastdds::dds::DomainParticipant* participant =
        eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->create_participant(0);

    // 注册数据类型
    eprosima::fastdds::dds::TypeSupport type(new HelloWorldPubSubType());
    type.register_type(participant);

    // 创建 Topic
    eprosima::fastdds::dds::Topic* topic = participant->create_topic(
        "HelloWorldTopic",  // Topic 名称
        type.get_type_name(),  // 数据类型名称
        eprosima::fastdds::dds::TOPIC_QOS_DEFAULT  // QoS 配置
    );

    if (topic == nullptr) {
        std::cerr << "Failed to create Topic!" << std::endl;
        return -1;
    }

    std::cout << "Topic created successfully!" << std::endl;

    // 清理资源
    participant->delete_topic(topic);
    eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->delete_participant(participant);
    return 0;
}
  1. TypeSupport:
    1. 用于注册和管理数据类型
    2. HelloWorldPubSubType 是自动生成的数据类型支持
  2. create_topic(name, type_name, qos)
    1. 创建一个 Topic,参数包括 Topic 名称、数据类型名称和 QoS 配置
    2. 返回一个指向 Topic 的指针
  3. delete_topic(topic)
    1. 删除 Topic,释放资源

Publisher 和 Subscriber

  1. Publisher:负责将数据发布到 Topic
  2. Subscriber:负责从 Topic 订阅数据

Topic实现:

  1. 观察者模式(Observer Pattern)
    1. Topic 是数据的逻辑分类,发布者(Publisher)和订阅者(Subscriber)通过 Topic 进行解耦
    2. 发布者将数据发布到 Topic,Topic 负责将数据分发给所有订阅了该 Topic 的订阅者
  2. 中介者模式(Mediator Pattern)
    1. Topic 充当发布者和订阅者之间的中介者,负责管理数据的传递
    2. 发布者和订阅者不需要直接交互,而是通过 Topic 进行通信

Publisher实现:

  1. Publisher 通过 DomainParticipant 的工厂方法(如 create_publisher)创建
  2. 代理模式(Proxy Pattern)
    1. Publisher 是数据发布的代理,负责将数据写入 DDS 中间件
    2. 实际的网络通信和数据传输由 DDS 中间件处理,Publisher 只是一个接口
  3. Publisher 内部维护了一个或多个 DataWriter,用于将数据写入 Topic

DataWriter

DataWriter是publisher一部分,负责将数据写入topic

  1. 数据写入:将应用程序生成的数据发布到 DDS 中间件
  2. QoS 管理:根据配置的 QoS 策略(如可靠性、持久性等)处理数据
  3. 生命周期管理:管理数据的生命周期,例如数据的创建、更新和删除

ROS2的DDS

DDS抽象:
  1. 节点:
    1. ROS 2 引入了 Node 的概念,封装了 DDS 中的 DomainParticipant
    2. 只需要创建和管理 Node,而不需要直接操作 DomainParticipant
  2. Publisher和Subscriber
    1. ROS 2 的 PublisherSubscriber 是对 DDS 中 DataWriterDataReader 的封装
    2. 只需要指定 Topic 名称和数据类型,ROS 2 会自动处理底层的 DDS 对象
  3. 消息Message
    1. ROS 2 使用 消息 作为数据传输的基本单位,消息类型通过 .msg 文件定义
  4. 统一的API
    1. ROS 2 通过 RMW(ROS Middleware Interface) 抽象了底层 DDS 实现的差异
    2. 每种 DDS 实现(如 Fast DDS、Cyclone DDS)都有一个对应的 RMW 实现
    3. 通过环境变量选择使用的 DDS 实现