| 本帖最后由 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");
  }
 示例代码 
 |