ROS 2 通信与 QoS

ROS 2 把通信下沉给 DDS,QoS 成为决定「能否连上、延迟多少、丢不丢包」的核心接口。本文讲清 RMW 抽象与 DDS 实现选型、QoS 策略全解与匹配协商机制、deadline 与 liveliness 事件、发现机制与静态端点、Zenoh 等新 RMW、零拷贝与共享内存、实时执行器交互、多机网络拓扑与通信诊断调优。

引言

ROS 2 最根本的架构决策是把通信下沉给 DDS,自己只保留一层薄薄的抽象(RMW)。这个决策带来一个后果:ROS 2 的通信行为,尤其是「能不能连上」「延迟多少」「丢不丢包」,几乎完全由 QoS 与底层 DDS 实现决定,而不由 ROS 2 的 API 决定。

工程上的第一个难点是 QoS 的匹配规则。两个端点即使话题名与类型都一致,只要 QoS 不兼容就「静默连不上」——没有报错、没有警告,订阅者就是不收数据。这是 ROS 2 新手最迷惑的问题,也是现场最难查的一类故障。理解 QoS 的兼容矩阵是排查这类问题的前提。

第二个难点是 DDS 实现的选择。ROS 2 支持多个 RMW 实现(Fast DDS、CycloneDDS、Zenoh),它们在中低负载下行为相似,但在节点数、话题数、网络拓扑复杂时表现差异巨大。选错实现会让「系统规模一上去就启动慢、CPU 高」。

第三个难点是实时性。通信层与执行器(executor)的交互方式决定了回调的调度延迟。控制回路对通信抖动极其敏感,而 DDS 默认的线程模型与内存分配并不为实时设计。本文聚焦通信层本身,节点的生命周期、参数系统与整体架构见ROS2 架构:节点、DDS 与生命周期 ,话题/服务/动作的工程写法见 ROS2 实战:话题、服务与动作 。

目录

  1. 通信层在 ROS 2 中的位置
  2. RMW 抽象与 DDS 实现选型
  3. QoS 策略全解
  4. QoS 匹配与协商机制
  5. deadline、liveliness 与事件
  6. 发现机制:SDP、Discovery Server 与静态端点
  7. Zenoh 与新型 RMW
  8. 实时性与执行器的交互
  9. 零拷贝与共享内存传输
  10. 多机通信与网络拓扑
  11. 通信诊断与性能剖析
  12. 选型与调参清单

1. 通信层在 ROS 2 中的位置

ROS 2 的通信栈是分层的,理解每层职责才能定位问题出在哪一层。

分层结构(自下而上):
  DDS 实现(Fast DDS / CycloneDDS / Zenoh)
    —— 提供发布订阅、发现、序列化、传输
  RMW(ROS Middleware)接口层
    —— 把 DDS 的 API 抽象成 ROS 2 需要的统一接口
    —— rmw_fastrtps_cpp / rmw_cyclonedds_cpp / rmw_zenoh_cpp
  rcl(ROS Client Library 通用层)
    —— 话题/服务/动作的通用逻辑,与语言无关
  rclcpp / rclpy
    —— C++ 与 Python 的客户端库,面向用户
关键认知:
  ROS 2 的「话题」概念映射到 DDS 的「Topic」+「DataWriter/DataReader」
  ROS 2 的「服务」映射到 DDS 的两个 Topic(请求与响应)
  ROS 2 的「动作」映射到 DDS 的三个服务(目标、结果、反馈)
  QoS 直接映射到 DDS 的 QoS 策略,ROS 2 只做了少量预设封装

切换 RMW 只需环境变量,不改代码:
  export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp

因为 QoS 是「透传」到 DDS 的,所以 DDS 的 QoS 语义就是 ROS 2 的 QoS 语义。理解这一点后,很多「ROS 2 行为诡异」的问题都可以用 DDS 的文档来解释,而不是在 ROS 2 层面猜。

2. RMW 抽象与 DDS 实现选型

RMW 是 ROS 2 与 DDS 之间的适配层,选择哪个 RMW 是通信调优的第一决策。

