Files
lzwcai-terminal-temi/交接文档.md
tanjianbin 74f4c01603 docs: 添加项目交接文档
详细说明项目定位、架构、配置、关键业务流程和排障指南,便于后续维护人员快速上手。
2026-05-08 17:15:56 +08:00

18 KiB
Raw Blame History

Temi 终端控制应用交接文档

本文档面向后续接手本项目的技术人员,重点说明项目定位、当前架构、配置约定、关键业务流程、排障思路,以及与旧版实现相比已经发生的变化。建议先通读本文,再结合 technique.md 和代码深入。

1. 项目定位与当前状态

  • 项目类型:基于 Temi SDK 的 Android 应用Kotlin
  • Android 模块:app
  • 包名:com.example.lzwcai_terminal_temi
  • 核心能力:
    • 通过 MQTT 指令控制 Temi 机器人导航、巡逻、接待、通知播报和基础动作。
    • 通过 LiveKit 进行音视频接入,并把房间内收到的 ASR/文本数据转发到 MQTT。
    • 通过 HTTP 接口做设备激活、运行时配置拉取、门禁工作流调用。
    • 通过 Telemetry 上报机器人状态心跳、事件、电量和位姿。
  • 当前版本和早期代码相比,最大的变化是:
    • MQTT 用户名/密码不再写死在代码中,而是在激活后从服务端拉取并存入本地。
    • 设置页主配置已经从单纯的 network_ip 扩展成 base_url + 登录账号 + 激活码 + 设备名
    • 主流程增加了激活态控制、自动回充、门禁工作流、接待返航工作流、ASR 转发等能力。

推荐阅读顺序:

  1. 本文档:快速建立维护视角。
  2. technique.md:查看协议和流程图。
  3. MainActivity.ktSettingsActivity.ktMqttManager.ktTaskController.kt:理解当前真实行为。

2. 核心模块一览

代码主要集中在 app/src/main/java/com/example/lzwcai_terminal_temi

  • MainActivity
    • 主界面与机器人事件中心。
    • 管理 MQTT / LiveKit 生命周期、TTS 状态、人体检测、到站处理、UI 状态、激活提示。
  • SettingsActivity
    • 配置页。
    • 负责 base_url、登录账号密码、激活码、设备名、LiveKit 参数、当前位置、特殊状态、agent_demp_id 等配置。
  • ConnectionService
    • 连接层编排。
    • 根据当前配置和激活状态创建/更新 MqttManagerLiveKitManager
  • MqttManager
    • MQTT 连接、重连、订阅、发布。
    • 解析 robot/cmdsoul2user管理流式播报、TTS 队列和任务启动。
  • TaskController
    • 任务状态机。
    • 管理 patrolreceptionnotificationspeech 等任务,以及任务超时、巡逻推进、接待确认按钮。
  • MainTaskPolicy
    • 统一定义空闲态 / 特殊状态下的行为决策。
    • 控制是否允许自动回充、门禁工作流、到站播报、闲时问候。
  • NavController
    • Temi 导航与动作封装。
    • 包含 goTorechargereposeturnBytiltAnglerandomPatrol 等。
  • AutoRechargeScheduler
    • 机器人空闲到站后的延时自动回充。
    • 当前策略是空闲到站后 10 秒且不在 home base 时触发 recharge()
  • WorkflowService
    • 工作流调用编排。
    • 负责开门、关门、接待返航工作流,并在缺配置时尝试刷新服务端配置。
  • HttpManager
    • HTTP 接口封装。
    • 负责登录、激活、拉取运行时配置、执行工作流。
  • LiveKitManager
    • LiveKit 房间连接、事件监听、自动重连、麦克风开关控制。
    • 麦克风开启条件依赖人体检测稳定状态和 TTS 静音状态。
  • TelemetryManager
    • 周期性心跳与事件上报。
    • 包含电量、位置、运动状态、任务状态、MQTT/LiveKit 连接状态。
  • RobotEventHandler
    • 机器人事件辅助逻辑。
    • 用于状态归类、地点归一化、角度归一化。
  • UiState
    • 主界面上网络异常横幅、激活提示横幅、连接指示灯颜色更新。
  • PermissionManager
    • Temi 权限检查与申请。
  • AnimatedEmojiView
    • 自绘表情组件,受任务状态和 TTS 状态驱动。
  • LogManager
    • Logcat 监听与订阅。

3. 运行环境与依赖

3.1 开发环境

  • Android Studio近期版本即可需支持
    • AGP 8.10.1
    • Kotlin 2.0.21
  • JDK17
  • Android SDK
    • compileSdk = 36
    • minSdk = 23
    • targetSdk = 36
  • 运行设备Temi 真机优先;模拟器仅适合 UI 预览。

