Files
Loongson_2k0300_SmartCar/README.md
T

257 lines
9.3 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.
# SmartCar Demo — 使用手册 & 踩坑记录
## 项目概述
龙芯 2K0300 智能车卖家 Demo,简易架构:`sysfs` 直接控制 GPIO/PWM + mmap 读编码器 + OpenCV 巡线。
**赛道**:蓝底黄线边界,灰度路面
**驱动**:前轮舵机转向 + 后轮双电机差速辅助
---
## 硬件信息
| 部件 | 型号/规格 | 说明 |
|------|----------|------|
| 主控 | 龙芯 2K0300 (LA264, 1.2GHz) | LoongArch64 |
| 摄像头 | USB UVC | 320×240 MJPG, `/dev/video0` |
| 显示器 | SPI LCD | `/dev/fb0`, RGB565, 160×128 (实际) |
| 舵机 | 标准 PWM 舵机 | pwmchip1/pwm0, 3ms 周期, 1.52ms 中位 |
| 电机驱动 | DRV8701E (双路) | pwmchip8/pwm1→右, pwmchip8/pwm2→左 |
| 编码器 | 硬件脉冲计数 | `/dev/mem` mmap 基址 `0x1611B000` |
| IMU | JY62 六轴陀螺仪 | `/dev/ttyS1`, 115200bps |
| ToF 测距 | VL53L0X | `/dev/stmvl53l0x_ranging` |
| 音箱 | wonderEcho | I2C-2, 地址 0x6E (有应答, 无驱动) |
### 关键引脚映射
| 功能 | GPIO / PWM | 备注 |
|------|-----------|------|
| 电机使能 | GPIO73 | 高有效, 1=启动, 0=紧急制动 |
| 左电机 IN1 (正转) | GPIO12 + pwmchip8/pwm2 | DRV8701 IN/IN 模式 |
| 左电机 IN2 (反转) | GPIO13 | **必须锁 0** |
| 右电机 PWM | pwmchip8/pwm1 | 方向脚 GPIO67 是哑脚 |
| 左编码器 | 通道0 + GPIO75 | 方向检测 |
| 右编码器 | 通道3 + GPIO72 | 方向检测, 极性 -1 |
| 舵机 | pwmchip1/pwm0 | 3ms, 1.31~1.73ms (±7 刻度) |
---
## 构建环境
### 交叉编译工具链
```
路径: /opt/loongson-gnu-toolchain-8.3-x86_64-loongarch64-linux-gnu-rc1.6
编译器: loongarch64-linux-gnu-g++ (GCC 8.3)
架构: -march=loongarch64
```
### OpenCV
```
路径: /home/ilikara/loongson/opencv-4.11.0/loongson
版本: 4.11.0 (必须匹配设备上的 libopencv)
```
### 编译
```bash
cd smartcar1
mkdir -p build && cd build
cmake .. # CROSS_COMPILE=1 在 cross.cmake 中设置
make -j$(nproc)
```
产物: `build/main/smartcar_demo` (约 90KB)
**Windows 上不可编译!** 必须在 Linux 下用交叉工具链。可在 WSL Ubuntu 中用 `g++ -std=c++17 -fsyntax-only` 做部分语法检查。
---
## 部署与启动
### 板端目录结构
```
/home/root/smartcar/
├── smartcar_demo # 主程序
├── ctl.sh # 启停脚本
├── gpio_fix_final.so # GPIO74→73 重定向 (LD_PRELOAD)
├── start.sh # 推荐启动脚本 (已内置 LD_PRELOAD)
├── showImg # LCD 预览开关
├── start # 车控启停
├── speed # 目标速度 (占空比)
├── deadband # 舵机死区
├── steer_gain # 转向增益
├── kp / ki / kd # 舵机 PID
├── mortor_kp / mortor_ki / mortor_kd # 电机 PID
└── foresee # 前瞻行号
```
### 推荐启动
```bash
# 方式 1: 使用包装脚本 (已固化 LD_PRELOAD)
sh /home/root/smartcar/start.sh
# 方式 2: 手动
LD_PRELOAD=/home/root/smartcar/gpio_fix_final.so /home/root/smartcar/smartcar_demo
```
---
## 运行时参数热调
**无需重新编译**,直接 `echo` 写文件即可实时生效:
```bash
echo 11 > /home/root/smartcar/speed # 目标占空比 (0~100)
echo 8 > /home/root/smartcar/deadband # 舵机死区 (像素)
echo 1.5 > /home/root/smartcar/steer_gain # 转向增益
echo 3.5 > /home/root/smartcar/kp # 舵机 P
echo 0.3 > /home/root/smartcar/ki # 舵机 I
echo 2.0 > /home/root/smartcar/kd # 舵机 D
echo 40 > /home/root/smartcar/foresee # 前瞻行 (0~120, 越大看越远)
echo 1 > /home/root/smartcar/showImg # 1=LCD 预览, 0=关闭
echo 1 > /home/root/smartcar/start # 1=启动, 0=停止
echo 1 > /home/root/smartcar/saveImg # 保存当前帧到 ./image/
```
---
## 踩坑记录 (关键!)
### 1. GPIO74 与 LCD 驱动冲突 — 程序无法启动
**现象**: `std::runtime_error: Failed to open GPIO value file`
**原因**: Demo 二进制硬编码 GPIO_EN=74, 但 GPIO74 被 LCD 驱动 `fb_st7735r` 占用 (内核级, 无法释放)。
**解决**: 编译 `gpio_fix_final.so`, 用 LD_PRELOAD 劫持 `open()` 系统调用, 将对 gpio74 的访问重定向到 gpio73。启动时必须带 `LD_PRELOAD`
**源代码修复**: `control.cpp``GPIO mortorEN(73)` — 如果从源码编译, 直接改成 GPIO73, 无需 LD_PRELOAD。
### 2. 右电机方向硬件锁死 — 差速失效
**现象**: 右轮只能单向旋转, 代码写 GPIO67 无效。
**原因**: DRV8701 的右路方向脚 (原本应对应某个 GPIO) 在 PCB 上直接拉高/拉低了。代码中的 GPIO67 是哑脚, 实际不控制任何硬件。
**解决**: 物理剪线交换右电机电源线 (M+/M- 对调), 代码中 GPIO67 作为占位符不动。这样一来, 代码输出正占空比时电机实际反向。
### 3. GPIO13 实测映射 — 文档与实物不符
**文档称**: GPIO12=左IN1, GPIO13=右IN1。
**实测**: GPIO13 控制的是**左电机 IN2 (反转)**, 不是右电机方向!
**影响**: 若 GPIO13=1, 左电机 IN1=1 IN2=1 → 制动状态, 左轮抱死。
**解决**: 代码中显式 `leftIn2.setValue(0)` 把 GPIO13 锁 0, 确保左电机只有正转 (IN1=1, IN2=0)。
### 4. 摄像头分辨率不稳定
**现象**: 摄像头偶尔返回 640×480 而非 320×240。
**原因**: 某些 UVC 摄像头不响应 `CAP_PROP_FRAME_WIDTH/HEIGHT` 设置, 按默认格式输出。
**解决**:
```cpp
cap.open(0, cv::CAP_V4L2); // 强制 V4L2 后端
cap.set(cv::CAP_PROP_FRAME_WIDTH, 320); // 设宽
cap.set(cv::CAP_PROP_FRAME_HEIGHT, 240); // 设高
cap.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M','J','P','G')); // MJPG
```
即使摄像头不遵从, `resize()` 也能在软件层统一到 80×60。
### 5. 编码器必须 root 权限
**现象**: `ENCODER` 构造失败, mmap 报错。
**原因**: 编码器通过 `/dev/mem` 直接映射 PWM 硬件寄存器 (物理地址 `0x1611B000`), 需要 root。
**解决**: 必须以 root 运行程序。`sudo` 或直接以 root 登录。
### 6. IMU 端口纠正
**文档称**: IMU 在 `/dev/ttyS2`
**实测**: IMU 在 `/dev/ttyS1` (115200bps)。
### 7. 网络热插拔导致断连
**现象**: 拔掉网线再插上, SSH 连不上。
**原因**: `/etc/network/interfaces` 中静态 eth0 配置与 connman 冲突。
**解决**: 删除 `/etc/network/interfaces` 中的 eth0 段, 让 connman 全权管理有线网络。修改后即使先开机后插网线也能自动获取 IP。
### 8. GCC 14.2.0 工具链 ABI 不兼容
**现象**: 用新版 GCC 14.2.0 (当前 WSL 环境) 编译的程序在设备上运行报 `GLIBCXX_3.4.30 not found`
**原因**: GCC 14.2.0 的 libstdc++ ABI 与设备上的 glibc 2.28 / libstdc++ 6.0.25 不兼容。
**解决**:
- **必须使用原始 GCC 8.3 rc1.6 工具链**。路径: `/opt/loongson-gnu-toolchain-8.3-x86_64-loongarch64-linux-gnu-rc1.6`
- 可用 C 编译器 (`gcc` 而非 `g++`) + 显式 `-march=la64v1.0` + 指定 `-Wl,-dynamic-linker=...` 编译纯 C 程序
### 9. 视觉管线分辨率选择
**Demo 内部处理**: 摄像头 320×240 → 缩放至显示分辨率 (160×120) → 再除以 `calc_scale=2` → 最终 **80×60** 做 HSV 二值化 + 洪泛填充 + 搜线。
**关键**: 80×60 是最优平衡点——再大 Otsu 不稳, 再小细节丢失。
### 10. 启动顺序 & 竞态
- GPIO 必须先 export + 设方向, 再启动程序
- 舵机 PWM 必须先设 period + enable, 才能写 duty_cycle
- 程序需要几秒初始化 IMU (校准 200 样本 × 5ms = 1 秒)
### 11. PWM 频率
| PWM | 频率 | 周期 | 用途 |
|-----|------|------|------|
| pwmchip8/pwm1,2 | 20kHz | 50000ns | 电机驱动 (DRV8701 需 ≥ 20kHz) |
| pwmchip1/pwm0 | 333Hz | 3000000ns | 舵机 (标准 3ms 周期) |
### 12. 算力实测 (2K0300 CPU)
| 精度 | 算力 | 备注 |
|------|------|------|
| FP32 | 0.43 GFLOPS | 无 SIMD, 纯标量 |
| INT8 | 0.44 GOPS | 几乎无加速, 与 FP32 持平 |
| INT4 | 0.24 GOPS | 比 INT8 更慢 (位操作开销) |
**结论**: 2K0300 没有 SIMD/NPU, 纯 CPU 推理极弱。模型需 ≤15M MACs 才能跑 30+ FPS。只适合微型 CNN (2-3 层, 32×32 输入, 8-16 通道) 做简单分类。
---
## Demo 程序列表
| Demo | 功能 |
|------|------|
| `main/` | **完整自动驾驶巡线** — CameraTimer + MortorTimer + 文件热调 |
| `demo1/` | 键盘 WASD 遥控 — 非阻塞终端 |
| `image_test/` | 离线图像处理调试器 — 方向键翻页, 7 种显示模式 |
| `udp_receive/` | UDP 遥控 (端口 8888) + Python 滑块 GUI |
| `encoder_demo/` | 编码器原始读数测试 |
| `jy62_demo/` | JY62 IMU 六轴数据读取 |
| `key_demo/` | 9 键 GPIO 状态面板 |
| `wonderEcho_demo/` | I2C smbus 读写实验 |
| `opencv_demo1/` | USB 摄像头 → framebuffer 直显 + FPS |
| `opencv_demo2/` | 3D 旋转立方体软件渲染 |
| `opencv_demo3/` | Haar 级联人脸检测 |
| `framebuffer_demo/` | 纯软件 8×8 字体 + 几何绘图 |
| `vl53l0x_test/` | VL53L0X 测距传感器 (ST 官方) |
---
## 文件说明
| 文件 | 用途 |
|------|------|
| `CMakeLists.txt` | 构建配置: `src/` → 静态库, 各 demo 独立链接 |
| `cross.cmake` | 交叉工具链切换 (`CROSS_COMPILE=1`) |
| `lib/` | 头文件: GPIO, PWM, PID, Motor, Encoder, Camera, Timer, serial 等 |
| `src/` | 实现文件: 每个 `.cpp` → 编译进 `libcommon_lib.a` |