三个主流 RMW 的定位:
  1. rmw_fastrtps_cpp(Fast DDS,默认):生态最完整、工具齐全
     (Discovery Server、Monitor),但默认线程模型偏激进,
     节点多时线程数爆炸。适合中小规模、要官方工具
  2. rmw_cyclonedds_cpp(CycloneDDS):内存与线程占用低、组播可控、
     稳定性口碑好,TRANSIENT_LOCAL 样本数需显式配置。
     适合资源受限平台、大规模节点、长期运行
  3. rmw_zenoh_cpp(Zenoh,较新):天然支持广域网、路由与穿透。
     适合跨网段、跨机房、云端协同(详见第 7 节)
实测经验(20 节点、100 话题、千兆网、空闲):
  Fast DDS 默认  :CPU 约 15%,启动 3 s
  CycloneDDS 默认:CPU 约 6%,启动 1.5 s
  结论:节点数增长时 CycloneDDS 的差距会进一步拉大

线程数对比(每节点默认):
  Fast DDS:为每个端点可能开多个线程,100 话题可达数百线程
  CycloneDDS:线程模型更省,通常几十个

选型的判断顺序是「规模 → 资源 → 工具需求」。小规模(< 20 节点)用默认的 Fast DDS 即可;中大规模(> 50 节点)或资源受限平台优先 CycloneDDS;跨网络拓扑用 Zenoh。切换 RMW 后必须重跑一遍 QoS 兼容性检查,因为两者对边界情况(如 KEEP_ALL 的容量上限)的默认行为不同。

3. QoS 策略全解

QoS 策略是通信行为的完整控制面板,常用的是三项,但全部策略在特定场景都重要。

Reliability(可靠性):
  RELIABLE     :保证送达,失败重传(TCP 语义)
  BEST_EFFORT  :尽力送达,可能丢(UDP 语义)
Durability(持久性):
  VOLATILE       :只给当前及之后的订阅者
  TRANSIENT_LOCAL:为晚加入的订阅者保留历史(地图、标定结果)
History(历史):KEEP_LAST(n) 只保留最近 n 条;KEEP_ALL 全保留
Depth(队列深度):与 History 配合,决定缓存多少条
Deadline(截止时间):数据必须在指定周期内更新,否则触发事件
Liveliness(活跃性):AUTOMATIC 由 DDS 判定存活;MANUAL_BY_TOPIC 显式声明
Lifespan(寿命):消息超过指定时间自动失效,不再投递
Ownership(所有权):SHARED 多发布者共存;EXCLUSIVE 配合 OwnershipStrength
DestinationOrder:BY_RECEPTION_TIME / BY_SOURCE_TIMESTAMP
ResourceLimits:限制历史、样本、实例数量
// 自定义 QoS:中等深度 + 可靠 + 保留历史
rclcpp::QoS qos(100);                  // depth = 100
qos.reliable();
qos.transient_local();
qos.deadline(rclcpp::Duration::from_seconds(0.1));  // 100ms 未更新则告警
qos.liveliness(rclcpp::LivelinessPolicy::Automatic);
qos.lifespan(rclcpp::Duration::from_seconds(1.0));  // 1s 后失效

auto pub = create_publisher<sensor_msgs::msg::PointCloud2>("/points", qos);
标准预设(覆盖 90% 场景):
  rclcpp::SensorDataQoS()    // BEST_EFFORT, KEEP_LAST 5, VOLATILE
  rclcpp::SystemDefaultsQoS()// RELIABLE, KEEP_LAST 10, VOLATILE
  rclcpp::ServicesQoS()      // RELIABLE, KEEP_LAST 10(服务用)
  rclcpp::ParametersQoS()    // RELIABLE + TRANSIENT_LOCAL(参数事件)

选型经验:传感器数据一律 BEST_EFFORT(旧帧无价值,丢帧优于延迟);状态、命令、地图用 RELIABLE;地图与标定结果用 TRANSIENT_LOCAL(晚启动的节点也能拿到)。

4. QoS 匹配与协商机制

QoS 不兼容不会报错,只会「连不上」,理解兼容规则是排查的关键。

兼容规则(发布者的能力必须 ≥ 订阅者的要求):
  Reliability:RELIABLE 发布可被 BEST_EFFORT 订阅(兼容)
              BEST_EFFORT 发布不能被 RELIABLE 订阅(不兼容!)
  Durability :TRANSIENT_LOCAL 发布可被 VOLATILE 订阅(兼容)
              VOLATILE 发布不能被 TRANSIENT_LOCAL 订阅(不兼容)
  Deadline   :发布的 deadline 必须 ≤ 订阅要求的 deadline
  Liveliness :发布的租约必须 ≤ 订阅要求的租约

