上一篇,我们讨论了服务机器人为什么会存在多个控制入口。

例如:

机身 Android

手机 App

Cloud

AUTO Task

Maintenance

这些入口最终可能都会要求机器人:

开始任务

停止任务

前往某个点位

返回充电

打开柜门

所以机器人不能简单采用:

谁最后发送 Command
就执行谁

而需要:

Control Arbiter

也就是:

控制权仲裁。

但是继续往下分析以后,又会出现一个新的问题。

手机远程控制机器人时,本身就要经过 Cloud:

手机 App
   ↓
Cloud
   ↓
Robot

那么 Cloud 要不要做一次控制权仲裁?

如果 Cloud 已经判断:

ALLOW

机器人本地为什么还要再判断一次?

再往下:

Linux 主控已经允许执行,

为什么 MCU 还可能拒绝电机动作?

也就是说:

为什么一条机器人指令,可能要经过不止一次“允许 / 拒绝”判断?

这一篇,我们就把这个问题彻底拆开。


一、先看一个最简单的远程控制场景

假设用户在手机 App 上点击:

RETURN_TO_CHARGE

控制链路:

手机 App
    ↓
Cloud
    ↓ MQTT
机器人 Linux 主控
    ↓
Navigation
    ↓
Chassis
    ↓
MCU
    ↓
Motor

表面上看,这似乎只是一条:

RETURN_TO_CHARGE

指令。

但真正执行过程中,至少会遇到三个完全不同的问题。

第一个问题:

这个用户有没有资格让这台机器人回充?

第二个问题:

机器人当前状态允不允许执行回充?

第三个问题:

底盘当前物理状态允不允许移动?

这三个问题显然不是一个层级的问题。

所以:

Control Arbitration

天然就会出现分层。


二、可以把它先抽象成三级

一个比较完整的机器人控制体系可以理解成:

        第一级
Cloud Global Arbiter

“业务上能不能下发?”

          ↓

        第二级
Robot / Linux Arbiter

“机器人现在能不能执行?”

          ↓

        第三级
MCU Safety Interlock

“物理上能不能安全执行?”

          ↓

       Hardware

这三层看起来都在做:

ALLOW / REJECT

但是它们检查的条件完全不同。

所以:

这不是重复判断,而是分层防线。


三、第一级:Cloud Control Arbiter

先看 Cloud。

手机 App 发起:

RETURN_TO_CHARGE

Cloud 首先掌握的是:

全局业务信息。

例如:

当前用户是谁?

机器人属于谁?

这个用户有没有控制权限?

当前是否已经有人在远程控制?

当前是不是已经存在冲突任务?

是不是另一个 App 已经获得控制权?

设备是否在线?

远程控制租约是否有效?

这些信息最适合谁判断?

当然是:

Cloud

因为机器人本地通常根本不知道:

这个用户的账号权限。


四、Cloud 仲裁解决的是“全局业务问题”

例如用户 A 和用户 B 同时打开 App。

用户 A:

START_TASK

用户 B:

RETURN_TO_CHARGE

机器人本地可能只看到:

Command A

Command B

但 Cloud 知道:

User A
=
设备管理员

User B
=
普通查看用户

所以 Cloud 可以直接:

User A
→ ALLOW

User B
→ REJECT

机器人根本不需要收到用户 B 的控制指令。

这就是 Cloud Arbiter 的价值。


五、Cloud 还可以管理“远程控制权”

假设一个服务机器人支持远程人工控制。

用户 A 已经获得:

REMOTE CONTROL

此时用户 B 又尝试接管。

Cloud 可以维护:

Control Owner

例如:

owner = userA

mode = REMOTE

leaseId = abc123

用户 B 请求:

TAKE_CONTROL

Cloud 判断:

当前已有远程控制者

于是:

REJECT
reason = REMOTE_CONTROL_OCCUPIED

这种:

多用户

多 App

账号权限

控制租约

问题显然非常适合在云端解决。


