9浏览
查看: 9|回复: 1

[ESP8266/ESP32] 基于 ESP32-S31-Korvo 与 C4002 毫米波传感器的离席/久坐提...

[复制链接]

1. 项目背景


久坐提醒是健康类嵌入式应用中一个很典型的场景。传统方案通常依赖按键、压力传感器、摄像头或 BLE 设备判断用户是否在座,但这些方案要么需要额外结构设计,要么涉及隐私问题。


本项目尝试使用 DFRobot C4002 毫米波人体存在传感器,结合 ESP32-S31-Korvo 开发板,实现一个适合书房、办公室场景的离席/久坐提醒器。


工程目标包括:


  • 通过 USB-TTL 转接器读取 C4002 数据;
  • 判断人体是否处于座位区域;
  • 在 LCD 屏幕显示当前状态、目标距离、久坐时间和倒计时;
  • 久坐超过阈值后点亮板载 RGB LED;
  • 支持离席重置和久坐时间统计。



项目仓库结构基于 ESP-IDF 工程组织,目标芯片为 esp32s31


2. 硬件环境


使用的主要硬件如下:


  • ESP32-S31-Korvo 开发板;
  • DFRobot C4002 毫米波人体存在传感器;
  • USB-TTL 转接器,例如 CH340/CH34x;
  • ESP32-S31-Korvo 板载 800x480 RGB LCD;
  • ESP32-S31-Korvo 板载 WS2812 RGB LED。



C4002 通过 USB-TTL 转接器连接到 ESP32-S31 的 USB Host 接口。这个连接方式先通过 ESP-IDF 官方 CDC Host 示例验证过,可正常识别 CH340 设备并读取串口数据。


之所以采用 USB-TTL 转接器,而不是直接使用普通 UART GPIO,是因为 ESP32-S31-Korvo 开发板的大量 I/O 已经分配给 RGB LCD、音频、按键、摄像头、SD 卡等板载外设,开发板没有额外引出足够方便使用的空闲 I/O 接口来连接 C4002。相比重新飞线或改动板载外设,使用 USB Host 接 USB-TTL 转接器更稳定,也更适合做可复现的开发板示例。


构建目标设置为:


  1. idf.py --preview set-target esp32s31
复制代码



因为当前使用的 ESP-IDF 分支中,esp32s31 仍属于 preview target,所以后续 idf.py 命令也需要带 --preview


3. USB CDC Host 接入 C4002


C4002 模块本质上通过 UART 输出数据。由于开发板侧使用 USB Host,因此采用 USB-TTL 转接器接入。


工程依赖以下 USB VCP/CDC 组件:


  1. dependencies:
  2.   usb_host_cdc_acm: "^2.3"
  3.   usb_host_ch34x_vcp: "^2.2"
  4.   usb_host_cp210x_vcp: "^2.2"
  5.   usb_host_ftdi_vcp: "^2.1"
复制代码



程序启动后会安装 USB Host 和 CDC ACM Host 驱动,并监听新设备连接:


  1. const cdc_acm_host_driver_config_t driver_config = {
  2.     .driver_task_stack_size = 4096,
  3.     .driver_task_priority = USB_HOST_PRIORITY + 1,
  4.     .xCoreID = 0,
  5.     .new_dev_cb = new_dev_cb,
  6. };
  7. cdc_acm_host_install(&driver_config);
复制代码



当 CH340 转接器插入后,日志类似:


  1. USB CDC connected VID=0x1A86 PID=0x7523
  2. CDC device opened at 115200 8N1
复制代码



C4002 默认波特率为 115200,使用 8N1。


4. C4002 数据帧解析


开发初期先按 ASCII 文本方式兼容解析,例如:


  1. state=presence,presence_dist=1.20
  2. state=motion,motion_speed=0.34
  3. state=none
复制代码



但实际测试中发现,C4002 通过当前配置输出的是二进制帧。抓到的数据帧以如下头部开始:


  1. FA F5 AA A5
复制代码



根据日志分析,帧格式大致为:


  • FA F5 AA A5:帧头;
  • 后 2 字节:小端整帧长度;
  • 最后 2 字节:前面所有字节的加和校验;
  • 偏移 12:目标状态;
  • 偏移 24、25:目标距离,单位厘米,小端格式。



状态字段当前按如下方式解释:


  1. 0:无目标
  2. 1:静止存在
  3. 2:运动
复制代码



解析代码中会校验帧头、长度和 checksum。距离字段解析后转换为米,用于 LCD 和日志显示。


5. 为什么必须结合距离判断


最开始只根据 C4002 的 Static PresenceMotion 状态判断用户是否久坐。测试后发现,这样会有一个明显问题:


用户离开座位但仍在房间内,C4002 仍可能检测到人体存在。此时传感器状态仍是 Static PresenceMotion,单纯依赖状态无法判断“在座”还是“离开座位”。


因此后续加入距离判断:


  1. 默认座位有效距离:30cm ~ 100cm
复制代码



只有当目标距离在这个范围内时,才认为用户处于座位区域:


  1. sample->in_seat_zone = distance_cm >= CONFIG_C4002_SEAT_MIN_DISTANCE_CM &&
  2.                        distance_cm <= CONFIG_C4002_SEAT_MAX_DISTANCE_CM;
复制代码



当距离超过 1m,例如日志中的:


  1. target_dist=1.50m
  2. seated=no
复制代码



即使状态仍为 Static Presence,也不再累计久坐时间。


6. 久坐计时逻辑的迭代


这个项目中最容易出错的是计时逻辑。


早期逻辑中,进入 session 后使用:


  1. static_s = now - static_start_us;
复制代码



这会导致一个问题:如果用户短暂离开座位区域,但还没有达到 away reset 时间,程序虽然显示 seated=no,但内部提醒判断仍可能继续按 wall-clock 时间增长。


例如:


  1. static=7s
  2. target_dist=1.56m
  3. seated=no
  4. ...
  5. REMINDER | Static presence for 15s
复制代码



这明显不符合预期,因为用户已经离开座位区域,倒计时应该暂停。


最终修正为“实际在座累计时间”模型:


  1. int64_t seated_interval_start_us;
  2. int64_t seated_accumulated_us;
复制代码



逻辑如下:


  • seated=yes 时开始或继续累计;
  • seated=no 时暂停累计;
  • 重新回到座位区域后继续累计;
  • 超过 away reset 时间后重置 session;
  • 久坐提醒只在 in_seat_zone=true 时触发。



这样就能实现:


  1. 0.96m 内累计到 7 秒
  2. 离开到 1.56m 后倒计时暂停
  3. 回到 1m 内后从 7 秒继续
  4. 累计到 15 秒才提醒
复制代码



7. 板载 RGB LED 控制问题


开发中遇到过一个典型硬件映射问题。


一开始根据资料误以为板载可寻址 RGB LED 在 GPIO8,但实际烧录后 LED 没有反应。后续查看 ESP32-S31-Korvo 出厂 demo 的 BSP,发现:


  1. #define BSP_LED_WS2812 GPIO_NUM_37
复制代码



而 GPIO8 是 LCD 的 RGB 数据线:


  1. #define BSP_LCD_DATA0 GPIO_NUM_8
复制代码



所以正确的 WS2812 引脚是 GPIO37。


出厂 demo 使用 led_strip 组件和 RMT 驱动 WS2812,颜色格式为 GRB。当前工程中采用 RMT 自定义 encoder 控制板载灯:


  • 上电短暂红灯自检;
  • 久坐提醒触发后点亮红灯;
  • 离座 reset 后熄灭红灯。



8. LCD 显示实现


ESP32-S31-Korvo 带有 800x480 RGB LCD。出厂 demo 中 LCD 参数如下:


  1. 分辨率:800 x 480
  2. 颜色格式:RGB565
  3. 数据宽度:16-bit RGB
  4. PCLK:26 MHz
复制代码



关键 GPIO:


  1. DATA0  GPIO8
  2. DATA1  GPIO9
  3. ...
  4. DATA15 GPIO36
  5. PCLK   GPIO40
  6. DE     GPIO43
  7. HSYNC  GPIO44
  8. VSYNC  GPIO45
复制代码



最开始尝试直接引入完整出厂 BSP,但它会连带引入 Camera、Video、Audio、SD 等依赖,其中 esp_video 在当前环境下编译遇到 sys/socket.h 缺失问题。


因此最终采用“最小 LCD 初始化”方案:


  • 只移植 RGB LCD GPIO 和时序参数;
  • 使用 esp_lcd_new_rgb_panel() 初始化 RGB panel;
  • 使用 esp_lvgl_adapter 注册到 LVGL;
  • 不引入完整 BSP。



LCD 初始化核心代码类似:


  1. esp_lcd_rgb_panel_config_t panel_config = {
  2.     .timings = {
  3.         .pclk_hz = 26 * 1000 * 1000,
  4.         .h_res = 800,
  5.         .v_res = 480,
  6.         .hsync_pulse_width = 1,
  7.         .hsync_back_porch = 40,
  8.         .hsync_front_porch = 20,
  9.         .vsync_pulse_width = 1,
  10.         .vsync_back_porch = 10,
  11.         .vsync_front_porch = 5,
  12.         .flags.pclk_active_neg = true,
  13.     },
  14.     .data_width = 16,
  15.     .in_color_format = LCD_COLOR_FMT_RGB565,
  16.     .flags.fb_in_psram = true,
  17. };