后果:DDS 不为这对端点建立连接,数据完全不流动,
      ROS 2 层面通常无任何报错(除非显式检查)
# 查看实际生效的 QoS 与端点匹配情况
ros2 topic info /scan --verbose
# Type: sensor_msgs/msg/LaserScan
# Publisher count: 1
#   Node name: lidar_driver
#     Reliability: BEST_EFFORT
#     Durability: VOLATILE
#     History (Depth): KEEP_LAST (5)
# Subscription count: 0        ← 收不到数据时先看这里

# 强制用指定 QoS 订阅,验证是否是兼容性问题
ros2 topic echo /scan --qos-reliability best_effort
调试顺序(固定,不要跳步):
  1. ros2 topic list                 确认话题存在
  2. ros2 topic info --verbose       比对两端 QoS
  3. ros2 topic hz                   看发布频率
  4. ros2 topic echo                 看内容
  跳过第 2 步直接看内容是最浪费时间的做法

一个隐蔽的坑是 depth 太小。KEEP_LAST(1) 在订阅者回调较慢时持续丢帧,而 ros2 topic hz 显示的是发布频率不是接收频率。要确认接收侧的实际速率,需要在回调里自己统计打点。

5. deadline、liveliness 与事件

除了「连不连得上」,QoS 还能表达「数据是否及时」「发布者是否还活着」这类时序语义。

Deadline 事件:
  发布端 deadline 内没发出 → OFFERED_DEADLINE_MISSED
  订阅端 deadline 内没收到 → REQUESTED_DEADLINE_MISSED
  用途:把「传感器卡死」「控制指令超时」变成可观测事件

Liveliness 事件:
  订阅端检测到发布者不再活跃 → LIVELINESS_CHANGED
  用途:检测节点崩溃、网络断开,比心跳话题更底层可靠

Lifespan:消息在队列中超过 lifespan 自动丢弃
  用途:避免过期指令被延迟执行(1 秒前的速度指令不该再执行)
// 订阅端监听 deadline 未命中事件
auto sub = create_subscription<sensor_msgs::msg::Image>(
    "/camera/image", rclcpp::SensorDataQoS(),
    [](sensor_msgs::msg::Image::ConstSharedPtr) {});
auto deadline_qos = sub->get_actual_qos().deadline();
// 通过 rclcpp 的事件机制或 rcl 的 qos_event 监听
// 也可用 ros2 topic 工具查看事件

把 deadline 当作健康监控用是 ROS 2 通信的一个高级技巧:给关键话题(如 /joint_states、/scan)设 deadline,订阅端监听 REQUESTED_DEADLINE_MISSED 事件,就能第一时间发现传感器掉线或节点卡顿,而不需要额外的看门狗话题。

6. 发现机制:SDP、Discovery Server 与静态端点

DDS 的发现机制决定节点如何互相「找到对方」,是系统规模化的瓶颈所在。

Simple Discovery Protocol(SDP,默认):
  节点通过组播周期性宣告自己的端点,节点少时良好,多时组播风暴

节点数与启动时间(实测经验值):
  5 个 < 1 s;20 个 2~5 s;50 个 10~30 s(开始丢包);
  100 个分钟级,甚至发现失败

三种应对手段(侵入性递增):
  1. 限制组播到指定网卡(避免跨网段泄漏)
  2. Discovery Server(集中式发现,节点只与服务器交互)
  3. 静态端点(initialPeersList,拓扑固定时最可靠)
# 方案一:限制组播到指定网卡
export CYCLONEDDS_URI='<CycloneDDS><Domain><General>
  <NetworkInterfaceAddress>eth0</NetworkInterfaceAddress>
  <AllowMulticast>spdp</AllowMulticast>
  </General></Domain></CycloneDDS>'

# 方案二:Discovery Server(ROS 2 内置支持,以 CycloneDDS 为例)
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
export ROS_DISCOVERY_SERVER=192.168.1.10:11811
ros2 run rmw_cyclonedds_cpp ddsperf  # 或 fastdds discovery -i 0