3.2 主要依赖

app/build.gradle.ktslibs.versions.toml

  • Temi SDKcom.robotemi:sdk:1.137.1
  • MQTT
    • org.eclipse.paho.android.service:1.1.1
    • org.eclipse.paho.client.mqttv3:1.2.5
  • LiveKit Android2.23.5
  • AndroidX / Material / Emoji2 等基础 UI 依赖。

3.3 权限

  • Temi 权限:
    • MAP
    • SEQUENCE
    • FACE_RECOGNITION
    • SETTINGS
  • Android 权限:
    • RECORD_AUDIO
    • CAMERA

说明:

  • MainActivity.onStart() 会注册机器人监听器并按激活状态决定是否启动 MQTT / LiveKit / Telemetry。
  • onRobotReady() 中会触发 PermissionManager.checkAndRequestPermissions()
  • LiveKit 权限未授予时不会建立连接。

4. 配置与持久化约定

应用配置统一存放在 SharedPreferences("app_prefs")

4.1 关键配置项

  • 服务与激活相关:
    • base_url:后端服务基础地址,例如 http://192.168.11.24:8088
    • login_username / login_password:调用登录接口用的账号密码
    • activation_code:激活码
    • device_name:设备名称
    • device_id:本机生成并持久化的设备标识
    • is_activated:是否已激活
  • 运行时下发配置:
    • mqtt_username / mqtt_password
    • od_wfid / od_wf_key:开门工作流配置
    • cd_wfid / cd_wf_key:关门工作流配置
    • vr_wfid / vr_wf_key:接待返航工作流配置
  • 任务与状态:
    • current_location:当前位置
    • special_state:特殊状态开关
    • agent_demp_idsoul2user 过滤字段
  • LiveKit
    • livekit_url
    • livekit_room
    • livekit_token
    • livekit_enabled
  • 兼容字段:
    • network_ip:仍会被保存,但现在是由 base_url 自动解析 host 后回填,主要给旧逻辑或排查时参考。

4.2 设置页实际能力

当前 SettingsActivity 不只是“填 IP”而是包含以下能力

  • 保存 base_urlagent_demp_id、登录用户名、登录密码。
  • 触发设备激活:
    • HttpManager.activateDevice()
    • 成功后拉取 MQTT 与工作流配置
    • is_activated 设为 true
  • 保存 LiveKit URL / 房间 / Token / 自动连接开关。
  • 选择当前位置。
  • 开关特殊状态。
  • 清除当前任务。
  • 查看 About 信息。
  • 长按 3 秒重启应用。

4.3 一个重要行为

base_url 发生变化时,设置页会主动清空以下信息并重置激活状态:

  • activation_code
  • device_name
  • is_activated
  • MQTT 用户名/密码
  • 所有工作流 ID / API Key

这意味着切环境后必须重新激活,文档和运维流程都要按这个行为来理解。

5. 通信协议与主题约定

5.1 MQTT Broker 与主题

  • Broker 地址:tcp://<base_url_host>:1883
    • 实际 host 由 ConnectionService.resolveBrokerHostFromBaseUrl()base_url 提取。
  • MQTT 账号:
    • 从本地 mqtt_username / mqtt_password 读取。
    • 这些值通常由激活成功后从服务端拉取。
  • 订阅主题:
    • robot/cmd:控制指令
    • soul2user:流式播报文本
  • 发布主题:
    • robot/status:状态心跳
    • robot/event:事件上报,例如 battery_low
    • robot/asrLiveKit 收到的文本/ASR 转发结果

5.2 指令映射

指令解析统一在 MqttManager.handleJsonCommand()

  • 基础控制:
    • recharge
    • goto
    • repose
    • turn
    • tilt
    • stop
    • terminate
    • continue
    • status
  • 语音:
    • speak
    • stream
  • 任务:
    • patrol
    • notification
    • reception

5.3 当前实现里的几个“非直觉行为”

这些点很容易和旧文档或接口约定不一致,接手时必须知道:

  • reception 指令里的 location 目前没有真正使用。
    • MqttManager 里接待地点被硬编码为 前台
    • destination 默认值是 会议室
    • text 默认值是“你是我要接待的贵宾吗?”
  • goto 若收到未知地点,不会报错退出,而是会回退到 会议室
    • 这是 NavController.goTo() 的当前保护逻辑。
  • stream 不只是简单播报全文。
    • 文本会进入 speechBuffer
    • 根据中英文标点和换行拆句
    • is_final=true 时会刷新剩余缓存
  • soul2user 消息支持通过 agent_demp_id 过滤 demp_id
  • session_idmessage_id 变化时,当前流式 TTS 会被打断并切换到新的会话上下文。

5.4 常见指令示例