六、为什么可能还需要 Control Lease?

假设用户 A 获得了远程控制权。

然后:

手机断网

Cloud 不能永久认为:

userA

还在控制机器人。

所以可以设计:

Control Lease

例如:

owner = userA

expiresAt = 10s later

客户端需要持续:

renew

如果长时间没有续约:

Control Lease Expired

Cloud 就可以释放:

REMOTE CONTROL

这和分布式系统中的:

Lease

思想非常接近。


七、Cloud ALLOW 到底意味着什么?

这里一定要建立一个重要认知。

Cloud 返回:

ALLOW

并不代表:

机器人必须执行。

它真正表示的是:

从云端当前掌握的全局业务状态来看,这条指令允许被下发。

也就是:

Cloud ALLOW
=
允许发送给 Robot

而不是:

Cloud ALLOW
=
Robot 必须执行

这两个概念完全不同。


八、为什么 Robot 还必须再做一次仲裁?

因为 Cloud 不掌握机器人此刻最真实的本地状态。

例如 Cloud 当前记录:

mode = REMOTE

state = IDLE

于是允许:

RETURN_TO_CHARGE

但是就在几百毫秒前,

现场用户通过机身 Android:

切换 LOCAL

Linux 当前真实状态已经变成:

mode = LOCAL

只是最新状态还没有来得及同步到 Cloud。

这时候如果机器人完全相信 Cloud:

Cloud ALLOW
↓
直接执行

远程命令就可能和现场控制发生冲突。

所以机器人本地必须:

重新判断一次。


九、第二级:Robot / Linux Control Arbiter

对于服务机器人来说,真正的本地控制入口可能是:

                 Cloud
                   │
                   │
机身 Android ──────┼──→ Linux
                   │
AUTO Task ─────────┤
                   │
Maintenance ───────┘

这几个入口最终真正汇聚的位置是:

Linux 主控

所以 Linux 这一层应该知道:

当前 ControlMode

当前 ControlOwner

当前任务

当前 Navigation 状态

当前是否 Maintenance

当前是否有人 Local 接管

当前机器人实际运行状态

因此:

机器人本地 Control Arbiter 通常应该靠近 Linux 主控。


十、Linux Arbiter 判断的不是“这个用户是谁”

例如远程收到:

RETURN_TO_CHARGE

Linux 通常没有必要重新判断:

这个用户是不是 VIP?

账号是否过期?

设备是不是属于这个用户?

这些 Cloud 已经处理。

Linux 真正关心的是:

当前是不是 LOCAL?

机器人是不是正在 MAINTENANCE?

当前 AUTO Task 能不能被打断?

机器人是不是正在执行另一项高优先级任务?

当前 Navigation 是否允许启动新目标?

当前状态是不是 CHARGING?

是不是已经处于 RETURNING?

这些属于:

本地机器人状态。


十一、服务机器人为什么尤其依赖本地仲裁?

因为它有一个非常重要的入口:

机身 Android
      ↓ TCP
Linux

这条链路:

根本不经过 Cloud。

例如:

手机 App
↓
Cloud
↓
RETURN_TO_CHARGE

Cloud 判断:

ALLOW

但与此同时,

现场用户:

机身 Android
↓
STOP_TASK

甚至:

切换到 LOCAL

Cloud 很可能还不知道这件事情。

但是 Linux 知道。

所以:

Linux Control Arbiter

必须成为:

机器人本地控制状态的最终事实源。


十二、一个服务机器人指令可以这样走

例如手机远程点击:

RETURN_TO_CHARGE

第一步:

手机 App
↓
Cloud

Cloud 判断:

用户权限 ✓

设备归属 ✓

远程控制权 ✓

任务冲突 ✓

于是:

Cloud Arbiter
→ ALLOW

然后:

Cloud Command Center
↓ MQTT
Linux

Linux 收到以后:

Command Handler

先解析:

RETURN_TO_CHARGE

然后进入:

