本帖最后由 zoey不种土豆 于 2024-11-21 20:14 编辑  
 
想象一下,仅需在空中挥挥手,就可以轻松控制灯的开关。这不仅为日常生活增添了便利,还为智能家居技术带来了更高的互动性和趣味性。手势识别的技术有很多种,在这个项目中,我们将利用两个光敏电阻,通过检测手在不同位置的光遮挡情况,实现手势控制。  
元件清单 
硬件连接 
按如下连线图连接。 
示例代码 
样例代码:
			
			
			- 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当前的开/关状态。 复制代码
 光敏电阻的读数会根据其位置和一天中的时间而变化。因此,在程序的设置阶段,我们需要执行自动校准以获得传感器的基线读数。 -  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);
 
  复制代码 
从之前关于光敏电阻的课程中,我们了解到较高的读数对应于较暗的光线条件。当手势发生时,投射到光敏电阻不同部分的阴影会导致其读数上升。因此,我们可以通过监控两侧光敏电阻读数的变化来区分左右挥手的手势。调整阈值变量可以让我们改进这个检测过程的灵敏度。 复制代码
 当左侧光敏电阻的读数超过其基线值加上阈值时,表示左侧有遮挡物。 - if (sensorVal1 > (cali1 + threshold))
 
  复制代码
 然而,仅依赖左侧读数是不够的;它需要与右侧光敏电阻的读数相结合来进行准确评估。 当左侧被遮挡而右侧没有时,它表示一个从右向左挥动的手势。 - if ((sensorVal1 > (cali1 + threshold)) && !(sensorVal2 > (cali2 + threshold)))
 
  复制代码
 在这行代码中,! 作为逻辑非运算符,用于反转内部表达式的值。&& 作为逻辑与运算符,检查两个表达式是否同时为真。如果条件满足,isOn 被设置为 true,从而打开 LED。否则,isOn 被设置为 false。 复制代码
 最后,我们使用 isOn 的当前值来决定是否打开或关闭 LED。在这里,if (isOn) 是 if (isOn == true) 的简写形式。 - if (isOn) {
 -     digitalWrite(ledPin, HIGH);  
 -     Serial.println("Turn On");
 -   } else {
 -     digitalWrite(ledPin, LOW);  
 -     Serial.println("Turn Off");
 -   }
 
  复制代码
  
示例代码  
 |