RDK X5 + Waveshare 3.5" SPI LCD 多算法 AI 交互演示(附完整代码)

RDK X5 + Waveshare 3.5" SPI LCD 多算法 AI 交互演示

一、项目概述

本项目在 RDK X5 开发板上,使用 Waveshare 3.5inch RPi LCD (F)(ST7796S 控制器,480×320 分辨率,SPI 接口)实现了一个完整的多算法 AI 交互演示系统。

核心特性:

  • 左侧按钮栏(OpenCV 绘制)+ 右侧 Firefox 全屏显示(TogetheROS Web Display)
  • 4 种 BPU AI 算法一键切换:手部关键点、手势识别、人脸年龄、行人重识别
  • 自动隐藏 XFCE 桌面组件,退出时自动恢复
  • 复用官方 ROS2 pipeline,无需自行编写推理代码

二、整体架构

┌─────────────────────────────────────────────┐
│  Hand Lmk  │                                │
│            │   TogetheROS Web Display       │
│  Hand Gest │   (Firefox Kiosk 模式)         │
│            │   400×320 像素                 │
│  Face Age  │                                │
│            │   相机画面 + AI 渲染结果        │
│  ReID      │                                │
│            │                                │
│  Exit      │                                │
└─────────────────────────────────────────────┘
  80×320          400×320
  OpenCV 按钮栏     Firefox 渲染区

数据流:

USB Camera → ROS2 Pipeline (BPU 推理) → WebSocket (:8000) → Firefox (TogetheROS Web Display)
                                              ↑
                                    ROS2Manager 启动/切换算法
                                              ↑
                                    OpenCV 按钮栏 (触摸切换)

技术栈:

组件 技术 作用
AI 推理 ROS2 + BPU (BPU 加速) 4 种 AI 算法推理
Web 渲染 TogetheROS WebSocket 将推理结果渲染到 Web 页面
显示 Firefox Kiosk 全屏显示 TogetheROS Web Display
按钮栏 OpenCV + X11 左侧 80px 按钮栏,支持触摸
窗口管理 xdotool + xprop 隐藏 XFCE 面板,无边框窗口

三、硬件连接

3.1 SPI LCD 引脚映射

功能 RDK X5 40PIN 设备树 GPIO
SPI SCK Pin 23 SPI1 总线
SPI MOSI Pin 19
SPI MISO Pin 21
SPI CS Pin 26 (CS1) reg = <1>
DC Pin 15 (BCM 22) &ls_gpio0_porta 9
Reset Pin 13 (BCM 27) &ls_gpio0_porta 0
Backlight Pin 12 (BCM 18) &dsp_gpio_porta 10 (sysfs 421)

注意: SPI CS 必须使用 CS1,避免与板载 IMU (BMI088) 冲突。


四、SPI LCD 驱动配置

4.1 编译内核模块

RDK X5 使用 panel-mipi-dbi 驱动,需要编译 4 个内核模块:

# 安装内核头文件
apt install hobot-kernel-headers
ln -sf /usr/src/linux-headers-6 /lib/modules/$(uname -r)/build

# 编译构建脚本
cd /usr/src/linux-headers-6 && make scripts

# 下载源码
BASE_URL="https://raw.githubusercontent.com/D-Robotics/x5-kernel/main"
curl -fsSL -o panel-mipi-dbi.c "$BASE_URL/drivers/gpu/drm/tiny/panel-mipi-dbi.c"
curl -fsSL -o drm_mipi_dbi.c "$BASE_URL/drivers/gpu/drm/drm_mipi_dbi.c"
curl -fsSL -o drm_gem_dma_helper.c "$BASE_URL/drivers/gpu/drm/drm_gem_dma_helper.c"
curl -fsSL -o gpio_backlight.c "$BASE_URL/drivers/video/backlight/gpio_backlight.c"

# 关键补丁:ST7796S 复位时序 (20us → 10ms)
sed -i 's/usleep_range(20, 1000)/usleep_range(10000, 15000)/' drm_mipi_dbi.c

# 编译
cat > Makefile << 'EOF'
KDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
obj-m += drm_mipi_dbi.o drm_gem_dma_helper.o panel-mipi-dbi.o
all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules
EOF
make -j$(nproc)

# 编译 gpio_backlight
cat > Makefile << 'EOF'
KDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
obj-m += gpio_backlight.o
all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules
EOF
make -j$(nproc)

