diff --git a/README.md b/README.md index 9f457db..54166ab 100644 --- a/README.md +++ b/README.md @@ -1,346 +1,210 @@ -# Avaota F1 开发与集成 +# NaviGlass Client 📱 -> 面向仓库根目录的总览文档,整合 Day1–Day9 日志、任务清单与完成总结。 +
+ +**面向视障人士的智能导航与辅助系统 - 客户端** + +基于 Avaota F1 (全志 V821 RISC-V) 的嵌入式终端 + +[功能特性](#功能特性) • [硬件配置](#硬件配置) • [编译部署](#编译部署) • [程序架构](#程序架构) + +
--- -## 1. 项目简介 +## ✨ 功能特性 -本项目面向 **Avaota F1 AI 机器人**,基于 **全志 V821 / 32-bit RISC‑V** SoC,目标是在 Tina Linux 固件上实现一套「可量产」的机器人终端固件,集成: - -- 音频采集(板载模拟麦克风)与播放(I2S + MAX98357A) -- IMU 六轴姿态传感(ICM‑42688‑P) -- GC2083 MIPI 摄像头 JPEG 图像采集 -- UDP / HTTP / WebSocket 网络通讯 -- 多线程主程序与静态链接交叉编译流程 - -文档与代码组织按「Day1–Day9 开发日志 + 任务清单 + 完成总结」推进,可作为以后移植到其他 Tina Linux / 全志平台的模板工程。 - -目前对话的位置是本地Windows 11系统的主机,用于开发的环境是局域网中的Ubuntu服务器。 +- **摄像头采集**: GC2083 MIPI (1280×720 @20fps, JPEG 硬件编码) +- **音频采集**: 板载模拟麦克风 (16kHz/mono) +- **音频播放**: I2S + MAX98357A 功放 +- **IMU 传感**: ICM-42688-P 六轴 (GPIO 模拟 SPI) +- **网络通信**: WebSocket (音视频) + UDP (IMU) +- **自动启动**: 开机自动连接服务器 --- -## 2. 硬件与开发环境 +## 🔧 硬件配置 -### 2.1 目标硬件(板端) +### 核心硬件 -- **SoC**:全志 V821,32‑bit RISC‑V 架构 -- **板载外设** - - 模拟麦克风 → 内置 Audio Codec(audiocodec) - - I2S 数字功放:MAX98357A(BCLK/LRCK/DOUT:PD12/PD13/PD15) - - 摄像头:GC2083,MIPI‑CSI2,典型输出 1280×720 @ 20fps - - IMU:ICM‑42688‑P(GPIO 模拟 SPI) -- **操作系统**:Tina Linux(基于 OpenWrt 的 Allwinner SDK) +| 组件 | 型号 | 接口 | +|------|------|------| +| SoC | 全志 V821 | 32-bit RISC-V | +| 摄像头 | GC2083 | MIPI-CSI2 | +| 功放 | MAX98357A | I2S (PD12/PD13/PD15) | +| 麦克风 | 板载模拟 | Audio Codec | +| IMU | ICM-42688-P | GPIO SPI | -### 2.2 主机开发环境(PC) +### 引脚配置 -- **系统**:Ubuntu 24.04 LTS(同时也有 Windows + WSL 的混合开发) -- **工具链 & SDK** - - Tina SDK:`tina-v821-release` - - `/home/rongye/ProgramFiles/AvaotaF1/avaota_sdk/tina-v821-release` 这是SDK位置 - - 交叉编译工具链: - - **当前使用**:`prebuilt/rootfsbuilt/riscv/nds32le-linux-musl-v5d` ⭐ **musl 工具链(与开发板兼容)** - - 编译器前缀:`riscv32-linux-musl-` - - ~~已废弃~~:`out/toolchain/nds32le-linux-glibc-v5d` (glibc 工具链,与板端 musl libc 1.2.4 不兼容) - - `/home/rongye/ProgramFiles/AvaotaF1/avaota_app_demo` 这是交叉编译的位置 - - Python:通过 `python-is-python3` 或为遗留脚本装 python2 并软链到 `python` - -### 2.3 开发主机准备要点(Ubuntu 24.04) - -- 开启 i386 架构以兼容旧版 32 位库 -- 手动安装被移除的 `libncurses5` / `libtinfo5` -- 安装 bison / flex / 交叉编译依赖,修复 `lunch` / `make` 时报错 -- 注意 `make -j` 一定要限制并行度(如 `-j8`),避免 OOM +| 功能 | 引脚 | 说明 | +|------|------|------| +| I2S BCLK | PD12 | 音频位时钟 | +| I2S LRCK | PD13 | 左右声道时钟 | +| I2S DOUT | PD15 | 音频数据输出 | +| SPI SCLK | PD3 | IMU 时钟 | +| SPI MOSI | PD2 | IMU 数据输入 | +| SPI MISO | PD4 | IMU 数据输出 | +| SPI CS | PD5 | IMU 片选 | --- -## 3. 仓库结构建议 +## 💻 开发环境 -实际仓库结构可按以下思路组织(示例): +### 主机环境 -```text -. -├── ../Docs/DevLogs/ # (位于上级目录) 每日开发日志 -│ ├── Day1.md … Day18.md -├── docs/ # 本地硬件/SDK文档 -│ ├── 1.png … 2.png -│ ├── AvaotaF1.md -│ ├── 引脚.md -│ ├── TinaSDK-Docs/ -│ ├── tina_files_clean.csv -├── ESP32S3/ # 可参考的ESP32S3固件 -├── src/ -│ ├── audio/ # AudioCapture / AudioPlayer -│ ├── camera/ # Camera 类 / MPP 封装 -│ ├── imu/ # ICM‑42688 SPI 驱动与测试 -│ ├── network/ # UDP / HTTP / WebSocket 客户端 -│ ├── utils/ -│ ├── main.cpp # 主程序入口(多线程集成) -│ ├── main_test.cpp # 本地硬件自检程序 -│ ├── Makefile # 交叉编译配置 -│ └── build_*.sh # 构建脚本(main/test/phaseX) -├── build_main.sh -├── logs.md # 编译时的日志(实时填写) -└── README.md # 本文档 +- **系统**: Ubuntu 24.04 LTS +- **SDK**: Tina SDK (tina-v821-release) +- **工具链**: musl (`riscv32-linux-musl-`) + +### SDK 路径 + +``` +/home/rongye/ProgramFiles/AvaotaF1/avaota_sdk/tina-v821-release +├── prebuilt/rootfsbuilt/riscv/nds32le-linux-musl-v5d/ ← 工具链 +└── ... ``` -你可以直接把 Day1–Day7、任务清单与完成总结放到 `../docs/DevLogs/` 目录,并用当前 README 作为入口索引。 +> ⚠️ 必须使用 **musl 工具链**,glibc 工具链与开发板不兼容 --- -## 4. 功能模块概览 +## 🚀 编译部署 -### 4.1 音频系统 - -**输入:板载模拟麦克风** - -- 通过 SoC 内部 **Audio Codec (audiocodec)** 采集 -- ALSA 设备:`hw:audiocodec` 或 `hw:0,0`(录音推荐 `plughw:0,0`) -- 运行时配置: - - `MIC Switch` 开启 - - `MIC Gain` 建议值 25(在音量与底噪之间平衡) - - `adc-vol` 与 `lineout-gain` 使用 DTS 默认值或适度调整 -- 采样参数: - - 16 kHz, S16_LE, Mono -- 典型链路: - - `setup_mic.sh` → `arecord` → `/tmp/test_mic.wav` → `aplay` / 上行网络 - -**输出:I2S + MAX98357A** - -- I2S0 接 MAX98357A,扬声器输出 -- Device Tree 为每个引脚创建独立 pinctrl 节点: - - `i2s0_bclk_pin`:PD12 - - `i2s0_lrck_pin`:PD13 - - `i2s0_dout0_pin`:PD15 -- I2S 平台设备 `&i2s0_plat` 绑定这些引脚,`status = "okay"` -- 通过 ALSA `aplay` / 自己的 `AudioPlayer` 类进行播放 - -### 4.2 IMU 传感器(ICM‑42688‑P) - -- 最终采用 **GPIO 模拟 SPI**: - - SCLK: PD3 - - MOSI: PD2 - - MISO: PD4 - - CS : PD5 -- SPI Mode0,软件 bit‑bang,速率约 500 kHz(可按需提升) -- 主要特性: - - WHO_AM_I = 0x47 识别验证 - - 加速度计:±16g,1 kHz ODR - - 陀螺仪:±2000 °/s,1 kHz ODR - - 温度通道:用于环境监控与漂移补偿 -- 静止状态验证: - - 合加速度 ≈ 9.8 m/s² - - 陀螺仪接近 0 °/s -- 上层封装: - - `ICM42688` 类提供采样与单位转换 - - 独立 `test_imu` 自检程序 - - 在主程序中通过 UDP 周期性上报 JSON/结构体数据 - -### 4.3 摄像头系统(GC2083 + MPP) - -- 使用 Allwinner Eyesee‑MPP 框架:SYS → VI → ISP → VENC -- 流水线: - - VI(接 MIPI 摄像头) - - ISP(自动曝光、白平衡、降噪) - - VENC(JPEG 编码) -- 关键配置: - - 分辨率:1280×720 @ 20fps(可调) - - JPEG 质量:80(在质量与码率之间折中) - - VI Buffer:5 帧 - - VBV Buffer:4 MB,避免 `VBV FULL` 错误 -- `Camera` 类职责: - - 完成 MPP 初始化 / 绑定 / 销毁 - - 按需抓拍单帧 JPEG(用于 WebSocket 发送或本地保存) - - 提供阻塞式 `capture_frame()` 接口与重试机制 -- 测试程序: - - `test_camera` 抓拍多张 JPEG 保存到 SD 卡 - - 实测成功率 100%,文件大小 20–80 KB 之间,画面曝光正常 - -### 4.4 网络通讯 - -**UDP** - -- 轻量 IMU 数据上报通道 -- 使用 POSIX socket,静态链接,无额外依赖 -- 典型用法: - - `UDPSender` 初始化目标 IP/Port - - 周期性发送 IMU/状态数据 - -**HTTP(libcurl 或轻量封装)** - -- 主要用途: - - 从服务器拉取 TTS 音频流(如 `stream.wav`) - - 拉取配置文件或诊断信息 -- 流式下载接口已预留,可边下边写入 `AudioPlayer` 播放 - -**WebSocket** - -- 早期方案:SDK 内置 `libuwsc`(后期为规避依赖,可用自实现轻量 WS 客户端) -- 主要用途: - - 上行:摄像头 JPEG 帧、音频 PCM 片段 - - 下行:控制指令 / 状态同步 -- 接口设计: - - `WSClient` 负责 TCP 连接、握手、帧收发、心跳与重连 - - 主线程中,每个子模块持有各自的 WSClient 实例或共享连接 - ---- - -## 5. 编译与构建流程 - -### 5.1 Tina SDK 环境准备(概要) - -1. 解压 SDK: - ```bash - mkdir -p ~/ProgramFiles/avaota_sdk - tar -xvf tina-v821-*.tar.xz -C ~/ProgramFiles/avaota_sdk - ``` -2. 初始化环境: - ```bash - cd ~/ProgramFiles/avaota_sdk/tina-v821-release - source build/envsetup.sh - lunch # 选择 avaota_f1 / v821 相关配置 - ``` -3. 全量编译: - ```bash - make -j8 - pack # 需要时打包固件 - ``` - -### 5.2 应用程序交叉编译 - -在 `src/` 目录中提供一个或多个构建脚本,例如: +### 1. 环境初始化 ```bash -#!/bin/bash -set -e - -SDK_ROOT=~/ProgramFiles/AvaotaF1/avaota_sdk/tina-v821-release -# ⚠️ 使用 musl 工具链(与开发板兼容) -TOOLCHAIN=${SDK_ROOT}/prebuilt/rootfsbuilt/riscv/nds32le-linux-musl-v5d/bin - -export PATH=${TOOLCHAIN}:$PATH - -make clean -make all -j4 # 或按目标拆分:make main / make test_audio / make test_imu +cd ~/ProgramFiles/AvaotaF1/avaota_sdk/tina-v821-release +source build/envsetup.sh +lunch # 选择 avaota_f1 ``` -Makefile 要点: +### 2. 交叉编译 -- 使用 `riscv32-linux-musl-g++` 编译器(musl 工具链) -- 动态链接器:`/lib32/ld.so.1`(板端需创建符号链接:`ln -s /lib32/ilp32d/libc.so /lib32/ld.so.1`) -- 链接静态或最小依赖的动态库 -- 注意链接顺序:业务库 → MPP/ISP/cedarx → `-lpthread -lrt -lm -ldl -lstdc++` +```bash +cd ~/ProgramFiles/AvaotaF1/avaota_app_demo +./build_main.sh +``` -### 5.3 部署与运行 +### 3. 部署到开发板 -1. 将交叉编译好的可执行文件拷贝到 SD 卡: - ```bash - cp avaota_client /media/$USER/SDCARD/ - ``` -2. 板端挂载 SD 卡并复制到 `/tmp`: - ```bash - mount /dev/mmcblk0p1 /mnt/extsd - cp /mnt/extsd/avaota_client /tmp/ - chmod +x /tmp/avaota_client - ``` -3. 运行: - ```bash - /tmp/avaota_client - ``` +```bash +# 复制到 SD 卡 +cp avaota_client /media/$USER/SDCARD/ -> 推荐所有测试程序(`test_audio` / `test_imu` / `test_camera` / `avaota_test`)都统一走上述流程,避免执行权限与只读分区问题。 +# 板端执行 +mount /dev/mmcblk0p1 /mnt/extsd +cp /mnt/extsd/avaota_client /mnt/UDISK/ +chmod +x /mnt/UDISK/avaota_client +/mnt/UDISK/avaota_client +``` + +### 4. 自动启动配置 + +程序已配置开机自启动: +- 位置: `/mnt/UDISK/avaota_client` +- 方式: `/etc/init.d/avaota` + `load_script.conf` +- 延迟: 15 秒 (等待音频系统就绪) --- -## 6. 主程序(集成)架构示意 - -主程序建议使用多线程模型,将各个模块解耦: +## 🏗️ 程序架构 ```cpp -// 伪代码示例 int main() { - init_logging(); - init_network_config(); // 服务器 IP / 端口 / 路径等 - init_signal_handler(); // Ctrl+C 安全退出 - - std::thread cam_thread(run_camera_loop); - std::thread mic_thread(run_audio_capture_loop); - std::thread spk_thread(run_audio_play_loop); - std::thread imu_thread(run_imu_udp_loop); - - // 可选:主线程处理下行指令 / 状态机 - run_main_control_loop(); - - // 等待退出 + init_signal_handler(); // Ctrl+C 安全退出 + + std::thread cam_thread(run_camera_loop); // 摄像头 → WebSocket + std::thread mic_thread(run_audio_capture); // 麦克风 → WebSocket + std::thread spk_thread(run_audio_play); // WebSocket → 扬声器 + std::thread imu_thread(run_imu_udp); // IMU → UDP + cam_thread.join(); mic_thread.join(); spk_thread.join(); imu_thread.join(); - return 0; } ``` -每个线程内部: +### 核心模块 -- 初始化各自的硬件和网络客户端 -- 进入循环: - - 采集 → 编码(可选) → 通过 UDP/WS 发送 - - 或从 HTTP/WS 接收 → 解码(可选) → 播放/控制硬件 -- 捕获异常并尝试重连 / 恢复,必要时上报主线程 +| 目录 | 模块 | 功能 | +|------|------|------| +| `src/audio/` | AudioCapture | 麦克风采集 (ALSA) | +| `src/audio/` | AudioPlayer | 扬声器播放 (I2S) | +| `src/camera/` | Camera | MPP 框架封装 | +| `src/imu/` | ICM42688 | GPIO SPI 驱动 | +| `src/network/` | WSClient | WebSocket 客户端 | +| `src/network/` | UDPSender | UDP 发送 | --- -## 7. 日志与文档索引 +## 📡 通信协议 -可以在 README 中给出所有开发日志与计划文档的入口,方便回溯: +### WebSocket 连接 -- `../Docs/DevLogs/Day1.md`:SDK 编译与 32 位环境踩坑 -- `../Docs/DevLogs/Day2.md`:UDP 通信、网络库编译、libuwsc / libcurl 准备 -- `../Docs/DevLogs/Day3.md`:音频采集 & 播放模块(ALSA + I2S) -- `../Docs/DevLogs/Day4.md`:模拟麦克风配置 + IMU SPI 驱动与验证 -- `../Docs/DevLogs/Day5.md`:GC2083 摄像头 MPP 集成与 JPEG 捕获 -- `../Docs/DevLogs/Day6.md`:硬件全功能验证、本地测试程序、网络库诊断 -- `../Docs/DevLogs/Day7.md`:交叉编译 Makefile 收敛、工具链配置 -- `../Docs/DevLogs/Day8.md`:整体编译成功、Cedar 库链接完成 -- `../Docs/DevLogs/Day9.md`:⭐ **musl 工具链修复 + 板上测试通过** -- `../Docs/task_complete.md`:完整任务清单与进度条(97% 完成) -- `../Docs/implementation_plan_complete.md`:实现计划 & 各阶段目标拆解 +| 端点 | 用途 | 数据格式 | +|------|------|---------| +| `/ws/camera` | 摄像头上传 | Binary (JPEG) | +| `/ws_audio` | 音频双向 | Binary (PCM16 16kHz) | + +### UDP 连接 + +| 端口 | 用途 | 数据格式 | +|------|------|---------| +| 12345 | IMU 数据 | JSON | + +### 服务器地址 + +```cpp +// main.cpp +#define SERVER_IP "8.148.25.142" // 公网 IP (frp 穿透) +#define SERVER_PORT 8081 +``` --- -## 8. 任务完成度与后续工作 +## 📁 目录结构 -### 8.1 当前完成度(参考任务清单与总结) - -- SDK/工具链/固件:✅ -- musl 工具链修复:✅ **(Day 9 关键突破)** -- 音频采集 & 播放:✅ -- IMU 采集:✅ **(板上测试通过)** -- 摄像头采集:✅ **(板上测试通过)** -- UDP / HTTP / WebSocket 基础:✅(库与客户端实现已完成) -- WiFi 网络配置:✅ **(192.168.110.132)** -- 板端硬件测试:✅ **(所有模块通过)** -- 网络服务器通信测试:⏳(服务器已部署,待测试) -- 性能评估与稳定性验证:⏳(待完成) - -整体项目 **97%** 完成,核心功能全部验证通过!🎉 - -### 8.2 建议的后续 TODO - -- 将服务器 IP / 端口、音频参数、帧率等抽象为配置文件(JSON / INI) -- 丰富错误日志并加上日志轮转 -- 对 WebSocket / HTTP 加入重连与指数退避策略 -- 若后续量产,考虑: - - 用硬件 SPI 替换 GPIO bit‑bang - - 对功耗与休眠策略进行优化 - - 引入简单看门狗机制,防止长期运行卡死 +``` +NaviGlassClient/ +├── avaota_app_demo/ +│ ├── src/ +│ │ ├── audio/ # 音频模块 +│ │ ├── camera/ # 摄像头模块 +│ │ ├── imu/ # IMU 模块 +│ │ ├── network/ # 网络模块 +│ │ ├── main.cpp # 主程序 +│ │ └── Makefile +│ └── build_main.sh +├── Device_Tree/ # DTS 配置 +├── docs/ # 硬件文档 +└── README.md +``` --- -## 9. 如何使用本 README +## 📊 性能参数 -- **新成员上手**:从本 README 入手,结合 `../Docs/DevLogs/DayX.md` 逐步了解每个子系统的设计与坑点。 -- **以后复用到新项目**:可以直接复制「编译流程」「外设接线 + DTS 配置」「主程序多线程架构」这几部分,稍作修改即可移植到其他全志 / RISC‑V 设备。 -- **代码导航入口**:按模块查找 `src/audio`, `src/imu`, `src/camera`, `src/network` 目录,结合对应的 DayX 日志阅读。 +| 指标 | 数值 | +|------|------| +| 视频帧率 | 10 FPS (上传) | +| 音频采样 | 16kHz / 16bit / Mono | +| IMU 采样 | 10 Hz | +| 启动时间 | ~15 秒 (音频系统就绪) | +| 功耗 | 待测 | -祝使用愉快 🎉,也欢迎在后续开发阶段继续补充和更新本 README。 +--- + +## 🔗 相关文档 + +- [服务器代码](../NaviGlassServer/) - Python 后端 +- [开发日志](../Docs/DevLogs/) - Day 1 ~ Day 25 +- [任务清单](../Docs/task_complete.md) +- [Avaota F1 文档](./docs/) + +--- + +## 📄 许可证 + +MIT License