289 lines
13 KiB
Markdown
289 lines
13 KiB
Markdown
# 部署与运维手册(项目总结)
|
||
|
||
本文面向 **生产/外场部署**:说明 **voice_drone_assistant** 是什么、与 **云端** / **ROS 伴飞桥** / **PX4** 如何衔接,以及 **推荐启动顺序**、**环境变量**与**常见问题**。
|
||
协议细节见 [`llmcon.md`](llmcon.md),通用配置索引见 [`PROJECT_GUIDE.md`](PROJECT_GUIDE.md),伴飞桥行为见 [`FLIGHT_BRIDGE_ROS1.md`](FLIGHT_BRIDGE_ROS1.md),`flight_intent` 字段见 [`FLIGHT_INTENT_SCHEMA_v1.md`](FLIGHT_INTENT_SCHEMA_v1.md)。
|
||
|
||
---
|
||
|
||
## 1. 项目总结
|
||
|
||
### 1.1 定位
|
||
|
||
**voice_drone_assistant** 是板端 **语音无人机助手**:麦克风 → 降噪/VAD → **SenseVoice STT** → **唤醒词** → 用户一句指令 → **云端 WebSocket**(LLM + TTS)或 **本地 Qwen + Kokoro** → 若服务端返回 **`flight_intent`**,可在本机 **校验后执行**(TCP Socket 旧路径,或 **ROS 伴飞桥** 推荐路径)。
|
||
|
||
### 1.2 推荐数据流(方案一:云 → 语音程序 → ROS 桥)
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
subgraph cloud [云端]
|
||
WS[WebSocket LLM+TTS]
|
||
end
|
||
subgraph board [机载 香橙派等]
|
||
MIC[麦克风]
|
||
MAIN[main.py TakeoffPrintRecognizer]
|
||
ROSPUB[子进程 publish JSON]
|
||
BRIDGE[flight_bridge ros1_node]
|
||
MAV[MAVROS]
|
||
end
|
||
FCU[PX4 飞控]
|
||
|
||
MIC --> MAIN
|
||
MAIN <-->|WSS pcm_asr_uplink + flight_intent| WS
|
||
MAIN -->|ROCKET_FLIGHT_INTENT_ROS_BRIDGE| ROSPUB
|
||
ROSPUB -->|std_msgs/String /input| BRIDGE
|
||
BRIDGE --> MAV --> FCU
|
||
```
|
||
|
||
- **不**把 ROS 直接暴露给公网:云端只连板子的 **WSS/WS**;飞控由 **本机 MAVROS + 伴飞桥** 执行。
|
||
- **TCP Socket**(`system.yaml` → `socket_server`)是另一条试飞控通道,与云端 **无关**;未起 Socket 服务端时仅会重连日志,不影响 ROS 方案。
|
||
|
||
### 1.3 目录与核心入口(仓库根 = `voice_drone_assistant/`)
|
||
|
||
| 路径 | 说明 |
|
||
|------|------|
|
||
| `main.py` | 语音助手入口 |
|
||
| `with_system_alsa.sh` | 建议包装启动,修正 Conda 与系统 ALSA |
|
||
| `voice_drone/main_app.py` | 唤醒、云端/本地 LLM、TTS、`flight_intent` 执行策略 |
|
||
| `voice_drone/flight_bridge/ros1_node.py` | ROS1 订阅 `/input`,执行 `flight_intent` |
|
||
| `voice_drone/flight_bridge/ros1_mavros_executor.py` | MAVROS:offboard / AUTO.LAND / RTL |
|
||
| `voice_drone/tools/publish_flight_intent_ros_once.py` | 单次向 ROS 发布 JSON(主程序 ROS 桥会子进程调用) |
|
||
| `scripts/run_flight_bridge_with_mavros.sh` | 一键:roscore(可选)+ MAVROS + 伴飞桥 |
|
||
| `scripts/run_flight_intent_bridge_ros1.sh` | 仅伴飞桥(须已有 roscore + MAVROS) |
|
||
| `voice_drone/config/system.yaml` | 音频、STT、TTS、云端、`assistant` 等 |
|
||
| `requirements.txt` | Python 依赖;**rospy** 来自 `apt` 的 ROS Noetic,见文件内注释 |
|
||
|
||
---
|
||
|
||
## 2. 环境与依赖
|
||
|
||
### 2.1 硬件与系统(典型)
|
||
|
||
- ARM64 板卡(如 RK3588)、ES8388 等音频编解码器、USB/内置麦克风。
|
||
- Ubuntu 20.04 + **ROS Noetic**(伴飞桥 / MAVROS 路径);同机运行语音进程与 `ros1_node`。
|
||
- 飞控串口(如 `/dev/ttyACM0`)与 MAVROS `fcu_url` 一致。
|
||
|
||
### 2.2 Python
|
||
|
||
- Python 3.10+(与原仓库一致即可)。
|
||
- 在 **`voice_drone_assistant`** 根目录:
|
||
|
||
```bash
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
### 2.3 ROS / MAVROS(伴飞桥方案必选)
|
||
|
||
```bash
|
||
sudo apt install ros-noetic-ros-base ros-noetic-mavros ros-noetic-mavros-extras
|
||
# 按官方文档执行 mavros 地理库安装(如有)
|
||
```
|
||
|
||
- 语音主程序的 **ROS 桥**子进程会 `source /opt/ros/noetic/setup.bash` 并 **prepend** `PYTHONPATH`,**不要**在未 source ROS 的 shell 里把 `PYTHONPATH` 设成「只有工程根」,否则会找不到 `rospy`(参见 `main_app` 中 `_publish_flight_intent_to_ros_bridge`)。
|
||
|
||
### 2.4 模型与权重
|
||
|
||
- STT / TTS /(可选)VAD 放入 `models/`,或 `bash scripts/bundle_for_device.sh` 从原仓库打包。
|
||
- 本地 LLM:GGUF 默认路径或 `ROCKET_LLM_GGUF`;**纯云端对话**时可弱化本地模型,但回退/混合模式仍需。
|
||
|
||
---
|
||
|
||
## 3. 部署拓扑
|
||
|
||
### 3.1 单机一体化(常见)
|
||
|
||
同一台香橙派上同时运行:
|
||
|
||
1. **roscore**(若尚无 master,由 `run_flight_bridge_with_mavros.sh` 拉起)。
|
||
2. **MAVROS**(`px4.launch`,串口连 PX4)。
|
||
3. **伴飞桥** `python3 -m voice_drone.flight_bridge.ros1_node`(订阅 **`/input`**)。
|
||
4. **语音** `bash with_system_alsa.sh python main.py`。
|
||
|
||
`ROS_MASTER_URI` / `ROS_HOSTNAME`:一键脚本内默认 `http://127.0.0.1:11311` 与 `127.0.0.1`;**新开调试终端** 执行 `rostopic`/`rosservice` 前须自行 `source /opt/ros/noetic/setup.bash` 并 export **同一** `ROS_MASTER_URI`(见下文「常见问题」)。
|
||
|
||
### 3.2 网络
|
||
|
||
- 板子能访问 **云端 WebSocket**(`ROCKET_CLOUD_WS_URL`)。
|
||
- PX4 + 遥控 + 安全开关等按外场规范配置;本文不替代安全检校清单。
|
||
|
||
---
|
||
|
||
## 4. 启动顺序(推荐)
|
||
|
||
### 4.1 终端 A:飞控栈 + 伴飞桥
|
||
|
||
在 **`voice_drone_assistant`** 根目录:
|
||
|
||
```bash
|
||
cd /path/to/voice_drone_assistant
|
||
bash scripts/run_flight_bridge_with_mavros.sh /dev/ttyACM0 921600
|
||
```
|
||
|
||
脚本会:
|
||
|
||
- 设置 `ROS_MASTER_URI`、`ROS_HOSTNAME`(未预设时默认为本机 master);
|
||
- 如无 master 则启动 **roscore**;
|
||
- 启动 **MAVROS** 并等待 `/mavros/state` **connected**;
|
||
- 前台启动伴飞桥,日志中应出现:`flight_intent_bridge 就绪:订阅 /input`。
|
||
|
||
**仅桥(已有 MAVROS 时)**:
|
||
|
||
```bash
|
||
source /opt/ros/noetic/setup.bash
|
||
export ROS_MASTER_URI="${ROS_MASTER_URI:-http://127.0.0.1:11311}"
|
||
export ROS_HOSTNAME="${ROS_HOSTNAME:-127.0.0.1}"
|
||
bash scripts/run_flight_intent_bridge_ros1.sh
|
||
```
|
||
|
||
### 4.2 终端 B:语音助手 + 云端 + 执行飞控
|
||
|
||
```bash
|
||
cd /path/to/voice_drone_assistant
|
||
|
||
export ROCKET_CLOUD_VOICE=1
|
||
export ROCKET_CLOUD_WS_URL='ws://<云主机>:8766/v1/voice/session'
|
||
export ROCKET_CLOUD_AUTH_TOKEN='<token>'
|
||
export ROCKET_CLOUD_DEVICE_ID='drone-001' # 可选
|
||
|
||
# 云端返回 flight_intent 时是否在机端执行
|
||
export ROCKET_CLOUD_EXECUTE_FLIGHT=1
|
||
# 走 ROS 伴飞桥(与 Socket/offboard 序列互斥,勿双开重复执行)
|
||
export ROCKET_FLIGHT_INTENT_ROS_BRIDGE=1
|
||
# 可选:ROCKET_FLIGHT_BRIDGE_TOPIC=/input ROCKET_FLIGHT_BRIDGE_WAIT_SUB=2
|
||
|
||
# 默认关闭本地「起飞演示」口令直起 offboard;需要时再设为 1
|
||
# export ROCKET_LOCAL_KEYWORD_TAKEOFF=1
|
||
|
||
bash with_system_alsa.sh python main.py
|
||
```
|
||
|
||
成功时日志类似:`[飞控-ROS桥] 已发布至 /input`;伴飞桥端出现 `执行 flight_intent:steps=...`。
|
||
|
||
### 4.3 配置写进 YAML(可选)
|
||
|
||
- 云端:`system.yaml` → `cloud_voice`(`enabled`、`server_url`、`auth_token` 等)。
|
||
- 本地口令起飞:`assistant.local_keyword_takeoff_enabled`(默认 `false`);环境变量 `ROCKET_LOCAL_KEYWORD_TAKEOFF` **非空时优先生效**。
|
||
|
||
---
|
||
|
||
## 5. 环境变量速查(飞控与云端)
|
||
|
||
| 变量 | 含义 |
|
||
|------|------|
|
||
| `ROCKET_CLOUD_VOICE` | `1`:对话走云端 WebSocket |
|
||
| `ROCKET_CLOUD_WS_URL` | 云端会话地址 |
|
||
| `ROCKET_CLOUD_AUTH_TOKEN` | WS 鉴权 |
|
||
| `ROCKET_CLOUD_DEVICE_ID` | 设备 ID(可选) |
|
||
| `ROCKET_CLOUD_EXECUTE_FLIGHT` | `1`:云端 `flight_intent` 在机端执行 |
|
||
| `ROCKET_FLIGHT_INTENT_ROS_BRIDGE` | `1`:执行方式为 **发布到 ROS `/input`**,不跑机内 Socket+offboard 序列 |
|
||
| `ROCKET_FLIGHT_BRIDGE_TOPIC` | 默认 `/input` |
|
||
| `ROCKET_FLIGHT_BRIDGE_SETUP` | 子进程内 source ROS 的命令,默认 `source /opt/ros/noetic/setup.bash` |
|
||
| `ROCKET_FLIGHT_BRIDGE_WAIT_SUB` | 发布前等待订阅者的秒数,默认 `2`;`0` 即尽可能快发 |
|
||
| `ROCKET_LOCAL_KEYWORD_TAKEOFF` | 非空时:`1/true/yes` 开启 **`keywords.yaml` takeoff → 本地 offboard** |
|
||
| `ROCKET_CLOUD_PX4_CONTEXT_FILE` | 覆盖 `cloud_voice.px4_context_file`,合并进 session.start |
|
||
|
||
更多调试变量见 **`voice_drone/main_app.py` 文件头注释** 与 [`PROJECT_GUIDE.md`](PROJECT_GUIDE.md) 第 5 节。
|
||
|
||
---
|
||
|
||
## 6. 联调与自测
|
||
|
||
### 6.1 仅测 ROS 链(无语音)
|
||
|
||
终端已 `source /opt/ros/noetic/setup.bash` 且与 master 一致:
|
||
|
||
```bash
|
||
rostopic pub -1 /input std_msgs/String \
|
||
"data: '{\"is_flight_intent\":true,\"version\":1,\"actions\":[{\"type\":\"land\",\"args\":{}}],\"summary\":\"测\"}'"
|
||
```
|
||
|
||
注意:`std_msgs/String` 在命令行里只能写 **`data: '...json...'`**,不能把 JSON 放在消息顶层。
|
||
|
||
### 6.2 确认话题与 master
|
||
|
||
```bash
|
||
source /opt/ros/noetic/setup.bash
|
||
export ROS_MASTER_URI=http://127.0.0.1:11311
|
||
rosnode list
|
||
rostopic info /input
|
||
rosservice list | grep set_mode
|
||
```
|
||
|
||
若 `Unable to communicate with master!`:当前 shell 未连上正在运行的 **roscore**(或未 export 正确 `ROS_MASTER_URI`)。
|
||
|
||
---
|
||
|
||
## 7. 常见问题(摘录)
|
||
|
||
| 现象 | 可能原因 | 处理 |
|
||
|------|----------|------|
|
||
| `ModuleNotFoundError: rospy` | 子进程未继承 ROS 的 `PYTHONPATH` | 已修复为 `PYTHONPATH=<根>:$PYTHONPATH`;确保 `ROCKET_FLIGHT_BRIDGE_SETUP` 能 source Noetic |
|
||
| 语音端「已发布」但桥无日志 | 曾用相对 `input`,与全局 `/input` 不一致 | 伴飞桥默认已改为订阅 **`/input`**;重启桥 |
|
||
| `set_mode unavailable` / land 失败 | OFFBOARD 断流、MAVROS 异常等 | 伴飞桥降落逻辑已带持续 setpoint + 重连 proxy;仍失败则查 `rosservice`、`/mavros/state`、链路 |
|
||
| takeoff 超时 | 未进 OFFBOARD、未解锁、定位未就绪 | 查地面站、`/mavros/state`、适当增大 `~takeoff_timeout_sec`(ROS 私有参数) |
|
||
| ALSA underrun | 播放与采集竞争 | 板端常见;可调缓冲区/设备或 `recognizer.ack_pause_mic_for_playback` |
|
||
|
||
---
|
||
|
||
## 8. 安全与运维建议
|
||
|
||
- 外场前在 **SITL 或系留** 环境验证完整 **`flight_intent`** 序列。
|
||
- 云端 token、WS URL 勿提交到公开仓库;用环境变量或本机 **overlay** 配置注入。
|
||
- 升级伴飞桥或 MAVROS 后清日志重试一遍 **`/input`** 手发 JSON。
|
||
|
||
---
|
||
|
||
## 9. 迁移到另一台香橙派:是否只拷贝 `voice_drone_assistant` 即可?
|
||
|
||
**结论:目录是「代码 + 配置」的核心载体,但仅靠「整文件夹 scp 过去」通常不够;新板必须再装系统级依赖、模型与(可选)ROS,并按现场改配置。**
|
||
|
||
### 9.1 拷贝目录本身会带上什么
|
||
|
||
| 已包含 | 说明 |
|
||
|--------|------|
|
||
| 全部 Python 源码、`voice_drone/config/*.yaml` 默认配置 | 可直接改 YAML / 环境变量适配新环境 |
|
||
| `scripts/`、`with_system_alsa.sh`、`docs/` | 启动与说明在包内 |
|
||
|
||
### 9.2 新板必须单独准备(不随目录自动存在)
|
||
|
||
| 项 | 说明 |
|
||
|----|------|
|
||
| **Ubuntu + 音频/ALSA** | 与当前开发板同代或自行适配;录音设备索引可能变化,需重选或设 `ROCKET_INPUT_DEVICE_INDEX` |
|
||
| **`pip install -r requirements.txt`** | 每台新 Python 环境执行一次(或整体迁移同一 conda 目录) |
|
||
| **`models/`** | STT/TTS/VAD 体积大,**务必**在本机先 `bash scripts/bundle_for_device.sh /path/to/rocket_drone_audio` 或手工拷入,见 `models/README.txt` |
|
||
| **`cache/` GGUF** | 纯云端可不强依赖;若需本地 Qwen 回退,拷贝或设 `ROCKET_LLM_GGUF` |
|
||
| **ROS Noetic + MAVROS** | **apt** 安装;伴飞桥方案 **必选**;`rospy` **不要**指望只靠 pip |
|
||
| **云端连通** | 新板 IP/防火墙能访问 `ROCKET_CLOUD_WS_URL`;token 用环境变量注入 |
|
||
| **`dialout` 等权限** | 访问 `/dev/ttyACM0` 的用户加入 `dialout`,否则 MAVROS 无串口 |
|
||
| **`system.yaml` 现场差异** | `socket_server` IP、可选 `tts.output_device`、若麦索引固定可写 `audio.input_device_index` |
|
||
|
||
### 9.3 推荐迁移流程(简表)
|
||
|
||
1. 在旧机或 CI:**bundle 模型** → 打包整个 `voice_drone_assistant`(含 `models/`,按需含 `cache/`)。
|
||
2. 新香橙派:解压到任意路径,安装 **`requirements.txt`**、**ROS+MAVROS**、系统音频工具。
|
||
3. 用 **`with_system_alsa.sh python main.py`** 试麦与 STT;再按本文 **§4** 双终端起 **桥 + 语音**。
|
||
4. 首次外场前做一次 **`rostopic pub /input`** 手发 JSON(见 **§6**)。
|
||
|
||
### 9.4 常见误区
|
||
|
||
- **只拉 Git、不拷 `models/`**:STT/TTS 启动即失败。
|
||
- **新板 Noetic 未装却开 `ROCKET_FLIGHT_INTENT_ROS_BRIDGE`**:发布子进程仍可能报错。
|
||
- **假设麦克风设备号一定相同**:Orange Pi 刷机或换内核后常变,以首次启动日志为准。
|
||
|
||
---
|
||
|
||
## 10. 文档索引
|
||
|
||
| 文档 | 用途 |
|
||
|------|------|
|
||
| [`README.md`](../README.md) | 仓库简介、模型、`bundle` |
|
||
| [`PROJECT_GUIDE.md`](PROJECT_GUIDE.md) | 配置项与日常用法索引 |
|
||
| **本文** | 部署拓扑、启动顺序、环境变量、联调、**§9 迁移清单** |
|
||
| [`FLIGHT_BRIDGE_ROS1.md`](FLIGHT_BRIDGE_ROS1.md) | 伴飞桥参数、PX4 行为、`rostopic pub` 注意 |
|
||
| [`FLIGHT_INTENT_SCHEMA_v1.md`](FLIGHT_INTENT_SCHEMA_v1.md) | JSON 协议 |
|
||
| [`llmcon.md`](llmcon.md) | 云端协议 |
|
||
| [`CLOUD_VOICE_FLIGHT_CONFIRM_v1.md`](CLOUD_VOICE_FLIGHT_CONFIRM_v1.md) | **飞控口头二次确认**(闲聊不变、确认/取消/超时)云端与机端字段约定 |
|
||
|
||
---
|
||
|
||
*文档版本与仓库同步;若行为与代码不一致,以当前 `main_app.py`、`flight_bridge/*.py` 为准。*
|