# 方案三:静态端点(Fast DDS 的 initialPeersList,写在 XML 里)
export FASTRTPS_DEFAULT_PROFILES_FILE=/etc/ros/fastdds_profile.xml
三种机制的取舍:
  SDP        :零配置、小规模最好;大规模不可用
  Discovery Server:集中式、可跨网段;引入单点(需冗余)
  静态端点   :最可靠、无发现开销;新增节点要改配置

跨网段或 VPN 场景下组播通常不可用,必须用 Discovery Server 或静态端点。这也是 Zenoh 的用武之地(见下一节)。域 ID(ROS_DOMAIN_ID)是最简单的隔离手段:不同机器人用不同域 ID,避免互相发现;机器人域规划建议 010 留给开发、11100 留给机器人编号、101+ 留给工具。

7. Zenoh 与新型 RMW

Zenoh 是为「广域、异构、动态」网络设计的协议,作为 ROS 2 的 RMW 解决了传统 DDS 的若干痛点。

Zenoh 相对 DDS 的差异:
  1. 无组播依赖:用 router 做发现与转发,天然穿透 NAT
  2. 跨网络:支持互联网、5G、VPN,节点无需在同一二层网络
  3. 资源占用低:为嵌入式与大规模 IoT 设计
  4. 路由与桥接:Zenoh router 可桥接不同域、不同网络

使用方式:
  export RMW_IMPLEMENTATION=rmw_zenoh_cpp
  ros2 run rmw_zenoh_cpp rmw_zenohd     # 启动 router

取舍:优点是跨网段天然支持、资源省、可路由;
      缺点是生态较新、部分 QoS 语义支持待完善、引入 router 需运维

Zenoh 与传统 DDS 不是替代关系而是互补:单机与局域网内用 DDS(成熟、工具全),跨网段与云端协作用 Zenoh。混合部署时可用 Zenoh 的 DDS 桥接,让两套网络互通。选型时务必实测目标场景下的延迟与吞吐,不要只看宣传数字。

8. 实时性与执行器的交互

通信层与执行器(executor)的交互方式决定回调的调度延迟,是实时控制的关键。

回调延迟的构成:
  1. DDS 接收线程收到数据(DDS 内部线程,优先级通常不可控)
  2. 放入等待集合(waitset)
  3. 执行器线程取出并调用回调
  4. 回调执行时间

延迟的主要来源:
  DDS 内部线程的调度延迟(可能被低优先级线程抢占)
  执行器的线程模型(单线程 vs 多线程)
  回调组配置(互斥 vs 可重入)
  内存分配与锁竞争(回调内的动态分配)
实时通信的三条纪律:
  1. 控制回调必须绑定到隔离核(CPU 亲和性),而非靠调度碰运气
  2. 控制回调内禁止动态分配、禁止日志、禁止阻塞调用
  3. 用 StaticSingleThreadedExecutor 减少每轮遍历开销
     (订阅关系固定时最快,因为它预建了回调到执行的映射)
// 实时控制节点的执行器配置
rclcpp::NodeOptions opts;
opts.use_intra_process_comms(true);     // 同进程零拷贝
auto node = std::make_shared<ControlNode>(opts);

rclcpp::executors::StaticSingleThreadedExecutor exec;
exec.add_node(node);
// 回调组:控制相关用 MutuallyExclusive,避免并发访问共享状态
// 感知相关用 Reentrant 提升吞吐(见架构一篇)
exec.spin();

通信抖动必须在端到端上测量,而不是只看 DDS 或只看回调。用 ROS 2 的 tracing(ros2_tracing、LTTng)能端到端追踪从「发布调用」到「订阅回调返回」的完整链路,定位延迟在哪个环节累积。这部分与机器人实时控制与嵌入式一篇的控制周期预算直接相关。

9. 零拷贝与共享内存传输

大消息(点云、图像)的通信成本主要是内存拷贝,零拷贝是提升吞吐的关键手段。

三个层次的「零拷贝」:
  1. 进程内通信(Intra-process):同进程节点绕过 DDS 直接传指针
     要求 use_intra_process_comms(true) + unique_ptr 发布,
     durability 必须为 VOLATILE
  2. Loaned Messages:从 DDS 预分配内存池借一块填充后发布,
     避免构造→序列化→拷贝的多次分配,适合高频定长消息
  3. 共享内存传输:跨进程但同机时用共享内存而非网络回环
     Iceoryx / Fast DDS SHM,适合大消息(图像、点云)跨进程高频传输
