MQTT 集成
本章区分设备上报和云端控制。端侧 REST 是普通应用的主要控制入口;MQTT 下行需要部署方开放对应 Broker 凭据和主题权限。已有本地 Broker 连接不意味着可以使用云端下行。
21.1 连接与主题
[local_mqtt] 用于本地连接与上报,[cloud_mqtt] 用于云连接及云端下行;按部署分别核对。主题根:
sys/{region}/{tenant_id}/{device_id}
| 主题后缀 | 方向 | QoS / 用途 |
|---|---|---|
/uplink | 设备 → Broker | 通常 QoS 1,register/heartbeat/offline/command_result |
/task/uplink | 设备 → Broker | QoS 1,任务状态与进度 |
/telemetry/{stream} | 设备 → Broker | 常规连接器 odom 为 0,其他为 1;专用云端 pose 推送为 QoS 0 |
/alarm | 设备 → Broker | QoS 1,告警事件 |
/downlink | Broker → 设备 | QoS 1,云端连接订阅控制指令 |
region/tenant_id 应显式配置,不依赖不同模块的缺省值一致。uplink_topic 可覆盖普通上行/指令回执主题,但不自动改变 task/telemetry 等子主题。注册/心跳保留策略受配置影响,客户端初次收到的保留消息可能是历史值,应结合 ts、boot_id、seq 判断。QoS 1 允许重复投递,消费者须去重。
21.2 注册、心跳与离线
公共字段:device_id:string、boot_id:string、seq:integer、ts:string、schema_version:string(v1)。
| msg_type | 特有字段 |
|---|---|
| register | status=online、ip、sw_version、device_type、model、capabilities;运行时还可附加身份和能力扩展 |
| heartbeat | status=online、health;周期由 heartbeat_interval_sec 配置 |
| offline | status=offline、reason |
capabilities.cloud_commands 是该设备声明的命令集合,cloud_navigation 声明 schema_version=v2 及支持的 mission_modes 等。文档列出的能力并不保证当前部署装配了所有依赖。
21.3 任务事件
/task/uplink 为 JSON 对象,没有 code/msg/data 信封:
{"task_id":"mission-example-id","task_type":"navigation","status":"running","progress_percent":25,"progress_detail":{"percent":25,"method":"step_count","phase":"waiting","completed_units":1,"current_unit":2,"total_units":4,"confidence":"high","updated_at":1794556800000},"timestamp":1794556800000}
| 字段 | 类型 | 说明 |
|---|---|---|
task_id、task_type | string | 本机任务身份与类型 |
command_id | string,可省略 | 来自云命令时的关联 ID |
status | string | pending/running/completed/failed/cancelled/stopping;与 REST LocalTask.Status 整数不同 |
progress_percent | number | 导航运行中最多 99,完成为 100 |
progress_detail | NavigationProgress,可选 | 同 6.6 |
mapping_result、map_edit_result | object,可选 | 对应任务执行结果 |
error_msg | string,可省略 | 失败信息 |
next_pending_task_id | string,可省略 | 自动衔接关闭时提示下一任务 |
timestamp | integer | Unix 毫秒 |
断开后不保证事件历史补发;重新连接时用 /tasks/{id} 对账。按 task_id 与事件时间关联,不能只显示最后到达的一条消息而忽略乱序/重复。
21.4 遥测记录
{"device_id":"SN1234567890","stream":"nav_status","seq":10,"schema_version":"v1","device_ts":1794556800000,"payload":{"status":"navigating","relocalization":"successful","global_relocalization":"idle"}}
固定元字段为 device_id、stream、seq、schema_version、device_ts、payload,payload 按 stream 定义。常见流有 device_info、robot_info、nav_status、services_status、pose,以及配置的 odom/map_odom 等里程计流。device_ts 为毫秒;seq 按流递增,进程重启后可从头开始。
遥测仅有内存缓冲,没有通用持久化、确认及离线补发保证。pose 专用控制还受开启、周期、导航上下文和数据新鲜度等部署策略约束。机器人实时位置依赖正确的坐标系与地图上下文,不能直接混用 odom 与 map_odom。
21.5 下行指令信封
| 字段 | 类型 | 要求 |
|---|---|---|
msg_type | string | 可省略;提供时必须 command |
command_id | string | 必填,唯一关联标识及任务幂等来源 |
command_type | string | 必填,支持集合内的类型 |
device_id | string | 可省略;提供时必须匹配本机 |
params | object | 命令参数;缺省为空对象 |
expires_at | string | 建议提供 RFC 3339 过期时间,过期拒绝 |
issued_at | string | 发出时间,地图编辑等流程另有校验 |
ttl_ms | integer | 结构保留;当前通用处理器不根据它推导 expires_at,不能仅靠 ttl_ms 实现过期保护 |
reconcile_only | boolean | 内部地图编辑对账用途,普通控制不要设置 |
示例中的时间必须由客户端在发送时生成未来有效值:
{"msg_type":"command","command_id":"cmd-example-001","command_type":"nav.mission.start","device_id":"SN1234567890","issued_at":"2026-11-13T08:00:00Z","expires_at":"2026-11-13T08:00:30Z","params":{"mode":"single_point","x":3.2,"y":1.5,"theta":0.0,"frame_id":"map"}}
通常处理一次命令产生 accepted 与后续结果,校验失败只产生 rejected;accepted 当前并非保证在 handler 执行前立即发布。通用处理器在内存缓存结果,同一 command_id 重发通常返回缓存结果;进程重启不保证保留该缓存。任务提交及地图编辑等还有各自的持久化幂等机制,不能扩展成所有命令跨重启“恰好执行一次”。
21.6 指令回执
{"msg_type":"command_result","schema_version":"v1","command_id":"cmd-example-001","status":"succeeded","robot_task_id":"mission-example-id","message":"navigation mission submitted","ts":"2026-11-13T08:00:01Z"}
必有 command_id、status、schema_version、ts;message/error_code/robot_task_id/data/identity_proof 视结果出现。该回执没有普通注册消息的全部公共字段,不能要求所有 uplink 消息都有 boot_id/seq。
status 常见 accepted/running/succeeded/failed/rejected;地图编辑对账可能返回 timeout 表示结果未确认。导航命令 succeeded 通常只证明任务提交成功,最终到达要看 robot_task_id 对应的 task/uplink 或 REST 状态。
常见拒绝 error_code:invalid_json、invalid_message_type、invalid_command、device_mismatch、unsupported_command、invalid_expiry、expired、device_busy、handler_unavailable、invalid_params。业务层另有 navigation_active、map_revision_mismatch、artifact_conflict、parameters_partial_failure 等字符串码,与 REST 数字业务码不同。无可识别 command_id 的畸形消息不保证能收到可关联回执。
21.7 常用控制指令参数
| command_type | params 与结果要点 |
|---|---|
| nav.container_start | scene_name(历史解析也接受 map_id 作名称)、map_revision、bringup_mode、use_relocalization、use_sim_time、use_online_map、runtime_version;建议只用 scene_name 表达地图名称 |
| nav.container_stop | 无参数 |
| nav.start_navigation | x、y 必填 number;theta、frame_id、scene_name、map_revision 可选;frame_id 默认 map;返回 robot_task_id |
| nav.mission.start | mode=single_point/path/complex;single_point 用顶层 x/y/theta,path 用 waypoints(至少 2 点)和 cycles(<=0 按1),complex 用 steps/default_params;可有 frame_id/use_relocalization 和地图上下文;返回 robot_task_id |
| nav.stop_navigation / task.cancel_current | 无参数;取消当前本机任务 |
| nav.pause_navigation / nav.resume_navigation | 无参数 |
| nav.relocalization.set | enabled:boolean 必填;REST 相应字段为 enable,不能混用 |
| nav.relocalization.pose.set | x、y 必填 number;theta、z 可选 |
| nav.relocalization.global.start | mode 可选,global/origin/sequential,缺省 sequential |
| nav.relocalization.global.cancel | 无参数 |
| nav.params.get | names:string,1–64 项;data 含 saved、runtime、apply_status,可含 runtime_error |
| nav.params.save | values:object,1–64 项;不是 REST 的裸参数字典;导航/重定位活跃时拒绝;逐参数失败可令结果 status=failed |
| service.scan.set | enabled:boolean 必填;服务切换后等待目标状态 |
| service.motion.set | enabled:boolean 必填;开启时 adapter_type 必须符合设备适配器目录;运行中修改受状态策略限制 |
| telemetry.pose.set | enabled:boolean 必填;interval_ms 为可选整数,500–5000 ms;省略保留原周期;设备须允许远程开关,否则回执失败 |
| mapping.start | scene_name 必填、runtime_version 可选,返回关联建图任务 |
| mapping.finish | 恰好 expected_robot_task_id 与 expected_runtime_instance_id 两个非空 string,避免停止新建图实例 |
| mapping.status.refresh | 无参数,刷新当前建图状态 |
| cloud.sync_resources | reason:string 可选,请求同步端侧资源 |
REST 与 MQTT 不能原样互转:REST standard 对应 MQTT single_point,REST route 对应 MQTT path;REST direct 没有独立同名云模式。MQTT 路线至少 2 点,而 REST route 入口至少 1 点。云端还会检查资源上下文与策略。
21.8 云资源与媒体协同指令
以下是当前支持的其余命令,用于云端协同,必须使用匹配版本的云端调用方生成参数;它们不是新增的端侧 REST 路由。
| command_type | 参数与边界 |
|---|---|
| nav.landmark.save | landmark_id、scene_name、map_revision、expected_revision、name、kind、points;新建/更新按资源版本规则;points 的 x/y 显式提供;拒绝未知字段 |
| nav.landmark.delete | landmark_id、scene_name、map_revision、expected_revision 等删除身份条件;删除前检查修订,不等同于 REST 简单 DELETE |
| nav.artifact.rebind | artifact_type、artifact_id、scene_name、map_revision;资源重新绑定,需匹配设备资源存储 |
| map.edit.apply | map_id、local_instance_id、scene_name、expected_release_id、base_digest、pgm_sha256、pgm_size,可有 source_device_uid;通过云传输获取内容;issued_at 有额外时效校验;运行中与最终 applied 回执分开 |
| media.stream.start | session_id:string、expires_at_unix:integer(Unix 秒)、streams(1–8项);每项必须有 alias、uri、stream_id 字符串,可有 passphrase:string、latency_ms:integer;会话传输目标由云端提供 |
| media.stream.renew | session_id、expires_at_unix |
| media.stream.stop | session_id |
| device.identity.prove | challenge;制造/云准入身份挑战,不是普通导航接入流程 |
云端媒体采用独立按需会话;不要把端侧控制台 Janus 视频链路或 HLS 描述为所有 Orsus 接口的统一视频协议。本篇不新增或承诺客户端直接调用这些内部协同流程的权限。