Robot Control Arbiter

继续判断:

currentMode = ?
controlOwner = ?
currentTask = ?
robotState = ?
navigationState = ?

假设发现:

currentMode = LOCAL

那么:

Robot Arbiter
→ REJECT

返回:

reason = LOCAL_CONTROL_ACTIVE

这是完全正常的。


十三、所以 Cloud ALLOW + Robot REJECT 并不矛盾

因为两边回答的问题不同。

Cloud:

这个远程请求
从全局业务角度
允许发送

Robot:

但从机器人此刻真实状态来看
现在不能执行

所以:

Cloud = ALLOW

Robot = REJECT

完全可能。

甚至是一个成熟系统必须允许出现的情况。


十四、那 Linux ALLOW 以后是不是就一定执行?

仍然不一定。

因为下面还有:

MCU

以及:

真实硬件。

假设 Linux 判断:

当前 REMOTE
没有任务冲突
Navigation 正常
允许回充

于是:

Robot Arbiter
→ ALLOW

然后 Navigation 开始控制底盘:

linearVelocity = 0.5m/s

但就在此刻,底盘检测到:

急停按下

怎么办?

当然还是不能动。


十五、第三级:MCU Safety Interlock

这里我更愿意叫:

Safety Interlock

而不是继续全部叫:

Control Arbiter

因为 MCU 做的已经不是:业务控制权仲裁。

而是:实时物理安全保护。

它可能检查:

Emergency Stop

Bumper

Cliff Sensor

Motor Overcurrent

Driver Fault

Watchdog

Communication Lost

Temperature

Hardware Limit

如果任何一个条件触发:

BLOCK

即使 Linux 发:

MOVE_FORWARD

MCU 仍然:

拒绝执行

甚至直接:

切断电机输出

十六、为什么 Safety 不能只放 Linux?

因为 Linux 本身也可能:

卡死

线程阻塞

进程崩溃

通信异常

系统负载过高

如果安全保护完全依赖:

Linux

那么 Linux 出问题时:安全能力也跟着失效。

所以一些关键保护需要继续下沉到:

MCU

Safety Controller

甚至纯硬件电路

例如物理急停可以设计成:

急停按钮
    ↓
Safety Circuit / MCU
    ↓
Motor Driver

直接阻止电机输出。

它不应该要求:

Android
↓ TCP
Linux
↓ CAN
MCU

完整链路正常以后才能停车。


十七、所以 STOP_TASK 和 Emergency Stop 属于不同层

例如:

STOP_TASK

属于业务控制。

可能经过:

Command Center
↓
Control Arbiter
↓
Task Manager
↓
Navigation
↓
平滑停止

它会考虑:

任务状态

业务结果

云端同步

而:

EMERGENCY STOP

关注的是:

先让危险动作停下来

它甚至可以绕开:

Task Manager

直接作用到:

Chassis / Motor

因此:

STOP_TASK ≠  EMERGENCY_STOP

一个是:业务停止。

一个是:安全停止。


十八、现在再看割草机器人

割草机器人也存在控制仲裁。

只是它和服务机器人控制入口分布不同。

割草机器人更常见的是:

手机 App
   ↓
Cloud
   ↓
Mower

远程业务入口首先汇聚到:

Cloud

所以 Cloud 可以承担很大一部分:

Global Control Arbiter

例如:

用户权限

设备归属

远程控制权

计划任务冲突

手动任务和自动任务冲突

多客户端操作

然后:

Cloud
↓ MQTT
Mower

十九、割草机器人本地为什么仍然需要判断?

例如 Cloud 下发:

START_MOWING

云端认为:

用户权限 ✓

设备在线 ✓

当前没有任务冲突 ✓

但是割草机器人此刻发现:

RTK / 定位不可用

电池过低

刀盘故障

机器人倾倒

急停按下

驱动故障

那么机器人仍然必须:

REJECT

例如:

reason = POSITIONING_NOT_READY