复制代码



9. PSRAM 配置问题


启用 LCD 后第一次运行遇到:


  1. lcd_rgb_panel_alloc_frame_buffers: no mem for frame buffer
  2. esp_lcd_new_rgb_panel: alloc frame buffers failed
复制代码



原因是 LCD 帧缓冲太大。800x480 RGB565 单帧约 750KB,内部 RAM 无法承载,必须启用 PSRAM。


出厂 demo 中也开启了 PSRAM:


  1. CONFIG_SPIRAM=y
  2. CONFIG_SPIRAM_SPEED_250M=y
  3. CONFIG_SPIRAM_XIP_FROM_PSRAM=y
复制代码



启用后启动日志中可以看到:


  1. esp_psram: Found 16MB PSRAM device
  2. esp_psram: Speed: 250MHz
  3. esp_psram: Adding pool of 15680K of PSRAM memory
复制代码



LCD 初始化也正常:


  1. RGB LCD registered to LVGL adapter
  2. LCD UI initialized
复制代码



10. LCD 界面内容


LCD 界面主要面向调试和实际使用,显示内容包括:


  • 状态图标;
  • 当前状态;
  • 是否在座;
  • 目标距离;
  • 久坐提醒倒计时;
  • 当前静止在座时间;
  • 当前 session 时间;
  • 总静止在座统计时间。



状态图标设计为简单字符:


  1. ?:未知
  2. O:离座或无目标
  3. S:在座
  4. M:运动
  5. !:久坐提醒
复制代码


基于 ESP32-S31-Korvo 与 C4002 毫米波传感器的离席/久坐提...图1
倒计时逻辑需要特别注意:


  • 在座时倒计时减少;
  • 离开座位区域时倒计时暂停;
  • 回到座位区域后继续;
  • 达到阈值后显示提醒状态。


基于 ESP32-S31-Korvo 与 C4002 毫米波传感器的离席/久坐提...图2
11. 当前默认配置


当前工程默认配置如下:


  1. 久坐提醒阈值:15 秒
  2. 重复提醒间隔:300 秒
  3. 离座重置时间:10 秒
  4. 座位有效距离:30cm ~ 100cm
  5. LCD 显示:开启
  6. 板载 RGB LED:GPIO37
复制代码



配置文件主要包括:


  1. sdkconfig.defaults
  2. main/Kconfig.projbuild
  3. main/idf_component.yml
复制代码



建议将 sdkconfig.defaults 上传仓库,便于其他开发者复现关键配置。


12. 构建与烧录


代码仓库地址:


  1. https://gitee.com/zealsoft/c4002_sedentary_reminder
复制代码



构建命令:


  1. cd D:\esp\master\esp-idf\projects\c4002_sedentary_reminder
  2. idf.py --preview set-target esp32s31
  3. idf.py --preview build
  4. idf.py --preview flash monitor
复制代码



13. 仓库上传建议


建议上传:


  1. CMakeLists.txt
  2. README.md
  3. README_zh.md
  4. sdkconfig.defaults
  5. dependencies.lock
  6. main/
  7. .gitignore
复制代码



建议忽略:


  1. build/
  2. managed_components/
复制代码



managed_components 是 ESP-IDF Component Manager 自动下载的依赖,不需要上传。build 是构建产物,也不应上传。


如果希望完全复现当前开发环境,也可以上传 sdkconfig。但更通用的做法是上传 sdkconfig.defaults,让用户通过 idf.py set-target 和默认配置生成自己的 sdkconfig


14. 总结


这个项目看起来只是一个“久坐提醒器”,但实际开发中涉及了不少嵌入式工程细节:


  • USB Host CDC 设备枚举;
  • C4002 二进制帧解析;
  • 毫米波存在状态与距离联合判断;
  • 防止房间内其他位置误判为在座;
  • WS2812 引脚与 LCD 引脚冲突排查;
  • ESP32-S31-Korvo RGB LCD 初始化;
  • LVGL adapter 接入;
  • PSRAM 帧缓冲配置;
  • 久坐计时逻辑从 wall-clock 改为实际在座累计。



最终实现的效果是:系统能够通过 C4002 判断用户是否处于座位区域,在 LCD 上显示状态和倒计时,并在实际久坐达到阈值后点亮红灯提醒用户起身活动。


神一样的老师  初级技师
 楼主|

发表于 9 分钟前

演示视频发到B站了:https://www.bilibili.com/video/BV1D2Ex6rEtQ/
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2026 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail