zoey不种土豆 发表于 2024-11-20 17:13:40

Arduino入门教程19--手势控制灯「DFR0100」

本帖最后由 zoey不种土豆 于 2024-11-21 20:14 编辑

想象一下,仅需在空中挥挥手,就可以轻松控制灯的开关。这不仅为日常生活增添了便利,还为智能家居技术带来了更高的互动性和趣味性。手势识别的技术有很多种,在这个项目中,我们将利用两个光敏电阻,通过检测手在不同位置的光遮挡情况,实现手势控制。
元件清单
硬件连接
按如下连线图连接。
图 1 手势控制灯连线图示例代码
样例代码:int ledPin = 13;       // 定义LED引脚为13
int lightSensor1 = 0; // 定义左侧光传感器引脚为A0
int lightSensor2 = 1; // 定义右侧光传感器引脚为A1

int cali1 = 0;         // 左侧光传感器的校准变量
int cali2 = 0;         // 右侧光传感器的校准变量

bool isOn = false;   // LED状态控制变量

void setup() {
Serial.begin(9600);       // 初始化串行通信
   
pinMode(ledPin, OUTPUT);// 将LED引脚设置为输出

// 校准光传感器:读取10次数据并平均作为环境光基线
for (int i = 0; i < 10; i++) {
    cali1 += analogRead(lightSensor1);
    cali2 += analogRead(lightSensor2);
    delay(500);
}
cali1 = (cali1 / 10);
cali2 = (cali2 / 10);

Serial.print("环境光: ");
Serial.print(cali1);
Serial.print(" , ");
Serial.println(cali2);

// 通过LED闪烁两次来指示程序的开始
for (int i = 0; i < 2; i++) {
    digitalWrite(ledPin, HIGH);
    delay(1000);
    digitalWrite(ledPin, LOW);
    delay(1000);
}

Serial.println("开始");
}
void loop() {
int sensorVal1 = analogRead(lightSensor1);
// 读取左侧光传感器的值
int sensorVal2 = analogRead(lightSensor2);
// 读取右侧光传感器的值
int threshold = 30;// 设置手势检测阈值
Serial.print("L: ");
Serial.print(sensorVal1);
Serial.print("   R: ");
Serial.println(sensorVal2);
// 根据传感器值确定手势方向并控制LED
if ((sensorVal1 > (cali1 + threshold)) && !(sensorVal2 > (cali2 + threshold))) {
    isOn = true;
}
if (!(sensorVal1 > (cali1 + threshold)) && (sensorVal2 > (cali2 + threshold))) {
    isOn = false;
}
if (isOn) {
    digitalWrite(ledPin, HIGH);// 打开LED
    Serial.println("打开");
} else {
    digitalWrite(ledPin, LOW);   // 关闭LED
    Serial.println("关闭");
}
delay(100);// 延迟100毫秒以避免频繁读取
}
请将装置放置在光线稳定且无阴影遮挡的环境中。上传程序后,将自动进行5秒钟的校准,检测当前光线值。校准完成后,LED会闪烁两次,指示程序启动。向左挥手可打开灯光,向右挥手可关闭灯光。如果效果不理想,可以参考串口打印的读数,调整阈值设置。

代码回顾
在程序开始时,定义LED和两个光敏电阻的引脚。然后,创建两个名为cali的变量来记录光敏电阻的初始读数。
int cali1 = 0;
int cali2 = 0;
接下来,我们介绍一种新的变量类型,bool,它代表布尔变量。它只有两个可能的值:true(真)和false(假),通常用于表示条件的真实性或开关的状态。在这里,我们定义一个名为isOn的布尔变量来记录LED当前的开/关状态。bool isOn = false;光敏电阻的读数会根据其位置和一天中的时间而变化。因此,在程序的设置阶段,我们需要执行自动校准以获得传感器的基线读数。 for (int i = 0; i < 10; i++) {
    cali1 += analogRead(lightSensor1);
    cali2 += analogRead(lightSensor2);
    delay(500);
}
在For循环中,光敏电阻的模拟值被读取了10次,每次读取之间间隔500毫秒,并将结果累加到变量cali1和cali2中。具体来说,这个循环的目的是为了对光敏电阻进行校准,以获取在特定环境下(即程序开始时)它们的基础读数。通过多次读取并取平均值,可以减少因单次读数误差或环境光线的短暂变化而导致的误差。之后,将累加得到的总读数除以10,即可得到两个光敏电阻的校准值(即基线读数),这些值将用于后续的比较和判断,以确定LED的开/关状态。cali1 = (cali1 / 10);
cali2 = (cali2 / 10);
循环结束后,计算左侧和右侧光敏电阻的平均值。这些平均值将作为后续光线比较和决策的校准基线值。一旦完成校准,将平均值打印到串行监视器上,并闪烁LED两次以指示程序的开始。在loop函数中,我们将比较光线的值并控制LED的开关。首先,设置两个变量来记录光敏电阻的实时读数。int sensorVal1 = analogRead(lightSensor1);
int sensorVal2 = analogRead(lightSensor2);
从之前关于光敏电阻的课程中,我们了解到较高的读数对应于较暗的光线条件。当手势发生时,投射到光敏电阻不同部分的阴影会导致其读数上升。因此,我们可以通过监控两侧光敏电阻读数的变化来区分左右挥手的手势。调整阈值变量可以让我们改进这个检测过程的灵敏度。int threshold = 30;当左侧光敏电阻的读数超过其基线值加上阈值时,表示左侧有遮挡物。if (sensorVal1 > (cali1 + threshold))然而,仅依赖左侧读数是不够的;它需要与右侧光敏电阻的读数相结合来进行准确评估。当左侧被遮挡而右侧没有时,它表示一个从右向左挥动的手势。if ((sensorVal1 > (cali1 + threshold)) && !(sensorVal2 > (cali2 + threshold)))在这行代码中,! 作为逻辑非运算符,用于反转内部表达式的值。&& 作为逻辑与运算符,检查两个表达式是否同时为真。如果条件满足,isOn 被设置为 true,从而打开 LED。否则,isOn 被设置为 false。isOn = true;最后,我们使用 isOn 的当前值来决定是否打开或关闭 LED。在这里,if (isOn) 是 if (isOn == true) 的简写形式。if (isOn) {
    digitalWrite(ledPin, HIGH);
    Serial.println("Turn On");
} else {
    digitalWrite(ledPin, LOW);
    Serial.println("Turn Off");
}
示例代码
下一课:Arduino入门教程20--反应速度测试「DFR0100」
页: [1]
查看完整版本: Arduino入门教程19--手势控制灯「DFR0100」