或者:

reason = LOW_BATTERY

所以割草机器人也是:

Cloud Global Arbiter
       ↓
Robot Local Check
       ↓
Safety
       ↓
Execution

只是:云端仲裁承担的比例更大。


二十、服务机器人和割草机器人真正的差异在哪?

放在一起就很清楚。

割草机器人

App A ─┐
       │
App B ─┼→ Cloud
       │  Global Arbiter
计划任务┘
          ↓
        MQTT
          ↓
        Robot
     Local / Safety
          ↓
       Chassis

它的特点:

大多数外部业务控制首先汇聚 Cloud。


服务机器人

手机 App
    ↓
  Cloud ───────────┐
                   │
机身 Android ──────┼→ Linux
                   │  Local Arbiter
AUTO Task ─────────┤
                   │
Maintenance ───────┘
                         ↓
                     MCU Safety

它的特点是:

存在机身 Android → TCP → Linux 这条绕过 Cloud 的本地控制链路。

所以:

Linux Local Arbiter

在服务机器人里会更加重要。


二十一、这也解释了为什么服务机器人的控制体系更复杂

割草机器人大量控制入口可以先:

Cloud

统一。

而服务机器人同时存在:

LOCAL
REMOTE
AUTO
MAINTENANCE

并且很多入口:直接发生在机器人本体。

所以 Linux 必须统一处理:

谁现在拥有控制权?

哪一种 Mode?

哪一个 Source?

哪一种 Command?

能不能抢占当前任务?

因此服务机器人会更明显地出现:

Robot Control Arbiter

这个独立架构角色。


二十二、这里还需要区分“普通底盘”和“智能底盘”

我们前面一直说:

Linux Arbiter

但实际项目中,有时候大家会说:

控制仲裁在底盘。

这句话是不是错?

不一定。

如果所谓的:

智能底盘

内部已经包含:

Linux

ROS / ROS2

Navigation

底盘服务

MCU

那么完全可以理解成:

Android
↓ TCP
智能底盘 Linux
【Control Arbiter】
↓
底盘 MCU

所以工程上说:

控制权仲裁在底盘

没有问题。

但是如果所谓底盘只是:

STM32

Motor Driver

Encoder

Wheel

那么更准确应该是:

Linux 主控
【业务 Control Arbiter】

↓

底盘 MCU
【Safety Interlock】

普通 MCU 一般不应该负责:

LOCAL 和 REMOTE 谁优先?

手机用户有没有远程控制权限?

AUTO Task 能不能被 App 抢占?

这些属于上层业务逻辑。


二十三、Cloud Arbiter 和 Command Center 也不是一回事

前面的补充篇我们讲过:

Command Center

它负责:

CommandId

Pending

Timeout

Retry

Result

Command Lifecycle

而:

Control Arbiter

负责:

这条 Command 有没有资格继续向下执行?

所以 Cloud 里可能同时有:

Cloud

├── Command Center
│      ↓
│   管 Command 生命周期
│
└── Control Arbiter
       ↓
    管远程业务控制权

两者可能属于同一个服务实现。

也可能以后拆成不同模块。

但逻辑职责要分开。


二十四、Robot 端也是一样

机器人 Linux:

MQTT / TCP
    ↓
Command Handler
    ↓
Control Arbiter
    ↓
Task / Navigation / Device

Command Handler 负责:

解析

校验

去重

幂等

Control Arbiter 负责:

当前是否允许执行

Task / Navigation 负责:

真正完成机器人能力

所以一个完整链路可以变成:

Command Center
      ↓
Communication
      ↓
Command Handler
      ↓
Control Arbiter
      ↓
Capability
      ↓
Hardware Adapter
      ↓
MCU Safety
      ↓
Hardware

这时候前几篇内容就全部串起来了。


二十五、三级系统各自掌握什么“事实”?

这是理解多级仲裁最好用的方法。

Cloud

掌握:

全局业务事实。

例如:

用户是谁

