Files
Vision-Web/README.md
T
2026-06-03 00:01:13 +08:00

236 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AimBot Web
基于 Vue 3 的机器人远程控制前端,提供自动监控、手动遥控和 PID 调参三个功能页面。
## 技术栈
| 层 | 技术 |
|----|------|
| 框架 | Vue 3.5 (Composition API, `<script setup>`) |
| 构建 | Vite 5 + pnpm |
| 路由 | Vue Router 4 (Hash 模式) |
| ROS 通信 | roslibjs → rosbridge WebSocket |
| HTTP | 原生 fetch |
## 项目结构
```
src/
├── main.js # 入口,挂载 App + Router
├── App.vue # 根布局:顶部导航 + router-view
├── config.js # 集中配置(地址、话题、控制参数)
├── router/index.js # Hash 路由表
├── composables/
│ └── useRosbridge.js # roslibjs 封装 Hook
└── views/
├── AutoMode.vue # 自动模式页
├── ManualMode.vue # 手动遥控页
└── DebugMode.vue # 调试模式页
```
## 架构分层
```
┌─────────────────────────────────────────────────────────┐
│ View 层 (views/*.vue) │
│ - 页面 UI 与用户交互 │
│ - 调用 composable + config │
├─────────────────────────────────────────────────────────┤
│ Composable 层 (composables/useRosbridge.js) │
│ - 封装 roslibjs 连接 / 发布 / 生命周期 │
│ - 暴露响应式 connected 状态 │
├─────────────────────────────────────────────────────────┤
│ Config 层 (config.js) │
│ - 所有可配置常量集中管理 │
│ - 部署时只需修改此文件 │
├─────────────────────────────────────────────────────────┤
│ Router 层 (router/index.js) │
│ - Hash 路由,/auto → /manual → /debug │
│ - 默认重定向到 /auto │
└─────────────────────────────────────────────────────────┘
```
## 路由设计
| 路径 | 页面 | 说明 |
|------|------|------|
| `#/auto` | AutoMode | 默认页,MJPEG 视频流 |
| `#/manual` | ManualMode | 键盘遥控 + 视频流 |
| `#/debug` | DebugMode | PID 参数配置 + 激光开关 |
| `#/` | → 重定向到 `#/auto` | |
选用 Hash 路由 (`createWebHashHistory`) 是为了避免部署到 Nginx 后直接访问子路径出现 404。
## 页面详解
### 1. AutoMode(自动模式)
**功能:** 显示自动运行过程的实时画面。
**数据流:**
```
web_video_server ──MJPEG──► <img src> ──► 浏览器渲染
```
**交互:**
- 「切换到当前模式」按钮 → `POST /api/mode/switch { mode: "auto" }` → ROS2 后端切换工作模式
**MJPEG 连接管理:**
- 组件挂载时 `<img>` 加载 MJPEG 流
- `onBeforeRouteLeave` 钩子中清空 `img.src`,确保离开页面时立即释放 TCP 连接
- 路由跳转顺序:旧页面断连 → 新页面建连,避免单连接服务端的冲突
### 2. ManualMode(手动模式)
**功能:** 键盘遥控机器人底盘和云台,J 键控制激光,同时观看实时画面。
**数据流:**
```
键盘事件 (keydown/keyup)
│
├─► pressed Set (WASD/方向键 多键集合)
│ │
│ ▼
│ computeVelocities() ◄── config.js
│ │
│ ├─► { left, right } ──► /cmd_wheel (值变化时发送)
│ └─► { pitch, yaw } ──► /cmd_gimbal (值变化时发送)
│ │
│ ▼
│ rosbridge ──► ROS2 节点
│
└─► J 键 (!e.repeat)
│
▼
POST /api/laser { action: "on"|"off" } ──► ROS2 HTTP 服务
```
**键盘映射策略:**
```
W (+线速度) ↑ (+pitch 度/秒)
A (+角速度) D (-角速度) ← (+yaw 度/秒) → (-yaw 度/秒)
S (-线速度) ↓ (-pitch 度/秒)
底盘 (差速驱动) 云台 (角度速率)
J 激光 开/关
```
- **多键同时按下**:W+A 同时按 = 前进 + 左转,自动合成左右轮速
- **同轴冲突**:W+S 同时按 → 相互抵消,线速度为 0
- **值变化才发布**:比较当前速度与上次发布值,无变化则跳过,避免无效 rosbridge 消息
- **自动启停**:首个按键按下启动 `requestAnimationFrame` 循环,所有按键松开启自动停止(publish 值不变的帧直接跳过)
- **J 键防重复**:`e.repeat` 过滤,长按 J 不会反复切换激光
**差速运动学转换:**
```
left_speed = linear - angular × (wheel_separation / 2)
right_speed = linear + angular × (wheel_separation / 2)
```
### 3. DebugMode(调试模式)
**功能:** PID 参数在线调参,激光开关,模式切换。
**交互:**
- 顶部三个按钮可切换任意模式
- **激光开关按钮**:「激光: ON/OFF」点击切换,`POST /api/laser { action: "on"|"off" }`
- 12 个数字输入框分 4 组:
- 视觉环 Yaw 电机:Kp / Ki / Kd
- 视觉环 Pitch 电机:Kp / Ki / Kd
- 角度环 Yaw 电机:Kp / Ki / Kd
- 角度环 Pitch 电机:Kp / Ki / Kd
- 「发布参数」按钮 → rosbridge 发布 JSON 到 `/pid_config` 话题
**发布数据格式:**
```json
{
"visual_yaw": { "kp": 1.0, "ki": 0.1, "kd": 0.01 },
"visual_pitch": { "kp": 1.0, "ki": 0.1, "kd": 0.01 },
"angle_yaw": { "kp": 2.0, "ki": 0.2, "kd": 0.02 },
"angle_pitch": { "kp": 2.0, "ki": 0.2, "kd": 0.02 }
}
```
## useRosbridge — 核心 Composable
```
useRosbridge()
│
├─ connect(url) → 建立 WebSocket,绑定 connection/close/error 事件
├─ disconnect() → 手动断开
├─ publish(topic, type, data) → 发布消息(自动缓存 Topic 对象)
├─ connected (ref) → 响应式连接状态
│
└─ onUnmounted() → 组件销毁时自动断开
```
- 每次调用 `useRosbridge()` 创建独立的 ros 实例
- Topic 对象按 `"topic:messageType"` 缓存,避免重复创建
- 组件卸载 (`onUnmounted`) 自动关闭 WebSocket,无需手动清理
## config.js — 配置项说明
```js
HTTP_API_BASE // HTTP API 基础地址
ROSBRIDGE_URL // rosbridge WebSocket,格式 ws://host:9090
MJPEG_AUTO_URL // 自动模式 MJPEG 流地址
MJPEG_MANUAL_URL // 手动模式 MJPEG 流地址
CMD_WHEEL_TOPIC // 底盘轮速话题名
CMD_GIMBAL_TOPIC // 云台角速度话题名
PID_CONFIG_TOPIC // PID 参数话题名
MAX_LINEAR // 最大线速度 (m/s)
MAX_ANGULAR // 最大角速度 (rad/s)
WHEEL_SEPARATION // 底盘轮距 (m)
GIMBAL_PITCH_DEG_S // 云台 pitch 角度速率 (度/秒)
GIMBAL_YAW_DEG_S // 云台 yaw 角度速率 (度/秒)
```
## HTTP API 接口一览
| 接口 | 方法 | 请求体 | 说明 | 触发位置 |
|------|------|--------|------|----------|
| `/api/mode/switch` | POST | `{"mode": "auto"\|"manual"\|"debug"}` | 切换工作模式 | Auto/Manual/Debug 页面按钮 |
| `/api/laser` | POST | `{"action": "on"\|"off"}` | 激光开关 | Manual J 键, Debug 按钮 |
## 通信架构总览
```
┌─────────────────────────────────────────────────────────┐
│ Vue3 前端 │
│ │
│ AutoMode.vue ────► fetch POST /api/mode/switch │
│ ────► <img src="/stream?topic=..."> │
│ ManualMode.vue ─► roslibjs ws://host:9090 │
│ ──► <img src="/stream?topic=..."> │
│ ──► fetch POST /api/laser (J 键) │
│ DebugMode.vue ──► roslibjs ws://host:9090 │
│ ───► fetch POST /api/mode/switch │
│ ───► fetch POST /api/laser (按钮) │
└──────────┬──────────────┬───────────────────────────────┘
│ HTTP │ WebSocket + MJPEG
▼ ▼
┌─────────┐ ┌──────────────┐
│ Nginx │ │ rosbridge │
│ 反代 │ │ web_video │
└────┬────┘ │ _server │
│ └──────┬───────┘
▼ ▼
ROS2 HTTP ROS2 话题
模式切换 底盘 / 云台 / PID
激光开关
```
## 开发命令
```bash
pnpm install # 安装依赖
pnpm dev # 开发服务器 → http://localhost:5173
pnpm build # 生产构建 → dist/
pnpm preview # 预览构建产物
```