# 与前端对接文档 ## 整体架构 ``` ┌──────────────────────────────────────────────────────────┐ │ 浏览器 (Vue3 前端) │ │ - 自动模式:观看 MJPEG 视频流 │ │ - 手动模式:键盘遥控 + MJPEG 视频流 │ │ - 调试模式:PID 调参 │ └──────┬──────────────┬──────────────┬─────────────────────┘ │ HTTP │ WebSocket │ HTTP (MJPEG) ▼ ▼ ▼ ┌──────────────┐ ┌──────────┐ ┌───────────────────┐ │ Nginx │ │rosbridge │ │ web_video_server │ │ 静态文件 │ │ :9090 │ │ :8081 │ │ 反向代理 │ └────┬─────┘ └────────┬──────────┘ └──────┬───────┘ │ │ │ ▼ ▼ │ ┌────────────────────────────────┐ └─────►│ ROS2 节点 │ │ - /cmd_wheel (轮速控制) │ │ - /cmd_gimbal (云台控制) │ │ - /pid_config (PID参数) │ │ - /api/mode/switch (模式切换) │ └────────────────────────────────┘ ``` ## 一、Nginx 配置 Nginx 负责三件事:托管 Vue 前端静态文件、反代 MJPEG 视频流、反代 HTTP API。 ### 1.1 前端部署 构建产物在 `dist/` 目录,部署到服务器后由 Nginx 直接托管: ```bash # 本地构建 cd aimbot-web pnpm build # 上传到服务器 scp -r dist/* user@server:/var/www/aimbot/ ``` ### 1.2 Nginx 配置示例 ```nginx server { listen 80; server_name your-domain.com; # 前端静态文件 root /var/www/aimbot; index index.html; # SPA 路由回退 — 所有非文件请求回 index.html location / { try_files $uri $uri/ /index.html; } # MJPEG 视频流反代 (web_video_server) location /stream { proxy_pass http://127.0.0.1:8081/stream; proxy_http_version 1.1; proxy_buffering off; # MJPEG multipart 边界必须保持完整 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # 长连接支持 proxy_set_header Connection ""; chunked_transfer_encoding off; # 超时配置 — 视频流需要长连接 proxy_read_timeout 86400s; proxy_send_timeout 86400s; } # 模式切换 API (HTTP → ROS2 节点) location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header Content-Type application/json; } } ``` ### 1.3 关键说明 | 配置项 | 说明 | |--------|------| | `proxy_buffering off` | MJPEG 流必须关闭缓冲,否则画面延迟严重 | | `chunked_transfer_encoding off` | multipart 边界依赖原始编码 | | `proxy_read_timeout 86400s` | 视频流是长连接,超时必须足够大 | | `try_files $uri /index.html` | Vue Hash 路由支持,直接访问 /#/manual 等路径 | --- ## 二、ROS2 环境配置 ### 2.1 rosbridge (WebSocket 服务) 前端通过 roslibjs 直连 rosbridge WebSocket,不走 Nginx 反代。 ```bash # 安装 sudo apt install ros-${ROS_DISTRO}-rosbridge-server # 启动 (默认 ws://0.0.0.0:9090) ros2 run rosbridge_server rosbridge_websocket ``` ### 2.2 web_video_server (MJPEG 推流) ```bash # 安装 sudo apt install ros-${ROS_DISTRO}-web-video-server # 启动 (默认 http://0.0.0.0:8081) # 发布摄像头话题后自动生成 /stream?topic= ros2 run web_video_server web_video_server ``` ### 2.3 话题一览 rosbridge 发布/订阅的话题需要与前端 `config.js` 一致: | 话题 | 消息类型 | 方向 | 用途 | |------|----------|------|------| | `/cmd_wheel` | `std_msgs/Float32MultiArray` | 前端→ROS2 | 左右轮速 `[left, right]` | | `/cmd_gimbal` | `geometry_msgs/Twist` | 前端→ROS2 | 云台角速度 `angular.y`(pitch) `angular.z`(yaw) | | `/pid_config` | `std_msgs/String` | 前端→ROS2 | PID 参数 JSON | ### 2.4 模式切换 API 前端 HTTP POST → Nginx 反代 → ROS2 节点(用户自行实现 HTTP 端): ``` POST /api/mode/switch Content-Type: application/json { "mode": "auto" | "manual" | "debug" } ``` 此接口需由 ROS2 侧 HTTP 服务(如 FastAPI / Flask / ros2-web-bridge)接收并处理模式切换逻辑。 --- ## 三、MJPEG 视频流地址 `web_video_server` 的 URL 规则:`http://:8081/stream?topic=<话题名>` 前端 `config.js` 中配置对应 URL: ```js // src/config.js export const MJPEG_AUTO_URL = '/stream?topic=/camera_auto' export const MJPEG_MANUAL_URL = '/stream?topic=/camera_manual' ``` 使用 `/stream` 相对路径时由 Nginx 反代到 `web_video_server`,避免跨域问题。 ### 摄像头话题发布示例 ```bash # 确保摄像头话题有数据 ros2 run image_transport republish raw in:=/camera_auto/image_raw out:=/camera_auto/compressed ``` `web_video_server` 自动识别话题类型并推送 MJPEG。 --- ## 四、启动顺序 ```bash # 1. 启动 ROS2 核心节点 ros2 launch your_robot bringup.launch.py # 2. 启动 rosbridge ros2 run rosbridge_server rosbridge_websocket & # 3. 启动视频推流 ros2 run web_video_server web_video_server & # 4. 启动模式切换 HTTP 服务(自行实现) python3 mode_api_server.py & # 5. 启动/重载 Nginx sudo systemctl reload nginx ``` --- ## 五、前端 config.js 配置 部署前修改 `src/config.js` 中的地址以匹配实际服务器环境: ```js // 后端 HTTP API(模式切换) export const HTTP_API_BASE = '' // 同域代理可留空或填 '/api' // rosbridge WebSocket export const ROSBRIDGE_URL = 'ws://192.168.1.100:9090' // 改成 ROS2 主机 IP // MJPEG 视频流 — 经 Nginx 代理 export const MJPEG_AUTO_URL = '/stream?topic=/camera_auto' export const MJPEG_MANUAL_URL = '/stream?topic=/camera_manual' // ROS 话题 — 必须与 ROS2 侧一致 export const CMD_WHEEL_TOPIC = '/cmd_wheel' export const CMD_GIMBAL_TOPIC = '/cmd_gimbal' export const PID_CONFIG_TOPIC = '/pid_config' // 键盘控制参数 — 按实际机器人调整 export const MAX_LINEAR = 0.5 // 最大线速度 m/s export const MAX_ANGULAR = 1.0 // 最大角速度 rad/s export const WHEEL_SEPARATION = 0.2 // 轮距 m export const GIMBAL_PITCH_SPEED = 0.5 // 云台 pitch 角速度 rad/s export const GIMBAL_YAW_SPEED = 0.5 // 云台 yaw 角速度 rad/s ``` --- ## 六、前端 nginx 完整部署命令 ```bash # 构建 cd aimbot-web && pnpm build # 部署 sudo cp -r dist/* /var/www/aimbot/ sudo cp nginx-aimbot.conf /etc/nginx/sites-available/aimbot sudo ln -s /etc/nginx/sites-available/aimbot /etc/nginx/sites-enabled/ sudo nginx -t && sudo systemctl reload nginx ``` --- ## 七、故障排查 | 现象 | 检查项 | |------|--------| | MJPEG 不出画面 | `web_video_server` 是否运行,话题是否有数据,Nginx `proxy_buffering` 是否设为 `off` | | rosbridge 连不上 | 防火墙是否开放 9090,`ROSBRIDGE_URL` 是否用 `ws://` 协议 | | 按键无反应 | rosbridge 连接状态是否为"已连接",话题名是否与 ROS2 侧一致 | | 模式切换报错 | `/api/mode/switch` 的 HTTP 服务是否实现并运行 | | 页面空白 | Nginx `try_files` 是否配了 `$uri /index.html` |