{"action":"goto","location":"前台"}
{"action":"speak","text":"欢迎光临","lang":"zh"}
{"action":"patrol","flag":false,"locations":["前台","会议室"],"times":2,"waiting":5}
{"action":"notification","location":"大厅","text":"会议即将开始,请尽快入场"}

6. 关键业务流程说明

6.1 激活态控制

MainActivity 已经把“是否激活”纳入主流程:

  • 未激活时:
    • 主界面显示“请先激活应用”横幅
    • MQTT 断开
    • LiveKit 断开
    • Telemetry 停止
    • 不再进入正常联网工作态
  • 已激活时:
    • 恢复 MQTT / LiveKit 连接流程
    • 开始心跳上报

这部分逻辑是当前版本的重要门槛,所有“为什么没连上 MQTT / LiveKit”的排查都先确认 is_activated

6.2 任务状态机

任务逻辑集中在 TaskController.kt

  • currentTask 主要值:
    • 空字符串:空闲
    • speech
    • patrol
    • reception
    • notification
  • 巡逻:
    • 支持指定路线和随机路线
    • 支持 timeswaitingnonStop
    • 通过 handlePatrolArrival() 推进路线索引和剩余圈数
  • 接待:
    • 到达接待点后开启等待
    • 稳定检测到人时显示确认按钮并播报接待文案
    • 点击按钮后前往目的地
  • 通知:
    • 到达目标地点即播报一次并结束任务
  • 纯播报:
    • 由 MQTT 流式/非流式语音触发
    • TTS 队列清空后自动清回空任务
  • 任务超时:
    • 接待任务在等待阶段会启动 15 分钟超时
    • 超时后播报“任务超时了,任务被取消,我先回充电桩了”并执行回充

6.3 到站、播报与自动回充

onGoToLocationStatusChanged() 是到站处理的关键入口:

  • 到站后会:
    • 更新 lastArrivalLocation
    • 回写 current_location
    • 处理巡逻到站推进
    • 处理接待任务到站
    • 处理通知任务到站
    • 根据 MainTaskPolicy 决定是否播报“已到达xxx”
  • 自动回充当前规则:
    • 仅在空闲任务或 speech 任务下允许
    • 特殊状态下禁用
    • 仅在不在 home base 时生效
    • 到站 10 秒后自动执行 recharge()

6.4 人体检测、门禁与问候

人体检测在 MainActivity 中做去抖:

  • DETECTED:约 0.8 秒稳定确认
  • IDLE:约 5 秒稳定确认

稳定状态变化后:

  • 会调用 LiveKitManager.setDetectionActive() 更新麦克风逻辑。
  • 会优先交给 TaskController.handleDetectionStateChanged() 处理任务内行为。
  • 如果当前是空闲态且允许门禁逻辑:
    • home base 检测到人时执行开门工作流
    • 回到 IDLE 时执行关门工作流
  • 如果当前是空闲态且不在 home base
    • 检测到人时会按当前时段播报“早上好 / 中午好 / 下午好 / 晚上好”

6.5 LiveKit 与语音互斥

LiveKit 麦克风并不是“连上就开”,而是由三项共同决定:

  • LiveKit 连接时传入的 enableMic
  • detectionActive == true
  • ttsMuted == false

也就是说:

  • 机器人开始 TTS 时会自动关闭麦克风。
  • TTS 结束后才允许再次开麦。
  • 没有人时不会持续开麦。

6.6 工作流调用

当前工作流主要有三类:

  • 开门:od_wfid / od_wf_key
  • 关门:cd_wfid / cd_wf_key
  • 接待返航:vr_wfid / vr_wf_key

调用路径:

  • WorkflowService.executeDoorWorkflow():处理开门/关门。
  • WorkflowService.markReceptionReturnPending()
    • 在接待确认按钮点击后设置“返航待触发”。
  • WorkflowService.triggerReceptionReturnWorkflowIfNeeded()
    • 当机器人后续回到 home base 时触发返航工作流。

补充说明:

  • 如果本地没有 workflow 配置,WorkflowService 会尝试重新调用 fetchRuntimeConfigs() 刷新一次。
  • 工作流执行失败时,主界面会展示短暂的“网络异常”横幅。

6.7 Telemetry 上报

TelemetryManager 负责状态上报:

  • 心跳频率:每 15 秒一次
  • 状态快照字段包括:
    • task
    • location
    • mqttConnected
    • liveKitConnected
    • battery
    • movement
    • position
  • 低电量策略:
    • 电量 <= 20% 且未充电
    • 10 分钟内只重复提醒一次
    • 本地播报“电量低,请及时充电。”
    • robot/event 发布 battery_low

7. 日志与排障