// 进程内通信:必须用 unique_ptr 发布,否则退化为拷贝
auto msg = std::make_unique<sensor_msgs::msg::PointCloud2>();
fillPointCloud(*msg);
pub_->publish(std::move(msg));    // 移动语义,零拷贝

// 借出消息(Fast DDS 风格伪码)
auto loaned = pub_->borrow_loaned_message();
fill(*loaned);
pub_->publish(std::move(loaned));
验证零拷贝是否生效:
  ros2 topic info /points --verbose
  看端点是否标记为 intra-process;intra-process 下 Publisher count
  可能显示为 0 但数据仍在流动——这是最容易误判的一点
  用 ros2 topic hz 确认数据实际到达更可靠

带宽也要算清楚:一路 10 Hz 的 64 线雷达点云约 2 MB/帧,未压缩就是 160 Mbps,三路相机轻松超过 1 Gbps。对策是分层:同机走共享内存,跨机只传降采样后的特征或压缩图像。

10. 多机通信与网络拓扑

多机器人系统的通信比单机复杂得多,网络拓扑是设计的一部分。

多机部署的三个必配项:
  ROS_DOMAIN_ID          :区分逻辑域,不同机器人不同 ID,避免互相发现
  ROS_LOCALHOST_ONLY=1   :单机调试时避免污染共享网络
  ROS_STATIC_PEERS / Discovery Server:跨网段通信

网络拓扑的三种形态:
  1. 扁平二层网络(同一交换机):组播可用,SDP 即可,< 50 节点
  2. 路由网络(跨网段):组播通常不可用,须 Discovery Server/静态端点/Zenoh
  3. 星型(中心 + 边缘):中心做 Discovery Server 与汇聚,适合车队与云端

带宽与延迟的预算:
  同交换机 < 1 ms;跨交换机 1~5 ms;WiFi 5~50 ms 且抖动大;
  蜂窝/广域几十到几百 ms
  无线策略:传感器用 BEST_EFFORT + 大 depth,感知尽量下沉到本地

无线网络是 ROS 2 通信的痛点。组播在 WiFi 上经常不可靠,SDP 会发现失败;TCP 语义的 RELIABLE 在丢包时重传导致延迟尖峰。无线场景优先考虑 Zenoh 或 Discovery Server,并接受「传感器数据丢帧」,而不是强行要求可靠传输。

11. 通信诊断与性能剖析

通信问题必须可观测,否则只能在出事后倒推。

常用诊断工具:
  ros2 topic info --verbose :端点、QoS、类型、匹配情况
  ros2 topic hz / bw        :发布频率 / 带宽占用
  ros2 topic delay          :端到端延迟(需时间戳)
  ros2 doctor --report      :整体健康检查
  ddsperf(CycloneDDS)     :底层 DDS 吞吐与延迟基准
ros2 topic bw /points       # 逐话题看带宽,定位「谁吃满网络」
ros2 topic delay /scan      # 看端到端延迟分布
ros2 doctor --report        # 整体诊断
ddsperf -c -n 10 -s 1024 -r 1Hz pub sub   # 底层 DDS 基准
关键监控指标:
  每个话题的实际接收频率(对比发布频率,看丢帧率)
  端到端延迟的 p50/p99(不是均值)
  带宽占用(是否接近网卡上限)
  DDS 线程数与 CPU 占用(发现线程泄漏)、发现耗时

延迟与频率要按话题分别监控,因为不同话题的预算不同。控制话题要求延迟 < 5 ms、频率稳定;感知话题可以接受更大的延迟与抖动。把两者混在一起看会掩盖问题。这套可观测性设计与机器人软件栈全景 中的可观测性章节是同一套方法论。

12. 选型与调参清单

把通信层的决策收敛成一份可执行的清单。

RMW 选型:
  节点 < 20、要官方工具 → rmw_fastrtps_cpp(默认)
  节点 > 50 或资源受限  → rmw_cyclonedds_cpp
  跨网段 / 云端协同     → rmw_zenoh_cpp