设备属于谁

远程控制者是谁

任务历史

账号权限

远程 Lease

Robot / Linux

掌握:

当前机器人执行事实。

例如:

当前 ControlMode

当前 Task

当前 Navigation

当前 Local 控制者

是否 Maintenance

设备当前真实运行状态

MCU / Safety

掌握:

当前物理事实。

例如:

急停有没有按下

电机有没有过流

碰撞有没有触发

驱动器是否故障

硬件是否允许输出

所以可以记成:

Cloud
全局业务事实

↓

Robot
本地执行事实

↓

MCU
物理安全事实

谁最接近事实,谁负责这一层最终判断。


二十六、这也是为什么状态不能只相信 Cloud

假设 Cloud 显示:

Robot = IDLE

并不代表机器人此刻一定还是:

IDLE

因为状态同步存在:

网络延迟

MQTT 延迟

数据库更新延迟

消息顺序

Robot 本地状态永远更加接近:

当前真实执行情况。

同样:

Linux 认为:

Motor = READY

也不代表下一毫秒电机一定能运行。

MCU 可能刚刚检测:

OVER_CURRENT

所以机器人控制必须接受:

越接近硬件,状态越实时。


二十七、最终执行原则:越往下越有否决权

这个模型还可以总结出一个非常重要的设计原则:

Cloud 可以允许

Robot 可以否决

MCU 还可以继续否决

也就是:

Cloud ALLOW
        ↓
Robot ALLOW
        ↓
MCU ALLOW
        ↓
Execute

任何一层:

REJECT

最终都不能执行。

例如:

Cloud
ALLOW

↓

Linux
ALLOW

↓

MCU
REJECT
急停触发

最终:

机器人不移动

不能因为 Cloud 已经允许,

就强制绕过下面的安全系统。

所以:

上层拥有调度权,下层拥有基于真实状态的否决权。

这个原则非常重要。


二十八、但下层不能反过来越权做上层业务决策

同样需要注意另外一面。

MCU 有权因为:

Emergency Stop

拒绝运动。

但是 MCU 不应该自己判断:

User A
比 User B 权限高

Robot Linux 可以判断:

当前 LOCAL
所以拒绝 REMOTE

但它通常不需要维护整个:

用户会员体系
账号权限
组织结构

所以好的分层不是:

大家什么都判断一遍。

而是:

每一层只判断自己最了解的事实。


二十九、把一个远程回充完整走一遍

用户:

RETURN_TO_CHARGE

第一层:

手机 App
↓
Cloud

Cloud Arbiter:

用户权限?
✓

设备归属?
✓

远程控制权?
✓

业务任务冲突?
✓

↓

ALLOW

Command Center:

创建 commandId = 1001

然后:

MQTT
↓
Robot

Robot Command Handler:

解析

去重

校验

进入 Robot Control Arbiter:

LOCAL 是否正在控制?
否

MAINTENANCE?
否

当前任务允许中断?
是

当前 RobotState 允许回充?
是

↓

ALLOW

进入:

Navigation

产生底盘控制:

setVelocity(...)

MCU Safety:

EmergencyStop?
否

Bumper?
否

DriverFault?
否

Watchdog?
正常

↓

ALLOW

最后:

Motor Execute

这才是一条完整的机器人控制链路。


三十、如果中途被拒绝怎么办?

假设 Cloud:

ALLOW

但是 Robot:

REJECT
reason = LOCAL_CONTROL_ACTIVE

机器人应该把结果上报:

commandId = 1001

status = REJECTED

reason = LOCAL_CONTROL_ACTIVE

Cloud Command Center 更新:

1001
REJECTED

手机 App 最终显示:

机器人当前正在本地控制
暂时无法远程回充

这时候用户看到的是:

业务拒绝。

而不是:

请求失败

或者:

网络异常

这就是前面 Command / Result 设计继续发挥作用的地方。


三十一、多级仲裁其实和前面所有文章都连起来了

