Skip to content

第9周个人作业 2:为 XIAO 扩展板添加手势传感器

项目介绍

本周个人项目的主要目标是:向你设计的微控制器板添加传感器并读取数据。因为我最终项目"智幻走马灯"的创意,需要用到手势控制,如下图所示。

在我的最终项目"智幻走马灯"中,手势控制系统将作为主要的用户交互界面,实现以下控制功能:

  1. 左右手势: 控制走马灯的旋转方向(顺时针/逆时针)
  2. 上下手势: 调节灯光亮度(增加/减少)

所以我在淘宝搜索了一些手势传感器,找到一个觉得可以尝试的传感器:超mini手势传感器感应运动方向RGB颜色识别模块Arduino树莓派

淘宝新地科技的店铺提供一个超 mini 的手势传感器,价格是 29.9 元RMB

于是我购买了 3 只回来,一方面作为第 9 周个人作业的一部分,一方面也想尝试看看是否可以用于我的最终项目。

所以本周作业我先列出了几个具体目标包括:

  1. 理解手势传感器的工作原理
  2. 设计传感器电路并与XIAO ESP32C3进行连接
  3. 编写程序测试手势识别功能
  4. 记录整个设计、制造和测试过程
  5. 展示输入设备的工作原理及其在最终项目中的应用场景

理解手势传感器的工作原理

我购买的"超mini手势传感器"产品,新地科技(或XLOT品牌)将 APDS-9960 芯片进行了适当的模块化,便于与各种微控制器(如 XIAO 开发版)进行简单的集成。下图左侧是购得的传感器,店家还送了各种连接线材,右侧是我目前做好的开发板。

XLOT APDS-9960 模块(左侧)与我的 XIAO 开发板对比

下面将重点研究 APDS-9960 手势传感器,这是一款由 Broadcom 设计和制造的多功能集成传感器。该传感器被新地科技(XLOT)采用并封装为便于DIY电子爱好者使用的模块。

淘宝的供应商的文档比较简陋,只有图片的简单说明

APDS-9960 简介

模块上的 APDS-9960 传感器

APDS-9960 是一款集手势检测、接近感应、环境光传感和RGB颜色传感于一体的多功能传感器。我在其官方网站找到了 APDS-9960 传感器的 Data Sheet:其特点包括:

  • 手势检测:可识别上下左右四个方向的手势
  • 接近检测:能测量物体与传感器的距离
  • 环境光和RGB颜色传感:能测量环境光强度和RGB颜色成分
  • I2C通信接口:标准I2C接口,兼容3.3V和5V逻辑电平
  • 集成IR LED:内置红外LED光源,用于手势和接近检测

物理结构

APDS-9960传感器具有紧凑的封装尺寸(约3.94mm×2.36mm×1.35mm),包含以下核心组件:

  1. 红外LED发光源:发射940nm波长的红外光
  2. 四个方向光电二极管:分别探测上、下、左、右四个方向反射的红外光
  3. 滤光片:包含紫外线和红外线过滤器,提高色彩感应的准确性
  4. 集成LED驱动电路:控制IR LED的脉冲宽度和电流强度

APDS-9960 传感器的 Data Sheet 中的功能框图

工作原理

手势检测原理

APDS-9960的手势检测功能基于光反射原理,工作流程如下:

  1. IR光发射:内置的红外LED发射脉冲IR光
  2. 手势反射:当用户手在传感器上方做出手势时,IR光被反射
  3. 方向性光电二极管接收:四个方向的光电二极管接收反射光并转换为电信号
  4. 信号处理:传感器内部处理器分析四个光电二极管的信号强度变化
  5. 手势识别:根据不同方向光电二极管信号的时序和强度变化,识别出手势方向

手势识别原理基于运动探测:

  • 从左到右手势:首先激活左侧光电二极管,然后是右侧
  • 从右到左手势:首先激活右侧光电二极管,然后是左侧
  • 从上到下手势:首先激活上侧光电二极管,然后是下侧
  • 从下到上手势:首先激活下侧光电二极管,然后是上侧

通过分析这些信号随时间的变化,传感器能识别基本的方向性手势。理论上,通过复杂的算法处理,还可以识别更复杂的手势模式。

APDS-9960 传感器的 Data Sheet 中的方向定位原理图

接近检测原理

接近检测利用相同的IR LED和光电二极管,但使用不同的信号处理方式:

  1. IR LED发射红外光
  2. 物体反射红外光
  3. 光电二极管检测反射光强度
  4. 反射光强度与距离成反比,通过测量反射光强度估算物体距离

APDS-9960传感器能够测量约10厘米范围内的物体距离,分辨率为8位(0-255)。

环境光和颜色检测原理