QoS 配置:
  传感器数据 → SensorDataQoS(BEST_EFFORT, KEEP_LAST 5)
  状态与命令 → RELIABLE + KEEP_LAST(10)
  地图与标定 → RELIABLE + TRANSIENT_LOCAL + KEEP_LAST(1)
  静态变换   → RELIABLE + TRANSIENT_LOCAL + KEEP_ALL

发现机制:< 20 节点用 SDP;> 50 用 Discovery Server;
          拓扑固定用静态端点;跨网段用 Discovery Server 或 Zenoh

性能:同进程大消息用 intra-process + unique_ptr;跨进程同机用共享内存;
      实时控制用隔离核 + 静态单线程执行器 + 回调内无分配

调参优先级(从高到低):
  1. RMW 实现(影响最大,改环境变量即可)
  2. QoS 匹配(连不上先查这里)
  3. 发现机制(规模上不去先查这里)
  4. 零拷贝与共享内存(大消息吞吐)
  5. 执行器与回调组(实时性)

权衡取舍

决策选 A选 B
RMWFast DDS:默认、工具全CycloneDDS:省资源、大规模稳
可靠性RELIABLE:不丢、可能延迟BEST_EFFORT:低延迟、可丢
持久性VOLATILE:省内存TRANSIENT_LOCAL:晚启动能拿到
发现SDP:零配置、小规模Discovery Server:大规模、跨网段
网络DDS:局域网成熟Zenoh:跨网段、云端
大消息网络回环:简单共享内存:快、需配置
执行器多线程:并发高静态单线程:低开销、实时

核心原则:通信配置由「数据的重要性」与「网络的可靠性」共同决定。重要且网络可靠的数据用 RELIABLE + 小 depth;不重要或网络不可靠的数据用 BEST_EFFORT + 大 depth。把这两条想清楚,绝大多数 QoS 决策就有了依据。

常见坑清单

  1. 发布者 BEST_EFFORT、订阅者 RELIABLE,静默收不到数据——ros2 topic info --verbose 比对两端 QoS。
  2. 忘记 TRANSIENT_LOCAL,晚启动的节点拿不到地图——地图与标定结果必须配 durability。
  3. 节点数过百仍用组播 SDP,启动耗时分钟级——改用 Discovery Server 或静态端点。
  4. Fast DDS 默认线程模型在节点多时线程数爆炸,CPU 飙升——换 CycloneDDS 或限制线程池。
  5. intra-process 下用了拷贝发布而非 unique_ptr,零拷贝退化为拷贝——必须 publish(std::move(msg))。
  6. intra-process 配了非 VOLATILE 的 durability,行为未定义——进程内通信的 durability 必须为 VOLATILE。
  7. KEEP_LAST(1) 且回调慢,持续丢帧却看不出来——hz 显示的是发布频率,需在回调侧统计。
  8. 无线网络强行用 RELIABLE,丢包重传导致延迟尖峰——传感器数据用 BEST_EFFORT。
  9. 多机器人同域 ID 互相发现,话题串台——规划域 ID 并显式设置 ROS_DOMAIN_ID。
  10. 切换 RMW 后不重跑兼容性检查,边界情况行为不同——切换后必须重验 QoS。

小结

ROS 2 通信的核心是「QoS 决定行为,RMW 决定性能」。QoS 的三个常用策略(Reliability、Durability、History)覆盖大多数场景,而 deadline、liveliness、lifespan 在健康监控与安全语义上有独特价值。RMW 的选择在系统规模化时影响巨大,Fast DDS 与 CycloneDDS 是主流,Zenoh 在跨网段场景有独特优势。

下一步建议阅读ROS2 架构:节点、DDS 与生命周期 ,理解通信层之上的节点、生命周期与执行器模型;ROS2 实战一篇讲清三种通信模式的工程写法;机器人实时控制与嵌入式一篇把通信延迟纳入控制周期预算。

最后一句经验:「收不到数据」先查 QoS 匹配,「系统规模上不去」先查发现机制。这两类问题占了 ROS 2 通信故障的绝大多数,而它们都有确定的排查方法。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「机器人」更多文章

  1. 机器人实时控制与嵌入式
  2. 足式与人形机器人运动控制
  3. 移动机器人定位