回头看第二季前面几篇:

TCP 长连接解决:

Android 和 Linux 怎么长期通信?

粘包半包解决:

TCP 字节流怎么还原消息?

Command / Ack / Retry 解决:

指令怎么可靠执行?

Command Center 解决:

谁管理指令生命周期?

Android / Linux / MCU 分层解决:

能力应该属于谁?

多控制入口解决:

Command 可能从哪里来?

而这一篇的多级仲裁解决:

这么多 Command
到底哪些有资格继续向下执行?

整个体系开始完整起来。


三十二、最终可以得到一张机器人控制架构图

          手机 App / 管理后台
                  ↓
          ┌───────────────┐
          │     Cloud     │
          │               │
          │ Control       │
          │ Arbiter       │
          │               │
          │ Command       │
          │ Center        │
          └───────┬───────┘
                  │
               MQTT
                  ↓
        ┌─────────────────┐
        │ Robot / Linux   │
        │                 │
TCP ───→│ Command Handler │
↑       │                 │
│       │ Control Arbiter │
│       │                 │
│       │ Task / Nav      │
│       └────────┬────────┘
│                │
│          CAN / Serial
│                ↓
│       ┌─────────────────┐
│       │ MCU / Safety    │
│       │                 │
│       │ E-Stop          │
│       │ Bumper          │
│       │ Overcurrent     │
│       │ Watchdog        │
│       └────────┬────────┘
│                ↓
│             Hardware
│
机身 Android

从上到下分别回答:

Cloud
业务上能不能下发?

↓

Linux
机器人现在能不能执行?

↓

MCU
物理上能不能安全执行?

三十三、总结

机器人里的:

Control Arbiter

并不一定只有一个。

对于复杂机器人系统,很自然会形成:

Cloud Global Control Arbiter

↓

Robot / Linux Control Arbiter

↓

MCU Safety Interlock

三层检查。

Cloud 负责:

全局业务控制。

主要判断:

用户权限

设备归属

远程控制权

多客户端冲突

任务冲突

Remote Lease

Robot / Linux 负责:

本地执行控制。

主要判断:

LOCAL / REMOTE / AUTO / MAINTENANCE

当前 Task

当前 RobotState

Local Android 控制权

Navigation / Chassis 状态

Command 是否允许抢占

MCU / Safety 负责:

实时物理安全。

主要判断:

急停

碰撞

防跌落

驱动器故障

过流

Watchdog

失联保护

最终判断

所以:

Cloud ALLOW
≠
Robot 必须执行

而是:

Cloud
业务允许

↓

Robot
本地允许

↓

MCU
安全允许

↓

Execute

越靠近机器人和硬件,越掌握最新的真实状态。

因此:

上层负责调度,下层保留基于真实状态和安全条件的否决权。

如果是割草机器人:

App
↓
Cloud Global Arbiter
↓
Mower Local / Safety
↓
Hardware

由于远程业务入口主要经过 Cloud,云端承担的全局控制仲裁会更多。

如果是服务机器人:

手机 → Cloud ───┐
                │
机身 Android ───┼→ Linux Control Arbiter
                │
AUTO Task ──────┤
Maintenance ────┘
                     ↓
                 MCU Safety

由于存在:

机身 Android
↓ TCP
Linux

这条本地直连控制链路,Linux 主控就必须成为:机器人本地控制状态的最终事实源。

到这里,我们可以把前面几个核心概念彻底区分开:

Command Center
解决:
指令生命周期怎么管理?

Control Arbiter
解决:
这条指令有没有资格执行?

Capability Owner
解决:
这个机器人能力到底属于谁?

Safety Interlock
解决:
物理上是否允许安全执行?

这四个角色组合起来,才逐渐形成一套真正完整的:

机器人可靠控制架构。

下一篇回到正式主线:

第 8 篇

《云柜机器人,本质上是在服务机器人底座上增加了哪些能力?》

Logo

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

更多推荐