# 安装
KDIR=/lib/modules/$(uname -r)/kernel/drivers/gpu/drm
mkdir -p $KDIR/tiny
cp drm_mipi_dbi.ko drm_gem_dma_helper.ko $KDIR/
cp panel-mipi-dbi.ko $KDIR/tiny/
cp gpio_backlight.ko /lib/modules/$(uname -r)/kernel/drivers/video/backlight/
depmod -a

4.2 设备树 Overlay

LCD Overlay (overlay-st7796s.dts):

/dts-v1/;
/plugin/;

/ {
    fragment@0 {
        target-path = "/";
        __overlay__ {
            backlight: backlight {
                compatible = "gpio-backlight";
                gpios = <&dsp_gpio_porta 10 0>;
                default-on;
            };
        };
    };

    fragment@1 {
        target-path = "/soc/a55_apb0/spi@34010000";
        __overlay__ {
            #address-cells = <1>;
            #size-cells = <0>;

            spidev@1 { status = "disabled"; };
            bmi08a@1 { status = "disabled"; };

            panel-mipi-dbi@1 {
                compatible = "panel-mipi-dbi-spi";
                reg = <1>;
                spi-max-frequency = <40000000>;
                dc-gpios = <&ls_gpio0_porta 9 0>;
                reset-gpios = <&ls_gpio0_porta 0 0>;
                backlight = <&backlight>;
                write-only;

                width-mm = <85>;
                height-mm = <53>;

                panel-timing {
                    clock-frequency = <0>;
                    hactive = <480>;
                    vactive = <320>;
                    hfront-porch = <0>;
                    hsync-len = <0>;
                    hback-porch = <0>;
                    vfront-porch = <0>;
                    vsync-len = <0>;
                    vback-porch = <0>;
                };
            };
        };
    };
};

4.3 生成 ST7796S 初始化固件

#!/usr/bin/env python3
import struct

MAGIC = b"MIPI DBI\x00\x00\x00\x00\x00\x00\x00"
VERSION = 1

def build_commands():
    cmds = bytearray()
    def add_cmd(cmd, *params):
        cmds.append(cmd); cmds.append(len(params)); cmds.extend(params)
    def add_delay(ms):
        cmds.append(0x00); cmds.append(0x01); cmds.append(ms & 0xFF)

    add_cmd(0x01); add_delay(120)       # Software Reset
    add_cmd(0x11); add_delay(120)       # Sleep Out
    add_cmd(0x3A, 0x55)                 # 16bit/pixel (RGB565)
    add_cmd(0xB6, 0x80, 0x02, 0x3B)    # Display Function Control
    add_cmd(0xB7, 0xC6)                 # Entry Mode Set
    add_cmd(0xC5, 0xA0)                 # Display Output Ctrl Adjust
    add_cmd(0xD0, 0xA7, 0x41, 0x1D)    # Power Control 1
    add_cmd(0xE0, 0xF0, 0x09, 0x0B, 0x06, 0x04, 0x15, 0x2F,
            0x54, 0x42, 0x3C, 0x17, 0x14, 0x18, 0x1B)  # Positive Gamma
    add_cmd(0xE1, 0xE0, 0x09, 0x0B, 0x06, 0x04, 0x03, 0x2B,
            0x43, 0x42, 0x3B, 0x16, 0x14, 0x17, 0x1B)  # Negative Gamma
    add_cmd(0x21)                       # Display Inversion On
    add_delay(120)
    add_cmd(0x36, 0x28)                 # MADCTL: landscape (480x320)
    add_cmd(0x29)                       # Display ON
    add_delay(120)
    return bytes(cmds)

header = MAGIC + struct.pack("B", VERSION)
commands = build_commands()
with open("panel-mipi-dbi-spi.bin", "wb") as f:
    f.write(header + commands)
print(f"Generated: {len(header) + len(commands)} bytes")

4.4 部署配置

# 编译 overlay
dtc -@ -I dts -O dtb -o overlay-st7796s.dtbo overlay-st7796s.dts

# 安装
cp overlay-st7796s.dtbo /boot/overlays/
cp panel-mipi-dbi-spi.bin /lib/firmware/

# 配置加载
cat > /boot/config.txt << 'EOF'
dtoverlay=overlay-st7796s

EOF
# 注意末尾必须有空行!

# 模块自动加载
cat > /etc/modules-load.d/mipi-dbi-lcd.conf << 'EOF'
drm_gem_dma_helper
drm_mipi_dbi
gpio_backlight
panel-mipi-dbi
EOF

# 重启
reboot

五、AI Demo 应用

5.1 支持的 4 种算法

