ROS2学习(13)------ 数据分发服务DDS
- 操作系统:ubuntu22.04
- IDE:Visual Studio Code
- 编程语言:C++11
- ROS版本:2
ROS 2(Robot Operating System 2)采用了Data Distribution Service (DDS)作为其底层通信中间件,以提供灵活且强大的分布式通信能力。与ROS 1使用的基于TCPROS/UDPROS的通信机制不同,ROS 2通过DDS支持更广泛的特性,如发现机制、服务质量(QoS)策略和跨网络的无缝通信等。以下是关于ROS 2中DDS的一些关键点说明:
算法描述
1. DDS简介
DDS是一个由对象管理组(OMG)定义的用于实时系统中的数据分发的中间件标准。它旨在为分布式应用提供高效可靠的数据传输服务,特别适用于需要高可靠性、实时性和可扩展性的环境。
2. ROS 2与DDS的关系
ROS 2通过抽象层封装了对多种DDS实现的支持,允许用户在不同的DDS供应商之间进行选择。这使得ROS 2不仅能够利用DDS提供的高级特性,还能根据具体应用场景的需求选择最适合的DDS实现。
支持的DDS实现包括但不限于:
- Fast DDS(原eProsima Fast RTPS):ROS 2默认使用的DDS实现。
- Cyclone DDS:性能优越,社区活跃。
- RTI Connext 和 ADLINK OpenSplice:商业级解决方案,适用于需要高度可靠性和性能的企业级应用。
3. 使用DDS的优势
- 自动发现机制:节点可以自动发现网络上的其他参与者,并建立连接,无需手动配置。
- 服务质量(QoS)策略:提供了丰富的QoS设置选项,允许用户根据需求调整通信行为,例如持久化消息、历史深度、可靠性等。
- 多语言支持:虽然ROS 2主要使用C++和Python,但DDS本身支持多种编程语言,便于集成到异构环境中。
- 安全性:一些DDS实现提供了加密、身份验证等安全功能,增强了系统的安全性。
4. 如何在ROS 2中选择和配置DDS实现
- 选择DDS实现:可以通过设置RMW_IMPLEMENTATION环境变量来指定要使用的DDS实现。例如,使用Cyclone DDS:
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
- 安装DDS实现:通常需要额外安装你想要使用的DDS实现。例如,在Ubuntu上安装Cyclone DDS:
sudo apt update && sudo apt install ros-<ros2-distro>-rmw-cyclonedds-cpp
- QoS配置:可以在创建发布者、订阅者、客户端或服务时指定QoS策略。以下是一个简单的例子,展示了如何为发布者设置可靠的QoS策略:
auto qos = rclcpp::QoS(rclcpp::KeepLast(10));qos.reliable();auto publisher = node->create_publisher<std_msgs::msg::String>("topic_name", qos);
5. 注意事项
- 兼容性问题:尽管ROS 2设计为与任何符合DDS标准的实现兼容,但在实际操作中可能会遇到某些特定于某个DDS实现的功能或限制。
- 资源消耗:不同的DDS实现在内存占用、CPU使用等方面可能有所不同,部署前应考虑目标平台的资源限制。
- 安全性配置:如果需要启用安全性功能,需确保所选的DDS实现支持这些特性,并正确配置相应的安全参数。
通过上述介绍,你应该对ROS 2如何利用DDS进行高效的分布式通信有了基本了解。ROS 2结合DDS的能力,使得开发者能够构建更加复杂、健壮的机器人系统。
DDS示例
下面我将提供一个简单的C++示例,展示如何在ROS 2中使用DDS进行通信。这个例子会包括创建一个发布者和订阅者,并且我们会介绍如何配置一些基本的服务质量(QoS)策略。
示例:发布者与订阅者
准备工作
确保你已经安装了ROS 2以及所需的DDS实现(如Fast DDS或Cyclone DDS)。如果没有,请参考ROS 2官方文档来安装适合你操作系统的版本。
创建包
首先,我们需要创建一个新的ROS 2包来存放我们的示例代码。
cd ~/ros2_ws/src
ros2 pkg create --build-type ament_cmake cpp_ddsdemo --dependencies rclcpp std_msgs
这将在~/ros2_ws/src目录下创建一个名为cpp_ddsdemo的新包,并添加必要的依赖项。
编写发布者代码
在cpp_ddsdemo包的src目录下创建一个名为talker.cpp的文件,并添加以下代码:
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"class Talker : public rclcpp::Node {
public:Talker() : Node( "talker" ){publisher_ = this->create_publisher< std_msgs::msg::String >( "chatter", 10 );auto qos_profile = rclcpp::QoS( rclcpp::KeepLast( 10 ) );qos_profile.reliable();timer_ = this->create_wall_timer( std::chrono::milliseconds( 500 ), std::bind( &Talker::publish_message, this ) );}private:void publish_message(){auto message = std_msgs::msg::String();message.data = "Hello, DDS!";RCLCPP_INFO( this->get_logger(), "Publishing: '%s'", message.data.c_str() );publisher_->publish( message );}rclcpp::Publisher< std_msgs::msg::String >::SharedPtr publisher_;rclcpp::TimerBase::SharedPtr timer_;
};int main( int argc, char* argv[] )
{rclcpp::init( argc, argv );rclcpp::spin( std::make_shared< Talker >() );rclcpp::shutdown();return 0;
}
编写订阅者代码
同样地,在src目录下创建另一个名为listener.cpp的文件,并添加以下代码:
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"class Listener : public rclcpp::Node {
public:Listener() : Node( "listener" ){auto qos_profile = rclcpp::QoS( rclcpp::KeepLast( 10 ) );qos_profile.reliable();subscription_ = this->create_subscription< std_msgs::msg::String >( "chatter", qos_profile, std::bind( &Listener::topic_callback, this, std::placeholders::_1 ) );}private:void topic_callback( const std_msgs::msg::String::SharedPtr msg ) const{RCLCPP_INFO( this->get_logger(), "I heard: '%s'", msg->data.c_str() );}rclcpp::Subscription< std_msgs::msg::String >::SharedPtr subscription_;
};int main( int argc, char* argv[] )
{rclcpp::init( argc, argv );rclcpp::spin( std::make_shared< Listener >() );rclcpp::shutdown();return 0;
}
运行演示
base) dingxin@dev01:/media/dingxin/data/projects/ros2/ros2_ws$ colcon build --packages-select cpp_ddsdemo
Starting >>> cpp_ddsdemo
Finished <<< cpp_ddsdemo [0.10s] Summary: 1 package finished [0.25s]
(base) dingxin@dev01:/media/dingxin/data/projects/ros2/ros2_ws$ source install/setup.bash
(base) dingxin@dev01:/media/dingxin/data/projects/ros2/ros2_ws$ ros2 run cpp_ddsdemo talker &
ros2 run cpp_ddsdemo listener
[1] 1160036
[INFO] [1748245206.358214598] [talker]: Publishing: 'Hello, DDS!'
[INFO] [1748245206.358651899] [listener]: I heard: 'Hello, DDS!'
[INFO] [1748245206.858210334] [talker]: Publishing: 'Hello, DDS!'
[INFO] [1748245206.858562915] [listener]: I heard: 'Hello, DDS!'
[INFO] [1748245207.358192083] [talker]: Publishing: 'Hello, DDS!'
[INFO] [1748245207.358469411] [listener]: I heard: 'Hello, DDS!'
[INFO] [1748245207.858307761] [talker]: Publishing: 'Hello, DDS!'
[INFO] [1748245207.858611755] [listener]: I heard: 'Hello, DDS!'
[INFO] [1748245208.358326562] [talker]: Publishing: 'Hello, DDS!'
[INFO] [1748245208.358733223] [listener]: I heard: 'Hello, DDS!'
[INFO] [1748245208.858240497] [talker]: Publishing: 'Hello, DDS!'
[INFO] [1748245208.858584031] [listener]: I heard: 'Hello, DDS!'
[INFO] [1748245209.358235552] [talker]: Publishing: 'Hello, DDS!'
[INFO] [1748245209.358555639] [listener]: I heard: 'Hello, DDS!'
[INFO] [1748245209.858258810] [talker]: Publishing: 'Hello, DDS!'
[INFO] [1748245209.858585246] [listener]: I heard: 'Hello, DDS!'
你应该能看到发布者每半秒发送一次消息,而订阅者接收并打印这些消息。