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

Arduino Uno自动浇水系统:如何仅在传感器输入变化时启用舵机

Arduino自动浇水系统修复方案

问题根源

  1. 模拟传感器的微小噪声会导致读数频繁变化,触发重复浇水动作
  2. 缺少状态标记,无法在一次浇水后禁用舵机直至传感器状态发生有效变化
  3. 循环末尾冗余的servo.write(0)可能干扰舵机正常工作
  4. delay()函数阻塞程序,导致LCD更新、传感器读取暂停

修复后的代码

#include <LiquidCrystal_I2C.h>
#include <Servo.h>

#define SOIL_SENSOR A0
#define ULTRASONIC_TRIG 13
#define ULTRASONIC_ECHO A1
#define POTENTIOMETER A2
#define SERVO_PIN 3
#define PIEZO_PIN 9

#define SERVO_DURATION 5000
#define DEBOUNCE_THRESHOLD 10  // 去抖动阈值,过滤微小噪声

#define ULTRASONIC_THRESHOLD 80
#define SOIL_THRESHOLD 500
#define POTENTIOMETER_THRESHOLD 500

int soilValue = 0;
int ultrasonicValue = 0;
int potentiometerValue = 0;
bool isWateringDisabled = false;  // 标记是否禁用浇水

Servo servo;
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  pinMode(PIEZO_PIN, OUTPUT);
  pinMode(ULTRASONIC_TRIG, OUTPUT);
  pinMode(ULTRASONIC_ECHO, INPUT);
  pinMode(SOIL_SENSOR, INPUT);
  pinMode(POTENTIOMETER, INPUT);
  
  servo.attach(SERVO_PIN);
  
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("Soil:");
  lcd.setCursor(0,1);
  lcd.print("Light:");

  // 初始化传感器基准值
  soilValue = analogRead(SOIL_SENSOR);
  ultrasonicValue = getUltrasonicDistance();
  potentiometerValue = analogRead(POTENTIOMETER);
}

void loop() {
  int new_soilValue = analogRead(SOIL_SENSOR);
  int new_ultrasonicValue = getUltrasonicDistance();
  int new_potentiometerValue = analogRead(POTENTIOMETER);
  
  // 更新LCD显示,清除多余数字
  lcd.setCursor(5, 0);
  lcd.print(new_soilValue);
  lcd.print("   ");
  lcd.setCursor(6, 1);
  lcd.print(new_potentiometerValue);
  lcd.print("   ");

  // 检查传感器是否发生有效变化(过滤噪声)
  bool hasSensorChanged = abs(new_soilValue - soilValue) > DEBOUNCE_THRESHOLD ||
                          abs(new_potentiometerValue - potentiometerValue) > DEBOUNCE_THRESHOLD ||
                          abs(new_ultrasonicValue - ultrasonicValue) > DEBOUNCE_THRESHOLD;

  if (hasSensorChanged) {
    // 更新基准值
    soilValue = new_soilValue;
    potentiometerValue = new_potentiometerValue;
    ultrasonicValue = new_ultrasonicValue;

    // 传感器变化后,重新允许判断是否浇水
    isWateringDisabled = false;
  }

  // 检查水位过低,触发蜂鸣器(非阻塞方式)
  if (ultrasonicValue > ULTRASONIC_THRESHOLD) {
    static unsigned long lastBeepTime = 0;
    if (millis() - lastBeepTime >= 1000) {
      tone(PIEZO_PIN, 1000);
      delay(500);
      noTone(PIEZO_PIN);
      lastBeepTime = millis();
    }
  }

  // 满足浇水条件且未被禁用时,执行浇水
  if (!isWateringDisabled && 
      soilValue < SOIL_THRESHOLD && 
      potentiometerValue > POTENTIOMETER_THRESHOLD && 
      ultrasonicValue < ULTRASONIC_THRESHOLD) {
    
    servo.write(180);
    delay(SERVO_DURATION);  // 若需非阻塞运行,可替换为millis()实现
    servo.write(0);

    // 浇水完成后禁用,直到传感器再次变化
    isWateringDisabled = true;
  }
}

int getUltrasonicDistance() {
  digitalWrite(ULTRASONIC_TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(ULTRASONIC_TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(ULTRASONIC_TRIG, LOW);
  
  int duration = pulseIn(ULTRASONIC_ECHO, HIGH);
  int distance = duration * 0.034 / 2;
  return distance;
}

关键修改说明

  1. 增加状态标记isWateringDisabled:

    • 浇水完成后设为true,禁止再次触发浇水动作
    • 仅当传感器发生有效变化时,重置为false,允许重新判断浇水条件
  2. 传感器去抖动处理:

    • 增加DEBOUNCE_THRESHOLD,只有当读数变化超过阈值时,才判定为有效变化
    • 避免模拟传感器的微小噪声导致重复触发
  3. 移除冗余代码:

    • 删除循环末尾的servo.write(0),避免干扰舵机正常动作逻辑
  4. 优化蜂鸣器逻辑:

    • 使用millis()实现非阻塞蜂鸣,避免阻塞程序影响LCD更新和传感器读取
  5. 初始化基准值:

    • 在setup()中读取初始传感器值,避免设备启动时误触发浇水或报警

内容的提问来源于stack exchange,提问作者Dede Kurniawan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 03:48:08