环境光和颜色感应使用专门的光电二极管阵列:

  1. 光电二极管上方有不同颜色的滤光片(红、绿、蓝和清晰)
  2. 四个通道并行收集特定波长范围的光强度
  3. 内置16位ADC将光电二极管信号转换为数字值
  4. 可以通过这些值计算出环境光强度和颜色成分

APDS-9960传感器的关键特性

根据数据手册,APDS-9960具有以下技术特性:

参数规格
工作电压2.4V-3.6V
通信协议I²C (最高400kHz)
集成LED波长950nm
手势检测距离约10-15cm
接近检测范围0-255 (8位分辨率)
颜色检测分辨率16位 (每通道)
集成FIFO缓冲区32×4字节 (用于手势数据)
工作温度-30°C至85°C

传感器状态机工作流程

APDS-9960内部实现了一个状态机来控制各个功能单元的工作流程:

工作流程简述:

  1. 初始化:上电后传感器进入低功耗睡眠状态
  2. 唤醒:通过I2C指令激活内部振荡器
  3. 功能启用:可单独启用手势、接近、颜色/环境光功能
  4. 数据采集:根据启用的功能,按特定顺序采集数据
  5. 中断生成:数据超过阈值或手势被识别时生成中断
  6. 数据读取:主控制器通过I2C读取数据寄存器
  7. 返回空闲或睡眠:完成数据处理后返回空闲状态或睡眠状态

APDS-9960 传感器的 Data Sheet 中的 状态机简化状态示意图

APDS-9960 传感器的 Data Sheet 中的详细状态图

手势引擎数据流

手势检测的数据流如下:

  1. 手势入口条件:当接近值超过设定阈值,进入手势状态机
  2. 数据采集:连续测量四个方向的信号强度
  3. FIFO存储:将四个方向(UDLR)的信号数据存入32×4字节的FIFO缓冲区
  4. 中断生成:当FIFO数据量达到阈值,生成中断
  5. 手势识别:主控制器读取FIFO数据,进行手势算法处理
  6. 手势退出:当所有方向的信号强度降至阈值以下,退出手势状态

这种设计允许连续监测手势,同时最小化对主控制器的干扰。

APDS-9960 传感器的 Data Sheet 中的详细手势操作流程图

与微控制器的接口方式

APDS-9960 通过I2C接口与微控制器通信:

  • 固定I2C地址:0x39
  • 通信速率:最高支持400kHz快速模式
  • 中断引脚:提供一个专用中断输出引脚,可触发微控制器的外部中断
  • 寄存器映射:通过寄存器配置传感器参数和读取数据

XLOT设计的模块在APDS-9960基础上增加了电平转换电路,使其能同时兼容3.3V和5V的逻辑电平,方便与各种微控制器连接。

设计传感器电路并与XIAO ESP32C3进行连接

硬件连接方案

APDS-9960 手势传感器采用 I2C 通信协议,与 XIAO ESP32C3 的连接非常简单直接。该传感器只需要四个引脚连接,包括电源、地线和I2C通信的两根数据线。

我给手势传感器插上了有 4 色线的接头,并向供应商询问了四条颜色线对应的引脚,红黑黄绿分别代表 VCC、GND、SDA 和 SCL。

XLOT APDS-9960 模块插上购买附送的 4 色线接头,另一端的引脚母头可以直接插入 XIAO 的引脚排针

由于我之前设计的开发板,没有引出 D4 和 D5,所以,我先直接通过引脚连接,以测试代码和性能。

连接方案详情

APDS-9960引脚XIAO ESP32C3引脚功能
VCC5V电源正极
GNDGND电源地线
SDAD4/GPIO6I2C数据线
SCLD5/GPIO7I2C时钟线

接线图

XIAO ESP32C3 与 XLOT APDS-9960 模块的接线图

硬件连接注意事项

  1. 电源选择:和淘宝卖家沟通,被告知传感器模块可在 3V-5V电压范围内工作,所以我接在了5V引脚上。
  2. I2C总线配置:默认情况下,XIAO ESP32C3的I2C总线使用D4(SDA)和D5(SCL)引脚。无需上拉电阻,因为XIAO ESP32C3 内部已经有上拉电阻。
  3. 传感器放置:手势传感器的放置位置非常重要,应确保:
    • 传感器上方5-10cm范围内没有遮挡物
    • 传感器面向用户,便于进行手势操作
    • 固定牢固,避免晃动导致误读
  4. 连接线长度:使用尽可能短的连接线,特别是I2C信号线,以减少信号干扰。推荐连接线长度不超过20cm。

实际连接实现

由于项目处于原型阶段,我使用杜邦线进行了临时连接,将XLOT APDS-9960模块与之前设计的XIAO ESP32C3扩展板相连。完成连接后的实物如下图所示:

