中间件作为嵌入式系统的核心组件,为应用程序提供通信支持、应用支持和公共服务。机器人操作系统(ROS)作为最流行的嵌入式中间件之一,为机器人开发提供了强大的框架支持。本文将深入解析ROS的核心概念、系统架构、通信机制,并通过树莓派实战演示ROS应用开发。

一、中间件基础概念

1.1 中间件定义与功能

中间件是介于应用系统和系统软件之间的软件层,使用系统软件提供的基础服务,衔接网络上应用系统的各个部分或不同的应用,实现资源共享和功能共享。主要提供三大功能:

  • 通信支持:早期分布式中间件采用远程调用和消息两种通信方式

  • 应用支持:为上层应用开发提供统一平台和运行环境

  • 公共服务:对应用软件中共性功能或约束的提取和复用

1.2 嵌入式系统中间件特性

在嵌入式系统中,中间件处于嵌入式应用和操作系统之间,主要作用是对嵌入式应用屏蔽底层操作系统的异构性。由于嵌入式应用场景差异,不同系统通常集成不同的中间件,需要支持移动环境、流媒体应用、DRE环境等多样化需求。

二、ROS核心概念解析

2.1 ROS本质与定位

ROS(Robot Operating System)本质上是一个中间件而非传统操作系统,被称为"元操作系统"或"机器人软件框架"。其设计理念可表述为:

ROS = Plumbing + Tools + Capabilities + Ecosystem
  • Plumbing:通信机制

  • Tools:开发工具

  • Capabilities:应用功能

  • Ecosystem:生态系统

ROS需要运行在现有操作系统(如Linux)之上,专注于机器人开发中的通信、设备驱动、数据可视化等。

2.2 ROS发展历程

ROS发展经历了多个重要阶段:

  • 2007年:ROS最初版本发布

  • 2010年:ROS 1.0版本推出

  • 2015年:ROS 2.0开始开发

  • 2017年:ROS 2.0首个稳定版发布

2.3 ROS核心特点

  1. 点对点设计:分布式网络架构,节点间通过RPC+TCP/UDP通信

  2. 多语言支持:支持Python、C++、Java等编程语言

  3. 架构精简:功能节点可单独编译,集成众多开源项目

  4. 工具丰富:3D可视化工具、物理仿真环境、数据记录工具等

  5. 开源免费:BSD许可,可修改、可复用、可商用

三、ROS系统架构详解

3.1 系统层次结构

ROS系统从维护和分布角度分为两大板块:

main核心部分:Willow Garage公司和开发者维护,提供分布式计算基础工具

universe全球代码:各国ROS社区维护,包括库代码和应用级代码

从功能角度分为三个级别:

计算图级(程序运行描述)
  • 节点(Node):执行具体任务的进程,可分布式运行

  • 话题(Topic):节点间传输数据的总线,采用发布/订阅模型

  • 服务(Service):使用客户端/服务器模型,支持双向通信

  • 节点管理器(ROS Master):为节点提供命名注册服务

文件系统级(程序组织)
  • 功能包(Package):ROS软件组织基本形式

  • 功能包集(Stack):多个功能包集合

  • 消息类型(Message):进程间传递的信息格式

  • 服务类型(Service):服务通信的请求与应答数据类型

社区级(资源共享)
  • 发行版:可独立安装的版本化功能包集

  • 软件源:共享代码的网站或主机服务

  • ROS Wiki:主要技术文档论坛

  • 邮件列表:主要交流渠道

3.2 软件层次架构

从实现角度分为三个层次:

  • OS层:建立在Linux之上,提供硬件抽象和底层驱动

  • 中间层:封装OS层接口,提供TCPROS/UDPROS通信

  • 应用层:调用中间层接口实现各种应用功能

四、ROS通信机制深度解析

4.1 话题通信机制

话题通信采用发布/订阅模型,实现流程如下:

  1. Talker向ROS Master注册

  2. Listener向ROS Master注册

  3. ROS Master进行信息匹配

  4. Listener向Talker发送连接请求

  5. Talker确认连接请求

  6. 建立网络连接并传输数据

# 话题发布者示例
#!/usr/bin/env python
import rospy
from std_msgs.msg import String

def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('talker', anonymous=True)
    rate = rospy.Rate(10) # 10hz
    
    while not rospy.is_shutdown():
        hello_str = "hello world %s" % rospy.get_time()
        rospy.loginfo(hello_str)
        pub.publish(hello_str)
        rate.sleep()

if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException:
        pass

4.2 服务通信机制

服务通信采用请求/响应模型,适合强逻辑处理场景:

  1. Server向ROS Master注册

  2. Client向ROS Master注册

  3. ROS Master进行信息匹配

  4. Client与Server建立连接

  5. 进行请求-响应通信

4.3 参数通信机制

通过参数服务器实现节点间参数共享:

  1. Talker设置参数值

  2. Listener查询参数值

  3. ROS Master返回参数值

4.4 话题与服务对比

条目 话题 服务
同步性 异步 同步
通信模型 发布/订阅 客户端/服务器
实时性
适用场景 数据传输 逻辑处理

五、ROS2架构革新

5.1 从ROS到ROS2的演进

ROS1存在实时性不足、资源管理弱等问题,ROS2进行了重大架构升级:

  • 架构颠覆:告别Master,使用基于DDS的Discovery机制

  • API重新设计:保持类似用法但更现代化

  • 编译系统升级:使用ament、colcon替代catkin

  • 多平台支持:支持Linux、Windows、macOS、RTOS等

5.2 DDS通信核心

ROS2采用以数据为中心的发布/订阅(DCPS)模型,创建"全局数据空间"。DDS核心实体包括:

  • 参与者(Participant):对应ROS节点

  • 发布者(Publisher):数据发布执行者

  • 订阅者(Subscriber):数据订阅执行者

  • 数据写入器(DataWriter):特定话题的消息发布者

  • 数据读取器(DataReader):特定话题的消息订阅者

5.3 QoS服务质量策略

ROS2引入丰富的QoS策略,用户可通过选择不同配置文件优化通信表现:

  • 发布/订阅机制的QoS设定

  • 服务QoS设定

  • 传感器数据QoS设定

  • 参数QoS设定

六、树莓派ROS实战演练

6.1 环境准备与安装

# 安装基础工具
dnf install wget yum tree git python3-devel

# 配置ROS环境
echo "source /opt/ros/noetic/setup.bash" >> ~/.bash_profile
source ~/.bash_profile

# 安装Python依赖
pip3 install empy==3.3.2

6.2 第一个ROS程序:小海龟仿真

# 启动ROS核心
roscore

# 新终端启动小海龟仿真
rosrun turtlesim turtlesim_node

# 新终端控制小海龟
rosrun turtlesim turtle_teleop_key

6.3 话题通信实战编程

创建ROS工作区和功能包:

# 创建工作区
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace

# 创建功能包
catkin_create_pkg my_ros_pkg roscpp std_msgs

# 编译工作区
cd ~/catkin_ws
catkin_make

话题发布者代码示例:

// topic_publisher.cpp
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>

int main(int argc, char **argv)
{
    ros::init(argc, argv, "talker");
    ros::NodeHandle n;
    ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
    ros::Rate loop_rate(10);

    int count = 0;
    while (ros::ok()) {
        std_msgs::String msg;
        std::stringstream ss;
        ss << "hello world " << count;
        msg.data = ss.str();
        
        ROS_INFO("%s", msg.data.c_str());
        chatter_pub.publish(msg);
        ros::spinOnce();
        loop_rate.sleep();
        ++count;
    }
    return 0;
}

话题订阅者代码示例:

// topic_subscriber.cpp
#include "ros/ros.h"
#include "std_msgs/String.h"

void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
    ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
    ros::init(argc, argv, "listener");
    ros::NodeHandle n;
    ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
    ros::spin();
    return 0;
}

6.4 自定义消息控制小海龟

通过编程实现小海龟圆周运动:

#!/usr/bin/env python
import rospy
from geometry_msgs.msg import Twist

def turtle_circle():
    rospy.init_node('turtle_controller', anonymous=True)
    pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)
    rate = rospy.Rate(10)
    
    while not rospy.is_shutdown():
        vel_msg = Twist()
        vel_msg.linear.x = 1.0  # 线速度
        vel_msg.angular.z = 1.0  # 角速度
        
        pub.publish(vel_msg)
        rate.sleep()

if __name__ == '__main__':
    try:
        turtle_circle()
    except rospy.ROSInterruptException:
        pass

七、ROS在openEuler上的移植优化

7.1 混合关键性部署

openEuler Embedded支持混合关键性部署,通过Jailhouse框架实现实时与非实时任务隔离:

# 启用Jailhouse
jailhouse enable /usr/share/jailhouse/cells/rpi4.cell

# 创建Linux cell
jailhouse cell linux /usr/share/jailhouse/cells/rpi4-linux.cell \
/boot/Image -d /usr/share/jailhouse/cells/dts/inmate-rpi4.dtb \
-c "console=ttyAMA1,115200 root=/dev/mmcb1k0p2"

7.2 实时性优化策略

  • 中断线程化:减少关中断时间,提高系统可抢占性

  • 优先级继承:解决优先级反转问题

  • 自旋锁优化:采用Qspinlock减少CPU资源浪费

附录:常用命令速查

功能

命令

查看节点

rosnode list

查看话题

rostopic list

消息发布

rostopic pub

包管理

rospack find

编译工作区

catkin_make

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