7.1 主要日志来源

  • Logcat Tag
    • MainActivity
    • MqttManager
    • LiveKitManager
    • SettingsActivity
    • ConnectionService
    • TaskController
    • TelemetryManager
    • HttpManager
  • LogManager.startLogcatListener() 会在应用启动时开始监听。

7.2 排障建议

  • MQTT 连不上:
    • 先确认是否已激活
    • 再看 base_url 是否能正确解析出 host
    • 再看本地是否已有 mqtt_username / mqtt_password
    • 查看 MqttManager 日志中的 MQTT connect skippedInitial connection failed
  • 激活失败:
    • 检查 base_url 是否正确
    • 检查登录账号密码是否正确
    • 检查激活码和设备名是否填写完整
    • 查看 HttpManagerLogin failedActivation failed
  • 工作流不触发:
    • 检查本地是否已保存 od_* / cd_* / vr_*
    • 确认 home base 地点名称归一化后能匹配
    • 查看是否处于特殊状态或非空闲任务,导致门禁逻辑被策略层禁用
  • 接待任务不工作:
    • 先注意当前实现里接待地点默认就是 前台
    • 检查是否稳定检测到人,而不是瞬时检测
    • 检查按钮是否显示、任务是否超时被取消
  • 导航到错误地点:
    • 当前未知地点会自动回退到 会议室
    • 先检查 Temi 侧地点名称是否与消息一致
  • LiveKit 不连或没声音:
    • 检查 URL / Room / Token / 自动连接开关
    • 检查麦克风和摄像头权限
    • 注意“已连接但没人时不开麦”是当前设计,不是异常
  • monitor.py 调试失败:
    • 它仍然写死了 API_KEY / API_SECRET / URL / 房间名
    • 需要和当前 LiveKit 环境保持一致

8. 常见改动场景指引

8.1 新增 MQTT 指令

推荐修改顺序:

  1. MqttManager.handleJsonCommand() 增加 action 分支。
  2. 如果涉及持续态流程,在 TaskController 增加任务类型,而不是把状态散落在 MainActivity
  3. 如果需要策略控制,同时补 MainTaskPolicy
  4. 如果需要状态上报,扩展 TelemetryManager

8.2 修正接待逻辑

如果你希望接待任务真正使用 MQTT 中的 location

  1. 修改 MqttManagerreception 分支,不要再写死 前台
  2. 联调 TaskController.startReceptionMode() 与现场 Temi 地点名称。
  3. 回归测试接待确认按钮、接待返航工作流、朝向恢复逻辑。

8.3 调整自动回充或门禁策略

优先改这里:

  • MainTaskPolicy:决定什么情况下允许自动回充、门禁、问候
  • AutoRechargeScheduler:决定延时多久回充
  • MainActivity.handleStableDetectionStateChanged():决定何时触发开门/关门

8.4 更换服务环境

新环境切换步骤建议如下:

  1. 在设置页改 base_url
  2. 确认激活状态已被重置
  3. 重新填写登录信息和激活码
  4. 重新激活,拉取 MQTT 与工作流配置
  5. 再检查 LiveKit 参数是否也需要同步更新

8.5 扩展 HTTP / 工作流集成

建议在 HttpManager 中新增原子接口,在 WorkflowService 中编排业务流程,避免把 HTTP 细节直接散落到 MainActivity

9. 安全与后续优化建议

  • 敏感信息:
    • 登录账号密码目前明文保存在 SharedPreferences
    • LiveKit 默认 API_KEY / API_SECRET 仍写在代码中
    • monitor.py 里也写死了 LiveKit 凭据和 URL
  • 配置管理:
    • 现在已经有“激活后拉运行配置”的雏形,可以继续把更多环境配置收敛到服务端
  • 协议一致性:
    • reception.location 未实际生效
    • goto 未知地点会静默降级到 会议室
    • 这些行为最好和上游协议重新对齐
  • 文案资源化:
    • 业务提示语很多还写在 Kotlin 代码里,后续可以逐步迁移到 strings.xml
  • 稳定性:
    • 工作流失败现在只是展示网络异常横幅,可考虑补充错误事件上报和重试机制

10. 建议接手路径

如果你是第一次接手,建议按下面顺序熟悉:

  1. 先在真机上跑通激活流程。
  2. 在设置页填好 base_url、登录账号、激活码、设备名,确认 MQTT 能连上。
  3. gotospeakpatrolnotification 四类指令验证基础链路。
  4. 再测试空闲态门禁、接待任务、自动回充、低电量事件。
  5. 最后再看 technique.md 里的流程图,对照 MainActivityTaskController 理解策略差异。

如需继续维护,建议同步更新 README.mdtechnique.md,因为它们目前还有一部分内容停留在旧版实现描述。