Files
Loongson_2k0300_SmartCar/README.md
T

9.3 KiB
Raw Blame History

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)

编译

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               # 前瞻行号

推荐启动

# 方式 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 写文件即可实时生效:

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.cppGPIO 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 设置, 按默认格式输出。

解决:

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