You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Arduino的自动冲水装置开发求助:LED逻辑控制卡壳

解决Arduino自动冲水装置的人员停留阶段逻辑问题

嘿,我来帮你搞定这个人员停留阶段的逻辑瓶颈!核心问题其实是要用状态机清晰区分「检测到人员进入」「人员停留」「人员离开」三个阶段,同时避免用delay()阻塞程序(不然你没法持续检测人员是否还在)。下面是完整的思路和代码实现:


先理清楚核心状态逻辑

我们把整个流程拆成4个状态,每个状态只做对应的事:

  • IDLE(初始状态):所有LED熄灭,伺服电机复位,等待检测人员
  • DETECTED(刚检测到人员):点亮第一个LED,1秒后自动熄灭,切换到停留状态
  • STAY(人员停留):持续检测人员是否在范围内,只要在就保持第二个LED点亮;一旦人员离开,切换到离开状态
  • LEAVE(人员离开):熄灭第二个LED,点亮第三个LED后随即熄灭,触发伺服电机冲水动作,最后回到初始状态

完整代码实现

#include <Servo.h>

// 硬件引脚定义
const int trigPin = 12;
const int echoPin = 11;
const int led1Pin = 10;  // 第一个LED:检测到人员时亮1秒
const int led2Pin = 9;   // 第二个LED:人员停留期间常亮
const int led3Pin = 8;   // 第三个LED:人员离开后闪一下
const int servoPin = 7;  // 伺服电机引脚

// 状态定义
enum DeviceState { IDLE, DETECTED, STAY, LEAVE };
DeviceState currentState = IDLE;

// 时间变量(用于非阻塞延时)
unsigned long led1Timer = 0;
unsigned long led3Timer = 0;
const unsigned long LED1_DURATION = 1000;  // 第一个LED亮1秒
const unsigned long LED3_DURATION = 500;   // 第三个LED亮500ms

// 超声波检测参数
const int DISTANCE_THRESHOLD = 30;  // 检测阈值:30cm内判定有人(可根据场景调整)
float distance = 0.0;

Servo flushServo;

void setup() {
  // 初始化引脚模式
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  pinMode(led3Pin, OUTPUT);
  
  // 初始化伺服电机
  flushServo.attach(servoPin);
  flushServo.write(0);  // 复位到初始位置
  
  // 串口调试(可选,方便看状态和距离)
  Serial.begin(9600);
}

void loop() {
  // 第一步:持续读取超声波距离
  distance = readUltrasonicDistance();
  
  // 第二步:根据当前状态执行对应逻辑
  switch(currentState) {
    case IDLE:
      // 初始状态:所有LED熄灭,等待检测人员
      digitalWrite(led1Pin, LOW);
      digitalWrite(led2Pin, LOW);
      digitalWrite(led3Pin, LOW);
      
      if(distance < DISTANCE_THRESHOLD) {
        // 检测到人员,切换到DETECTED状态
        digitalWrite(led1Pin, HIGH);
        led1Timer = millis();
        currentState = DETECTED;
        Serial.println("状态切换:IDLE -> DETECTED");
      }
      break;
      
    case DETECTED:
      // 刚检测到人员:等待1秒后熄灭第一个LED,进入停留状态
      if(millis() - led1Timer >= LED1_DURATION) {
        digitalWrite(led1Pin, LOW);
        digitalWrite(led2Pin, HIGH);
        currentState = STAY;
        Serial.println("状态切换:DETECTED -> STAY");
      }
      break;
      
    case STAY:
      // 人员停留状态:持续检测,只要人还在就保持LED2亮
      if(distance < DISTANCE_THRESHOLD) {
        // 人员仍在,保持LED2点亮
        digitalWrite(led2Pin, HIGH);
      } else {
        // 人员离开,切换到LEAVE状态
        digitalWrite(led2Pin, LOW);
        digitalWrite(led3Pin, HIGH);
        led3Timer = millis();
        currentState = LEAVE;
        Serial.println("状态切换:STAY -> LEAVE");
      }
      break;
      
    case LEAVE:
      // 人员离开状态:点亮LED3后熄灭,触发冲水
      if(millis() - led3Timer >= LED3_DURATION) {
        digitalWrite(led3Pin, LOW);
        // 触发伺服电机冲水动作(示例:转到90度停留1秒后复位)
        flushServo.write(90);
        delay(1000);  // 这里用delay没问题,因为已经到最后阶段了
        flushServo.write(0);
        // 回到初始状态
        currentState = IDLE;
        Serial.println("状态切换:LEAVE -> IDLE");
      }
      break;
  }
  
  // 串口打印调试信息(可选)
  Serial.print("当前距离:");
  Serial.print(distance);
  Serial.print("cm | 当前状态:");
  Serial.println(currentState);
  delay(100);  // 降低串口打印频率,不影响主逻辑
}

// 封装超声波读取函数
float readUltrasonicDistance() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  long duration = pulseIn(echoPin, HIGH);
  // 计算距离:声速340m/s = 0.034cm/µs,往返距离所以除以2
  float cm = duration * 0.034 / 2;
  return cm;
}

关键细节说明

  1. 状态机模式:用enum定义状态,switch-case处理每个状态的逻辑,避免了混乱的嵌套判断,让代码更清晰
  2. 非阻塞延时:用millis()代替delay(),这样在等待LED1熄灭的过程中,程序依然能持续检测超声波距离(如果用delay(),这1秒内没法检测人员是否离开)
  3. 超声波距离读取:封装成函数,便于维护和修改
  4. 调试辅助:加入串口打印,方便你查看当前距离和状态,快速排查问题

注意事项

  • 调整DISTANCE_THRESHOLD的值,根据你的安装位置和使用场景,避免误触发或漏检测
  • 伺服电机如果扭矩较大,建议用外部电源供电,不要直接用Arduino的5V引脚,防止供电不足
  • 可以在STAY状态里加入防抖逻辑(比如连续3次检测到距离超过阈值才判定离开),避免因为人员轻微移动导致误判

内容的提问来源于stack exchange,提问作者manan gandhi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:49:24