按钮 算法 ROS2 Launch 输出话题
Hand Lmk 手部关键点检测 hand_lmk_detection.launch.py /hobot_hand_lmk_detection
Hand Gest 手势识别 hand_gesture_fusion.launch.py /hobot_hand_dynamic_gesture_detection
Face Age 人脸年龄检测 body_det_face_age_det.launch.py /hobot_face_age_detection
ReID 行人重识别 reid.launch.py /perception/detection/reid

5.2 安装

# 下载附件 rdk_x5_ai_demo.zip 并解压
unzip rdk_x5_ai_demo.zip -d rdk_x5_ai_demo
cd rdk_x5_ai_demo

# 一键安装
sudo bash install.sh

或手动安装:

mkdir -p /app/ai_demo_web
cp ai_demo_browser.py /app/ai_demo_web/
cp start_ros2.sh /app/ai_demo_web/
chmod +x /app/ai_demo_web/start_ros2.sh
cp ai-demo.desktop /home/sunrise/Desktop/
chmod +x /home/sunrise/Desktop/ai-demo.desktop

5.3 使用方法

# 方式1:双击桌面 "AI Demo (ROS2)" 图标
# 方式2:命令行启动
su - sunrise -c 'export DISPLAY=:0 && bash /app/ai_demo_web/start_ros2.sh'

操作说明:

  • 触摸左侧按钮切换算法
  • 右侧 Firefox 自动显示 TogetheROS Web Display(相机画面 + AI 渲染结果)
  • 点击 Exit 按钮退出,自动恢复 XFCE 桌面

六、核心代码说明

6.1 主程序 (ai_demo_browser.py)

核心组件:

  1. ROS2Manager - 管理 ROS2 pipeline 生命周期

    • switch(algo_id) - 切换算法(先 stop 再启动新的 ros2 launch)
    • _wait_for_web() - 等待 TogetheROS Web 服务就绪
    • _launch_browser() - 启动 Firefox Kiosk 并用 xdotool 调整窗口
  2. AIDemo - OpenCV 窗口管理

    • 左侧 80×320 按钮栏(cv2.WINDOW_GUI_NORMAL 无边框)
    • 使用 xprop 设置为 DOCK 窗口类型(无边框但仍可接收鼠标事件)
    • 触摸切换算法后自动置顶按钮栏
  3. XFCE 桌面管理

    • 启动时用 xdotool 将 xfce4-panel 和 xfdesktop 移到屏幕外
    • 退出时自动恢复

6.2 窗口管理关键技巧

# 1. 设置窗口为 DOCK 类型(无边框但可接收鼠标)
subprocess.run(["xprop", "-id", wid, "-f", "_NET_WM_WINDOW_TYPE", "32a",
              "-set", "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_DOCK"])

# 2. 移除 MOTIF 装饰
subprocess.run(["xprop", "-id", wid, "-f", "_MOTIF_WM_HINTS", "32i",
              "-set", "_MOTIF_WM_HINTS", "2, 0, 0, 0, 0"])

# 3. 置顶 + 跳过任务栏
subprocess.run(["xprop", "-id", wid, "-f", "_NET_WM_STATE", "32a",
              "-set", "_NET_WM_STATE",
              "_NET_WM_STATE_ABOVE,_NET_WM_STATE_SKIP_TASKBAR,_NET_WM_STATE_SKIP_PAGER"])

七、常见问题

Q1: SPI LCD 不显示

  • 检查内核模块是否加载:lsmod | grep panel
  • 检查 DRM 设备:ls /dev/dri/
  • 检查 overlay 是否生效:cat /sys/class/drm/card0-SPI-1/status

Q2: mono2d_body_detection 崩溃 (segfault)

  • 原因:模型版本与 BPU SDK 不匹配
  • 解决:使用默认 model_type=0,不要指定 kps_model_type:=1

Q3: 按钮无法点击

  • 原因:窗口类型为 SPLASH 时不接收鼠标事件
  • 解决:使用 DOCK 窗口类型

Q4: Firefox 窗口位置不对

  • 使用 xdotool 强制调整(代码中已实现两次调整确保稳定)

Q5: XFCE 面板遮挡

  • 启动脚本会自动隐藏 xfce4-panel 和 xfdesktop
  • 退出时自动恢复

八、参考资料

九、附件下载

:package: rdk_x5_ai_demo.zip - 包含所有代码文件 + 一键安装脚本

包内文件:

rdk_x5_ai_demo/
├── ai_demo_browser.py    # 主程序 (531 行)
├── start_ros2.sh         # 启动脚本
├── ai-demo.desktop       # 桌面快捷方式
└── install.sh            # 一键安装脚本