XIAO ESP32C3 与 XLOT APDS-9960 模块的连接效果图

在最终项目中,将考虑使用更可靠的连接方式,如焊接或使用牢固的接插件,以确保系统长期稳定工作。

传感器放置设计

为了获得最佳的手势识别效果,传感器的放置非常关键。经过几次次测试,我确定了以下放置方案:

  1. 纸盒安装方式:我采用了简单但实用的方法,将手势传感器用胶带固定在纸盒上盖的内壁,这种方式有几个明显优势:
    • 便于传感器保持直立姿态
    • 可以随时调整传感器角度
    • 提供了轻量且稳定的支撑结构

XLOT APDS-9960 模块使用胶带固定在纸盒上盖的内壁

  1. 高度定位:传感器表面距离底座约3cm,便于用户在设备上方5-10cm处进行手势操作。
  2. 角度调整:传感器略微向上倾斜约15度,使其更容易捕捉用户手部动作。这种倾斜角度是通过胶带固定在纸盒上盖内壁的方式轻松实现的。
  3. 遮光设计:纸盒本身就提供了一定的遮光效果,我在纸盒上方只保留了足够的开口供手势操作。这种简易的遮光设计大大提高了在强光环境下的识别准确率。
  4. 位置标识:在纸盒外部添加了简单的标记,指示用户进行手势操作的最佳位置。

这种使用纸盒作为支架的方法不仅成本低廉,而且组装拆卸方便,非常适合原型开发阶段的快速测试和调整。

编程测试手势识别功能

开发环境搭建

开发环境基于Arduino IDE进行搭建,主要包括以下步骤:

  1. 安装 XIAO ESP32C3 开发板支持
    • 在 Arduino IDE 中添加 Seeed Studio XIAO 开发板支持
    • 选择"XIAO_ESP32C3"作为目标开发板
  2. 安装XLOT_APDS9960库
    • 将下载的XLOT_Gesture_Sensor库复制到Arduino库文件夹
  3. 测试环境准备
    • 设置串口监视器波特率为115200
    • 准备测试环境,确保有稳定的光照条件

3.2 测试程序代码

店家首先提供了一个 I2C 的测试程序,以便能检测到 0x39 的传感器设备。

cpp
#include <Wire.h>

void setup() {
  Wire.begin(6,7);        // 初始化I2C总线//17,16   21 22
  Serial.begin(115200);  // 初始化串口
  while (!Serial);     // 等待串口打开
}

void loop() {
  byte error, address;
  int devices = 0;

  Serial.println("Scanning...");

  for (address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address<16) {
        Serial.print("0");
      }
      Serial.print(address,HEX);
      Serial.println("  !");
      devices++;
    }
    else if (error==4) {
      Serial.print("Unknown error at address 0x");
      if (address<16) {
        Serial.print("0");
      }
      Serial.println(address,HEX);
    }    
  }
  if (devices == 0) {
    Serial.println("No I2C devices found\n");
  }
  else {
    Serial.println("done\n");
  }
  // delay(5000);  // 每5秒执行一次I2C扫描
}

运行测试程序,如果接线正确,会看到下面的画面。

扫描提示在 0x39 发现 I2C 设备

plain
Scanning...
I2C device found at address 0x39  !
done

然后运行淘宝店家提供的手势识别测试程序,它能够识别APDS-9960传感器捕获的上、下、左、右四个方向的手势,并通过LED和串口输出提供反馈:

cpp
#include <Wire.h>

#include "XLOT_APDS9960AD.h"
XLOT_APDS9960AD apds;

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(115200);
  Wire.begin(6, 7);
  
  if(!apds.begin()){
    Serial.println("failed to initialize device! Please check your wiring.");
  }
  else Serial.println("Device initialized!");

  //gesture mode will be entered once proximity mode senses something close
  apds.enableProximity(true);
  apds.enableGesture(true);
  apds.setProxGain(APDS9960_PGAIN_8X);
  apds.setGestureGain(APDS9960_PGAIN_8X);
  apds.setGestureGain(APDS9960_AGAIN_64X);
  apds.setGestureGain(APDS9960_GGAIN_8);
}

// the loop function runs over and over again forever
void loop() {
  //read a gesture from the device
    uint8_t gesture = apds.readGesture();
    if(gesture == APDS9960_DOWN) Serial.println("v");
    if(gesture == APDS9960_UP) Serial.println("^");
    if(gesture == APDS9960_LEFT) Serial.println("<");
    if(gesture == APDS9960_RIGHT) Serial.println(">");
}

运行程序,可以在串口监视器看到输出的手势方向指示,如下图所示。

在串口监视器看到输出的手势方向指示

实际操作的效果视频如下所示。