手势控制 RGB 灯:基于 APDS-9960 与 Arduino 的动感灯光交互
硬件清单
| 元器件 | 数量 | 关键参数 |
|---|---|---|
| Arduino UNO R3 | 1 | 5V 逻辑电平,兼容 I2C |
| SparkFun APDS-9960 模块 | 1 | 手势/接近/环境光/色彩传感器,I2C 地址 0x39 |
| 共阴极 RGB LED | 1 | 三脚分别接 PWM 引脚,公共阴极接 GND |
| 4.7 kΩ 电阻 | 1 | I2C 上拉(模块通常已板载,外接更稳妥) |
| 面包板 & 杜邦线 | 1套 |
接线原理图

关键连接:
- APDS-9960 VCC → 3.3V(或 5V,模块自带 LDO),GND → GND
- SDA → A4,SCL → A5(UNO 硬件 I2C)
- INT → D2(外部中断 0,下降沿触发)
- RGB LED:R→A0, G→A1, B→A2(PWM 输出),公共阴极→GND
项目原理
APDS-9960 内置四向光电二极管,通过检测反射光强度的时空变化识别 上/下/左/右/近/远 六种手势。Arduino 读取手势中断标志,在主循环中调用 readGesture() 获取方向,据此切换 RGB LED 颜色或开关状态。
默认手势映射
| 手势 | 动作 |
|---|---|
| 向上划动 | 开灯 |
| 向下划动 | 关灯 |
| 向右划动 | 下一个颜色 |
| 向左划动 | 上一个颜色 |
| 靠近/远离 | 预留扩展 |
预置配色方案(6 种)
| 编号 | 名称 | R | G | B |
|---|---|---|---|---|
| 0 | 红 | 255 | 0 | 0 |
| 1 | 天蓝 | 255 | 153 | 204 |
| 2 | 深蓝 | 100 | 0 | 170 |
| 3 | 绿 | 0 | 255 | 0 |
| 4 | 蓝 | 0 | 0 | 255 |
| 5 | 紫罗兰 | 191 | 0 | 255 |
可在代码 switch(colorNumber) 中自行增减颜色,或改为 HSV 色环渐变。
完整代码
#include <Wire.h>
#include <SparkFun_APDS9960.h>
#define APDS9960_INT 2 // 中断引脚
int redPin = A0, greenPin = A1, bluePin = A2;
volatile int isrFlag = 0;
int onOff = 0, colorNum = 0;
SparkFun_APDS9960 apds = SparkFun_APDS9960();
void setup() {
pinMode(APDS9960_INT, INPUT);
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(APDS9960_INT), []{ isrFlag = 1; }, FALLING);
if (apds.init()) Serial.println("APDS-9960 init OK");
else { Serial.println("Init failed!"); while(1); }
if (apds.enableGestureSensor(true)) Serial.println("Gesture sensor running");
else { Serial.println("Gesture enable failed!"); while(1); }
pinMode(redPin, OUTPUT); pinMode(greenPin, OUTPUT); pinMode(bluePin, OUTPUT);
analogWrite(redPin, 0); analogWrite(greenPin, 0); analogWrite(bluePin, 0);
}
void loop() {
if (isrFlag) {
detachInterrupt(digitalPinToInterrupt(APDS9960_INT));
handleGesture();
isrFlag = 0;
attachInterrupt(digitalPinToInterrupt(APDS9960_INT), []{ isrFlag = 1; }, FALLING);
}
if (onOff) {
setColor(colorNum);
} else {
analogWrite(redPin, 0); analogWrite(greenPin, 0); analogWrite(bluePin, 0);
}
delay(100); // 降低循环频率,减少串口输出
}
void handleGesture() {
if (apds.isGestureAvailable()) {
switch (apds.readGesture()) {
case DIR_UP: Serial.println("UP"); onOff = 1; break;
case DIR_DOWN: Serial.println("DOWN"); onOff = 0; break;
case DIR_LEFT: Serial.println("LEFT"); if (onOff) colorNum = (colorNum + 5) % 6; break;
case DIR_RIGHT: Serial.println("RIGHT"); if (onOff) colorNum = (colorNum + 1) % 6; break;
case DIR_NEAR: Serial.println("NEAR"); break;
case DIR_FAR: Serial.println("FAR"); break;
default: Serial.println("NONE");
}
Serial.print("Color: "); Serial.println(colorNum);
}
}
void setColor(int idx) {
switch (idx) {
case 0: analogWrite(redPin,255); analogWrite(greenPin,0); analogWrite(bluePin,0); break;
case 1: analogWrite(redPin,255); analogWrite(greenPin,153); analogWrite(bluePin,204); break;
case 2: analogWrite(redPin,100); analogWrite(greenPin,0); analogWrite(bluePin,170); break;
case 3: analogWrite(redPin,0); analogWrite(greenPin,255); analogWrite(bluePin,0); break;
case 4: analogWrite(redPin,0); analogWrite(greenPin,0); analogWrite(bluePin,255); break;
case 5: analogWrite(redPin,191); analogWrite(greenPin,0); analogWrite(bluePin,255); break;
}
}
进阶玩法
- 亮度调节:增加“近/远”手势控制 PWM 占空比
- 呼吸灯模式:结合
millis()实现非阻塞渐变 - 多设备联动:通过 ESP-NOW / MQTT 同步多盏灯
- 颜色自定义:接入旋钮电位器或手机 App 调色
常见问题排查
- 手势识别率低:确保模块表面无遮挡,手势幅度 > 5cm,速度适中;调整
setGestureGain()增益 - I2C 通信失败:检查上拉电阻、供电电压、线序;用
I2C Scanner确认 0x39 - 中断丢失:UNO 仅 D2/D3 支持外部中断,确认接线;中断服务程序保持极简
- LED 颜色异常:确认共阴/共阳接法,共阴极需 PWM 输出高电平点亮
制造工艺
- 树莓派 + PIR 传感器 + MQTT 打造 AWS IoT 运动触发按钮
- 蓝牙控制树莓派机器人:语音反馈功能构建指南
- 手势控制 RGB 台灯 —— 交互式免手操作照明
- 通过树莓派用 Alexa 控制 LED - 简单分步指南
- 废旧遥控车改装:Arduino + USB Host Shield 实现 Xbox 手柄无线控制
- Arduino Mega 驱动 Wii Nunchuk 控制 6 自由度机械臂
- Arduino Nano 语音控制机器人:蓝牙 + 手机 APP 实现
- 基于 Arduino Nano 的智能运动感应水枪
- PiBot:Arduino驱动的88键钢琴机器人,精准演奏MIDI乐曲
- Arduino RGB LED调色器:三电位器混色入门项目
- Wi-Servo:基于 ESP8266 的 Wi-Fi 网页端舵机远程控制系统
- 户外DMX控制RGB投光灯:低成本高性能舞台灯光DIY方案