【花雕学编程】Arduino BLDC 之农业灌溉机器人(光感+湿度分区调速)

“Arduino BLDC之农业灌溉机器人(光感+湿度分区调速)”是一个典型的软硬件深度耦合的嵌入式系统。其核心设计哲学是:在Arduino等算力受限的微控制器上,通过多光感分区感知构建环境光照场,结合土壤湿度反馈,动态调节BLDC电机的移动速度与灌溉策略,实现“趋光巡航”与“按需精准补水”的闭环控制。
主要特点
- 多光感分区调速与趋光导航
这是机器人的“环境自适应”核心,使其能够根据光照分布自主调整运动轨迹。
光照场感知:在机器人前、后、左、右等方向布置多个光敏传感器(如LDR或BH1750),实时采集各区域的光照强度,构建一个简化的“光照梯度图”。
差速转向控制:通过计算左右两侧光照差值,动态调整左右BLDC电机的转速差,实现“趋光”或“避光”行为。例如,当左侧光照强于右侧时,左侧电机减速、右侧加速,机器人自然转向光源方向。
平滑调速:BLDC电机配合FOC(磁场定向控制)或PWM调速,可实现无级平滑的速度变化,避免因光照突变导致的机器人抖动或急停,提升运动稳定性。 - 湿度分区反馈与变频灌溉
这是机器人的“精准作业”核心,使其能够根据土壤墒情动态调整灌溉策略。
土壤湿度实时监测:通过电容式或电阻式土壤湿度传感器,实时采集土壤体积含水率。系统设定干燥阈值和湿润阈值,当检测到土壤缺水时,自动启动水泵进行灌溉。
变频精准补水:灌溉速度并非一成不变,而是与土壤湿度联动。例如,在土壤湿度接近干燥阈值时,系统会降低水泵转速或采用“间歇式浇水”(如开2秒-停5秒),让水分充分渗透,避免地表径流;当湿度接近湿润阈值时,逐渐降低灌溉强度,实现精细化补水。
环境耦合决策:灌溉决策不仅依赖湿度,还结合光照和温度数据。例如,在高温强光环境下,蒸腾作用加剧,系统会降低湿度启动阈值,提前触发灌溉;而在阴雨或夜间,则抑制灌溉以防烂根。 - BLDC高扭矩底盘与分层控制架构
底盘是机器人的“双腿”,其性能直接决定了机器人在复杂农田环境中的通过性和作业效率。
高扭矩密度:BLDC电机具备高功率密度和快速动态响应,能够在泥泞、起伏的农田中保持稳定的行驶姿态,并精准执行灌溉和避障动作。
低噪声与高效率:BLDC电机的无刷结构和正弦波驱动显著降低了运行噪音和转矩脉动,适合在温室大棚等需要保持安静的环境中长时间作业,同时高效率也延长了单次充电的续航时间。
分层式控制架构:上位机(决策层)可采用高性能计算平台(如树莓派或ESP32),负责运行SLAM、全局路径规划、任务调度和高级人机交互逻辑;下位机(执行层-Arduino)以高性能Arduino(如Teensy 4.0/4.1或Arduino Mega)作为微控制器,负责底层的实时控制任务,精确控制BLDC电机的转速和位置,同时实时采集编码器、IMU和底层传感器数据,进行故障检测和紧急制动处理。
应用场景
该系统凭借其智能化、自适应性和高适应性的特性,主要应用于以下场景:
小型农场与温室大棚精准灌溉:针对草莓、生菜等浅根作物或温室大棚环境,机器人可按照预设路径或趋光逻辑自主巡航。通过实时监测土壤湿度,实现“哪里干旱浇哪里”的精准滴灌或喷灌,相比传统漫灌可节水30%-50%。
农业科研与自动化播种巡检:在农业试验田中,机器人不仅可用于灌溉,还可搭载播种漏斗进行自动化播种作业。同时,结合DHT11等温湿度传感器,机器人可作为移动监测站,实时收集农田微气候数据并上传至云端,辅助农业专家优化种植策略。
校园科普与创客教育:该系统集成了传感器应用、电机控制、逻辑算法与机械结构,是极佳的STEM教育案例。学生可以通过该项目深入理解嵌入式系统、多传感器融合及自动化控制的基本原理。
家庭园艺与阳台种植:在家庭阳台或小型花园中,机器人可以自主巡逻,根据光照和湿度自动调节浇水策略,避免因遗忘浇水导致植物枯萎,或因浇水过多导致烂根。
需要注意的事项
在实现该系统时,需重点关注以下技术细节与工程红线:
- 传感器校准与数据滤波
土壤传感器校准:土壤湿度传感器的读数受土壤质地影响极大。在实际使用前,必须将传感器分别插入完全干燥和完全湿润的土壤中进行测试,记录analogRead的极值,并通过代码中的map函数进行准确映射。
光感传感器一致性:不同LDR或数字传感器存在个体差异,必须进行现场校准:在标准光源下记录各传感器输出,建立偏移补偿表;数字传感器建议启用内部积分时间自动调节(如BH1750的Continuous_H模式)。
软件防抖与滤波:传感器信号易受农田环境干扰。建议对湿度数据进行多次采样(如5-10次)取滑动平均值,以减少噪声干扰;同时引入软件防抖逻辑(如连续3次低于阈值才判定为干燥),避免水泵频繁误启停。 - 严格的电源管理与水泵驱动
独立供电:水泵和BLDC电机在启动时会产生巨大的瞬态电流,极易拉低Arduino的供电电压导致主控复位。因此,水泵和电机必须采用独立的电源供电,严禁与Arduino共用电源路径。
继电器与续流保护:控制水泵的继电器线圈两端必须并联续流二极管,防止断开瞬间产生的反向电动势击穿Arduino引脚;同时建议在电源端并联大容量电容(如1000μF)进行滤波。
共地连接:Arduino的GND必须与电机驱动模块、水泵驱动模块的GND物理连接,否则控制信号无法形成回路。 - 控制算法的实时性与稳定性
控制周期:光感分区调速和湿度反馈控制对实时性要求较高。控制回路必须使用硬件定时器中断或millis()非阻塞定时,严禁使用delay()函数。建议控制频率≥50Hz,以确保避障和调速的实时性。
PID参数整定:差速转向控制中的距离PID与转向PID参数需根据实际机械结构进行精细标定。参数过大会导致跟随抖动,过小则响应迟缓。建议采用增量式PID或带限幅的积分分离PID,以增强非线性工况下的动态性能。
死区时间控制:在驱动BLDC电机的三相全桥逆变电路中,必须插入短暂的“死区时间”(通常0.5-2μs),防止上下桥臂MOSFET同时导通造成短路。 - 安全冗余与失效保护
软件限幅:在代码中严格限制最大输出转矩、最大速度和最大电流。若控制模块异常,应切回默认保守参数或固定低速模式。
硬件急停:必须设置独立的硬件急停电路(如物理急停按钮或防撞条),采用中断级处理,可强切电机使能(EN),确保在系统失控时能瞬间切断动力。
故障检测:系统需具备堵转保护、缺相保护、过流保护、过温保护、欠压保护等多重安全机制。故障发生时,应立即停机并记录故障码,便于后期排查。

1、基础光感-湿度联动分区调速(LDR + 土壤湿度 + BLDC 差速底盘)
适用场景:温室大棚或小型农田,机器人沿预设路径巡航,LDR 感知光照分布以微调行进方向(趋光避荫),土壤湿度传感器触发定点灌溉,BLDC 差速底盘实现平稳调速。
/**
* 农业灌溉机器人 - 光感趋光 + 湿度触发分区调速
* 硬件假设:Arduino Mega, 2×BLDC差速驱动(SimpleFOC), LDR×2(左右), 土壤湿度传感器,
* 水泵继电器, 超声波避障
* 逻辑:光照差 -> 转向微调;湿度低于阈值 -> 停车灌溉 + 降低行进速度
*/
#include <SimpleFOC.h>
// BLDC 电机定义 (需根据实际硬件补全 Encoder/Driver 初始化)
BLDCMotor motorL(7);
BLDCMotor motorR(7);
#define LDR_LEFT_PIN A0
#define LDR_RIGHT_PIN A1
#define SOIL_MOISTURE A2
#define TRIG_PIN 2
#define ECHO_PIN 3
#define PUMP_PIN 8
// 阈值标定
const int SOIL_DRY_THRESHOLD = 650; // 干燥阈值 (需根据传感器实测调整)
const int SOIL_WET_THRESHOLD = 350; // 湿润阈值
const int LDR_DIFF_THRESHOLD = 120; // 光照差阈值,超过则转向微调
const float SAFE_DISTANCE_CM = 30.0;
// 调速参数
const float BASE_SPEED_RAD = 8.0; // 基础巡航速度 (rad/s)
const float SLOW_SPEED_RAD = 3.0; // 灌溉/避障时降速
const float TURN_GAIN = 0.008; // 光照差 -> 转向增益
unsigned long lastIrrigationTime = 0;
const unsigned long IRRIGATION_COOLDOWN = 30000; // 灌溉冷却 30s
bool irrigationActive = false;
float measureDistance() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH, 25000);
return (duration == 0) ? 999.0 : duration * 0.0343 / 2.0;
}
void setMotorSpeed(float leftRad, float rightRad) {
motorL.move(leftRad);
motorR.move(rightRad);
}
void setup() {
Serial.begin(115200);
// BLDC 初始化 (简化示意,实际需配置 Encoder + Driver)
motorL.init();
motorR.init();
motorL.initFOC();
motorR.initFOC();
motorL.controller = MotionControlType::velocity;
motorR.controller = MotionControlType::velocity;
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(PUMP_PIN, OUTPUT);
digitalWrite(PUMP_PIN, LOW);
}
void loop() {
motorL.loopFOC();
motorR.loopFOC();
// ========== 1. 多源感知 ==========
int ldrLeft = analogRead(LDR_LEFT_PIN);
int ldrRight = analogRead(LDR_RIGHT_PIN);
int soilMoisture = analogRead(SOIL_MOISTURE);
float obstacleDist = measureDistance();
// 光照差 -> 转向分量
int ldrDiff = ldrLeft - ldrRight;
// ========== 2. 安全优先:避障 ==========
if (obstacleDist < SAFE_DISTANCE_CM) {
setMotorSpeed(0, 0);
digitalWrite(PUMP_PIN, LOW);
Serial.println("Obstacle! Stop.");
delay(100);
return;
}
// ========== 3. 湿度决策 ==========
bool needIrrigation = (soilMoisture > SOIL_DRY_THRESHOLD);
unsigned long now = millis();
if (needIrrigation && !irrigationActive
&& (now - lastIrrigationTime > IRRIGATION_COOLDOWN)) {
irrigationActive = true;
digitalWrite(PUMP_PIN, HIGH);
lastIrrigationTime = now;
Serial.println("Irrigation ON");
}
// 湿度回升到湿润阈值或超时后停止灌溉
if (irrigationActive && (soilMoisture < SOIL_WET_THRESHOLD
|| (now - lastIrrigationTime > 15000))) {
irrigationActive = false;
digitalWrite(PUMP_PIN, LOW);
Serial.println("Irrigation OFF");
}
// ========== 4. 光感分区调速 ==========
float speedL, speedR;
if (irrigationActive) {
// 灌溉时停车,只开水泵
speedL = 0;
speedR = 0;
} else {
// 基础巡航速度
speedL = BASE_SPEED_RAD;
speedR = BASE_SPEED_RAD;
// 光照差转向微调:光照强的一侧减速,产生“趋光”转向
if (abs(ldrDiff) > LDR_DIFF_THRESHOLD) {
float turnAdjust = ldrDiff * TURN_GAIN;
speedL = constrain(BASE_SPEED_RAD - turnAdjust, 2.0, 12.0);
speedR = constrain(BASE_SPEED_RAD + turnAdjust, 2.0, 12.0);
}
// 湿度接近干燥时提前降速,准备灌溉
if (soilMoisture > SOIL_DRY_THRESHOLD - 100) {
speedL *= 0.6;
speedR *= 0.6;
}
}
setMotorSpeed(speedL, speedR);
Serial.print("LDR L/R:"); Serial.print(ldrLeft); Serial.print("/"); Serial.print(ldrRight);
Serial.print(" | Soil:"); Serial.print(soilMoisture);
Serial.print(" | Irrig:"); Serial.print(irrigationActive);
Serial.print(" | Speed L/R:"); Serial.print(speedL); Serial.print("/"); Serial.println(speedR);
delay(50);
}
要点:光感调速的核心是将光照差映射为差速转向分量——光照强的一侧减速,使机器人朝向光照更充足的方向偏移。湿度触发灌溉时,底盘停车、水泵启动,避免移动中喷洒造成水资源浪费。灌溉冷却时间防止同一位置反复浇水。
2、分区湿度阵列 + 光感方向权重调节(多区域精准灌溉)
适用场景:机器人搭载多路土壤湿度传感器(或沿路径预设多个检测点),根据各区域湿度差异决定行驶速度——湿度越低的区域,行进越慢、灌溉越充分,实现“按需调速、精准补水”。
/**
* 农业灌溉机器人 - 分区湿度阵列 + 光感方向权重
* 硬件假设:Arduino Mega, BLDC驱动底盘, 4路土壤湿度传感器(左前/右前/左后/右后),
* LDR×2, 水泵, 超声波
* 逻辑:根据前方左右两侧湿度差异,动态调整左右轮速(湿度低的一侧减速,增加灌溉停留时间)
*/
#include <SimpleFOC.h>
BLDCMotor motorL(7);
BLDCMotor motorR(7);
#define SOIL_FL A0 // 左前
#define SOIL_FR A1 // 右前
#define SOIL_BL A2 // 左后
#define SOIL_BR A3 // 右后
#define LDR_LEFT A4
#define LDR_RIGHT A5
#define PUMP_PIN 8
#define TRIG_PIN 2
#define ECHO_PIN 3
const int DRY_THRESHOLD = 700;
const int WET_THRESHOLD = 300;
const float CRUISE_SPEED = 7.0;
const float SLOW_FACTOR = 0.4; // 干燥侧减速因子
unsigned long lastPumpTime = 0;
bool pumpOn = false;
int readSoilAvg(int pin) {
// 滑动平均滤波
static int buf[4][5] = {{0}};
static int idx[4] = {0};
int sensorIdx = 0;
if (pin == SOIL_FL) sensorIdx = 0;
else if (pin == SOIL_FR) sensorIdx = 1;
else if (pin == SOIL_BL) sensorIdx = 2;
else sensorIdx = 3;
buf[sensorIdx][idx[sensorIdx]] = analogRead(pin);
idx[sensorIdx] = (idx[sensorIdx] + 1) % 5;
long sum = 0;
for (int i = 0; i < 5; i++) sum += buf[sensorIdx][i];
return sum / 5;
}
void setup() {
Serial.begin(115200);
motorL.init(); motorR.init();
motorL.initFOC(); motorR.initFOC();
motorL.controller = MotionControlType::velocity;
motorR.controller = MotionControlType::velocity;
pinMode(PUMP_PIN, OUTPUT);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
digitalWrite(PUMP_PIN, LOW);
}
void loop() {
motorL.loopFOC();
motorR.loopFOC();
// ========== 1. 分区湿度读取 ==========
int soilFL = readSoilAvg(SOIL_FL);
int soilFR = readSoilAvg(SOIL_FR);
int soilBL = readSoilAvg(SOIL_BL);
int soilBR = readSoilAvg(SOIL_BR);
// 左侧/右侧平均湿度
int leftMoisture = (soilFL + soilBL) / 2;
int rightMoisture = (soilFR + soilBR) / 2;
int minMoisture = min(min(soilFL, soilFR), min(soilBL, soilBR));
// ========== 2. 光感方向权重 ==========
int ldrL = analogRead(LDR_LEFT);
int ldrR = analogRead(LDR_RIGHT);
// ========== 3. 避障 ==========
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long dur = pulseIn(ECHO_PIN, HIGH, 25000);
float dist = (dur == 0) ? 999.0 : dur * 0.0343 / 2.0;
if (dist < 25.0) {
motorL.move(0); motorR.move(0);
digitalWrite(PUMP_PIN, LOW);
delay(100);
return;
}
// ========== 4. 分区调速逻辑 ==========
float speedL = CRUISE_SPEED;
float speedR = CRUISE_SPEED;
// 湿度低的一侧减速,使机器人偏向干燥区域“多停留”
if (leftMoisture > DRY_THRESHOLD) {
speedL *= SLOW_FACTOR; // 左侧干燥 -> 左轮减速
}
if (rightMoisture > DRY_THRESHOLD) {
speedR *= SLOW_FACTOR; // 右侧干燥 -> 右轮减速
}
// 光照差叠加转向权重
int ldrDiff = ldrL - ldrR;
speedL += ldrDiff * 0.005;
speedR -= ldrDiff * 0.005;
speedL = constrain(speedL, 1.5, 10.0);
speedR = constrain(speedR, 1.5, 10.0);
// ========== 5. 灌溉触发 ==========
unsigned long now = millis();
if (minMoisture > DRY_THRESHOLD && (now - lastPumpTime > 20000)) {
pumpOn = true;
lastPumpTime = now;
digitalWrite(PUMP_PIN, HIGH);
} else if (minMoisture < WET_THRESHOLD && pumpOn) {
pumpOn = false;
digitalWrite(PUMP_PIN, LOW);
}
motorL.move(pumpOn ? 0 : speedL);
motorR.move(pumpOn ? 0 : speedR);
Serial.print("Soil L/R:"); Serial.print(leftMoisture); Serial.print("/"); Serial.print(rightMoisture);
Serial.print(" | Speed L/R:"); Serial.print(speedL); Serial.print("/"); Serial.print(speedR);
Serial.print(" | Pump:"); Serial.println(pumpOn);
delay(50);
}
要点:分区湿度阵列的价值在于将“全局灌溉”变为“局部响应”。左右两侧独立读取湿度后,干燥一侧的驱动轮减速,使机器人自然偏向该区域,同时增加灌溉停留时间。这比统一降速更精准,也避免了湿润区域被过度浇水。光感权重叠加在湿度权重之上,优先级低于湿度。
3、光感使能 + 湿度闭环调速 + 分时段灌溉(与逻辑安全架构)
适用场景:需要满足“白天灌溉、夜间停泵”的基本农艺要求,同时根据土壤湿度实时调节 BLDC 底盘的行驶速度——湿度越低,行驶越慢、灌溉越充分,形成闭环。
/**
* 农业灌溉机器人 - 光感使能 + 湿度闭环调速 + 分时段安全
* 硬件假设:Arduino Mega, BLDC底盘, LDR(环境光), 土壤湿度, 水泵继电器, OLED(可选)
* 逻辑:光照 > 阈值 且 土壤干燥 -> 允许灌溉;灌溉时底盘速度与湿度偏差成反比
*/
#include <SimpleFOC.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
BLDCMotor motorL(7);
BLDCMotor motorR(7);
#define LDR_PIN A0
#define SOIL_PIN A1
#define PUMP_PIN 8
Adafruit_SSD1306 display(128, 64, &Wire, -1);
// 参数
const int LIGHT_ENABLE_THRESHOLD = 500; // 光照使能阈值 (白天)
const int SOIL_DRY_THRESHOLD = 700;
const int SOIL_TARGET = 400; // 目标湿度
const float MAX_SPEED = 9.0;
const float MIN_SPEED = 2.0;
bool lightEnabled = false;
bool irrigationActive = false;
void setup() {
Serial.begin(115200);
motorL.init(); motorR.init();
motorL.initFOC(); motorR.initFOC();
motorL.controller = MotionControlType::velocity;
motorR.controller = MotionControlType::velocity;
pinMode(PUMP_PIN, OUTPUT);
digitalWrite(PUMP_PIN, LOW);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Agri-Robot Ready");
display.display();
}
void loop() {
motorL.loopFOC();
motorR.loopFOC();
// ========== 1. 感知 ==========
int lightLevel = analogRead(LDR_PIN);
int soilMoisture = analogRead(SOIL_PIN);
// 光感使能:光照充足才允许灌溉(避免夜间蒸发少时无效浇水)
lightEnabled = (lightLevel > LIGHT_ENABLE_THRESHOLD);
// ========== 2. 闭环调速计算 ==========
// 湿度偏差 -> 速度因子:越干 -> 速度越低 -> 灌溉停留越久
float speedFactor = 1.0;
if (soilMoisture > SOIL_TARGET) {
// 偏差归一化:从 TARGET 到 1023 映射为 1.0 -> 0.2
float deviation = (float)(soilMoisture - SOIL_TARGET) / (1023 - SOIL_TARGET);
deviation = constrain(deviation, 0, 1);
speedFactor = 1.0 - deviation * 0.8; // 最慢降到 20%
}
float cruiseSpeed = MIN_SPEED + (MAX_SPEED - MIN_SPEED) * speedFactor;
// ========== 3. 灌溉决策 ==========
bool shouldIrrigate = lightEnabled && (soilMoisture > SOIL_DRY_THRESHOLD);
if (shouldIrrigate && !irrigationActive) {
irrigationActive = true;
digitalWrite(PUMP_PIN, HIGH);
} else if (!shouldIrrigate && irrigationActive) {
// 湿度回升到目标值或光照不足 -> 停泵
if (soilMoisture < SOIL_TARGET || !lightEnabled) {
irrigationActive = false;
digitalWrite(PUMP_PIN, LOW);
}
}
// ========== 4. 运动输出 ==========
if (irrigationActive) {
motorL.move(0);
motorR.move(0);
} else if (!lightEnabled) {
// 夜间不灌溉,正常巡航 (或按需求停止)
motorL.move(5.0);
motorR.move(5.0);
} else {
motorL.move(cruiseSpeed);
motorR.move(cruiseSpeed);
}
// ========== 5. 状态显示 ==========
static unsigned long lastDisplay = 0;
if (millis() - lastDisplay > 500) {
lastDisplay = millis();
display.clearDisplay();
display.setCursor(0, 0);
display.print("Light: "); display.print(lightLevel);
display.setCursor(0, 10);
display.print("Soil: "); display.print(soilMoisture);
display.setCursor(0, 20);
display.print("Irrig: "); display.println(irrigationActive ? "ON" : "OFF");
display.setCursor(0, 30);
display.print("Speed: "); display.println(cruiseSpeed, 1);
display.display();
}
Serial.print("Light:"); Serial.print(lightLevel);
Serial.print(" Soil:"); Serial.print(soilMoisture);
Serial.print(" Irrig:"); Serial.print(irrigationActive);
Serial.print(" Speed:"); Serial.println(cruiseSpeed);
delay(100);
}
要点:此案例引入了光感使能安全逻辑——“光照 > 阈值 且 土壤干燥”才允许灌溉,符合“白天浇水减少病害、夜间蒸发少时避免无效灌溉”的基本农艺原则。湿度闭环调速将土壤湿度偏差映射为底盘速度因子:越干燥,机器人行进越慢,灌溉停留时间越长,形成“感知-决策-执行”的闭环。OLED 状态显示便于现场调试。
要点解读
-
光感在灌溉机器人中不是“太阳能板”,而是“环境使能信号”。 很多初学者将 LDR 用于判断“是否需要给电池充电”,但在灌溉场景中,光感的核心价值是判断当前是否适合灌溉。夜间或阴天蒸发量小,浇水效率低且易引发病害;光照充足时灌溉,作物吸收效率更高。将光照作为“与逻辑”的使能条件,比单纯用湿度触发更符合农艺要求。
-
“分区调速”的本质是“用底盘运动表达优先级”,而非单纯改变电机转速。 传统灌溉机器人只有“走”和“停”两种状态。分区调速引入第三种状态:干燥区域低速通过。这相当于用机器人的运动行为告诉系统:“这个区域需要更多关注”。干燥一侧驱动轮减速,机器人自然偏向该区域;湿度接近阈值时整体降速,为灌溉做准备。这种“用运动表达优先级”的思路,比复杂的路径规划更实用。
-
湿度闭环调速比阈值开关控制更节水,且对 BLDC 更友好。 案例三中的 speedFactor = 1.0 - deviation * 0.8 是典型的比例控制——湿度偏差越大,速度越慢。BLDC 配合 FOC 可以实现平滑的转速变化,频繁的“启动-停止”反而会缩短电机和驱动器的寿命。用连续调速替代离散开关,是 BLDC 相对于有刷电机的核心优势之一。
-
灌溉触发必须有“冷却时间”和“湿度回升终止条件”。 传感器噪声或土壤局部不均匀可能导致水泵频繁启停。案例一中的 IRRIGATION_COOLDOWN = 30000 和案例二中的 (now - lastPumpTime > 20000) 都是冷却机制。同时,不能只依赖“湿度低于阈值就开泵”,还需要“湿度回升到目标值或超时后停泵”的终止条件,否则会在传感器故障时持续灌溉。
-
分区灌溉的传感器布局应与运动方向对齐。 案例二中左前/右前/左后/右后四路传感器并非随意布置:前方传感器主导“即将进入的区域”,后方传感器验证“刚刚离开的区域”。当前方某侧干燥时,机器人减速并偏向该侧;当后方对应传感器显示湿度回升时,说明该区域灌溉有效。这种前后呼应的布局,比简单的左右两路更能反映灌溉效果。

4、基于光感+湿度的分区基础灌溉程序(核心:多区域按需调速灌溉)
适用场景:大田分区灌溉,机器人实现光感遮盖防误喷、湿度分区检测,按需调节水泵(BLDC)转速,适配大田不同地块的灌溉需求。
核心逻辑
利用光感识别作业区域,天黑或遮挡时暂停灌溉,避免夜间或误操作浪费水
分区采集土壤湿度,匹配预设阈值,动态调节BLDC水泵转速
结合分区启停,实现按需灌溉,兼顾灌溉效率与节水
// 光感+湿度分区基础灌溉程序
// 硬件:光敏电阻、土壤湿度传感器(电容式)、BLDC水泵驱动、分区阀门
// 功能:分区检测湿度,光感遮护,按需调速灌溉,适配大田场景
#include <Arduino.h>
// ========== 硬件引脚定义 ==========
const byte LS_PIN = A0; // 光敏传感器引脚
const byte SOIL_PIN[3] = {A1, A2, A3}; // 3个分区湿度传感器
const byte SOLENOID_VALVE[3] = {3, 5, 6}; // 3个分区电磁阀(低电平开启)
const byte PWM_PIN = 9; // BLDC水泵转速控制引脚
// ========== 灌溉参数 ==========
const uint8_t THRESHOLD_HIGH = 600; // 湿度高阈值,高于则停止灌溉
const uint8_t THRESHOLD_LOW = 200; // 湿度低阈值,低于则满速灌溉
const uint8_t MOTOR_FAST = 200; // 满速占空比
const uint8_t MOTOR_SLOW = 120; // 低速占空比
const uint8_t LS_DIM = 300; // 环境光暗阈值,低于则暂停灌溉
bool irrigating = false; // 灌溉状态标志
uint8_t currentZone = 0; // 当前作业分区
// ========== 函数声明 ==========
float readSoilHumidity(byte pin);
uint8_t readLightStatus();
int calcMotorSpeed(uint8_t humidity);
void setup() {
Serial.begin(115200);
Serial.println("分区调速灌溉系统启动");
pinMode(LS_PIN, INPUT);
for (byte i = 0; i < 3; i++) {
pinMode(SOIL_PIN[i], INPUT);
pinMode(SOLENOID_VALVE[i], OUTPUT);
digitalWrite(SOLENOID_VALVE[i], HIGH); // 初始关闭阀门
}
pinMode(PWM_PIN, OUTPUT);
analogWrite(PWM_PIN, 0); // 初始水泵停机
}
void loop() {
uint8_t lightVal = readLightStatus(); // 1. 检测环境光
if (lightVal < LS_DIM) { // 2. 环境过暗,暂停灌溉并复位
if (irrigating) {
Serial.println("环境光过暗,暂停灌溉");
analogWrite(PWM_PIN, 0);
for (byte i = 0; i < 3; i++) {
digitalWrite(SOLENOID_VALVE[i], HIGH);
}
irrigating = false;
}
delay(500);
return;
}
// 3. 分区依次检测湿度,按需开启阀门与调速
for (byte i = 0; i < 3; i++) {
currentZone = i;
float humidity = readSoilHumidity(SOIL_PIN[i]);
int speed = calcMotorSpeed(humidity); // 计算所需转速
if (speed > 0) {
irrigating = true;
digitalWrite(SOLENOID_VALVE[i], LOW);// 开启对应阀门
analogWrite(PWM_PIN, speed);// 匹配水泵转速
Serial.print("分区"); Serial.print(i+1); Serial.print("湿度");Serial.print(humidity);Serial.print(",转速");Serial.println(speed);
} else {
digitalWrite(SOLENOID_VALVE[i], HIGH);// 关闭阀门
}
delay(1000); // 分区灌溉间隔
}
// 灌溉完成后休息10s再循环
if (irrigating) {
delay(10000);
}
}
// 读取土壤湿度,电容式传感器返回0-1023,数值越高湿度越大
float readSoilHumidity(byte pin) {
uint16_t raw = analogRead(pin);
// 简易滤波,取多次采样的平均值
uint16_t sum = 0;
for (byte k = 0; k < 3; k++) {
sum += analogRead(pin);
delay(20);
}
return sum / 3.0f;
}
// 读取光感值,0-1023,数值越高光照越强
uint8_t readLightStatus() {
return analogRead(LS_PIN);
}
// 计算水泵转速,湿度越高转速越低
int calcMotorSpeed(uint8_t humidity) {
if (humidity >= THRESHOLD_HIGH) {
return 0; // 湿度达标,停止灌溉
} else if (humidity >= THRESHOLD_LOW) {
return Mo Tor_SLOW; // 湿度适中,低速灌溉
} else {
return MOTOR_FAST; // 湿度不足,满速灌溉
}
}
适用场景优化
增加地块面积参数,大地块分区延长灌溉时长,小地块缩短,适配不同规模
优化传感器安装位置,分区多点采样取平均值,避免单点偏差
加入降雨检测,雨天自动关闭灌溉,进一步提升节水效果
5、光感+湿度分区+光照补偿灌溉程序(核心:光感联动与动态适配)
适用场景:温室大棚灌溉,机器人结合光照强度调节灌溉强度,弥补光强不足导致的作物蒸腾差异,同时实现分区精准湿度控制。
核心逻辑
融合光感与湿度数据,光照强度与湿度阈值动态关联,实现光感补偿调水
分区检测湿度与光照,匹配作物需水规律,动态调节BLDC转速与灌溉时长
结合温室环境特性,优化灌溉节奏,保障作物生长需水
// 光感+湿度分区+光照补偿灌溉程序
// 硬件:光敏模块、土壤湿度传感器、BLDC水泵、分区电磁阀、光照阈值参数
// 功能:温室分区灌溉,光照补偿,动态调节灌溉量,适配作物生长需求
#include <Arduino.h>
// ========== 硬件定义 ==========
const byte LS_PIN = A0; // 顶部光感,检测整体光照
const byte SOIL_PIN[4] = {A1, A2, A3, A4};// 4个分区湿度传感器
const byte LS_ZONE[4] = {A5, A6, A7, A8}; // 4个分区光感(可选,简化用顶部光感)
const byte VALVE[4] = {2, 3, 5, 6}; // 4个分区电磁阀
const byte PWM_PIN = 9; // BLDC水泵控制
// ========== 灌溉参数 ==========
const uint8_t LIGHT_FULL = 700; // 充足光照(满光)
const uint8_t LIGHT_LOW = 300; // 弱光阈值
const uint8_t HUMIDITY_H[4] = {650, 600, 550, 620}; // 各分区湿度高阈值
const uint8_t HUMIDITY_L[4] = {180, 200, 170, 190}; // 各分区湿度低阈值
uint8_t baseSpeed = 160; // 基础转速
// ========== 函数声明 ==========
uint8_t calcLightCompensation(uint8_t lightVal);
float getZoneHumidity(byte zone);
uint8_t getLightZone(byte zone);
void setup() {
Serial.begin(115200);
Serial.println("光照补偿分区灌溉系统启动");
pinMode(LS_PIN, INPUT);
for (byte i = 0; i < 4; i++) {
pinMode(SOIL_PIN[i], INPUT);
pinMode(VALVE[i], OUTPUT);
digitalWrite(VALVE[i], HIGH);// 阀门初始关闭
}
pinMode(PWM_PIN, OUTPUT);
analogWrite(PWM_PIN, 0);
}
void loop() {
uint8_t overallLight = analogRead(LS_PIN); // 1. 顶部整体光照
// 2. 光照补偿系数,弱光时降低湿度阈值(作物需水增加)
float compFactor = calcLightCompensation(overallLight);
// 3. 分区检测与灌溉
for (byte i = 0; i < 4; i++) {
float humidity = getZoneHumidity(i);
// 根据补偿系数调整阈值
uint8_t highThreshold = (uint8_t)(HUMIDITY_H[i] * compFactor);
uint8_t lowThreshold = (uint8_t)(HUMIDITY_L[i] * (2.0f - compFactor)); // 弱光时降低低阈值
lowThreshold = constrain(lowThreshold, 100, 300);
if (humidity < highThreshold) {
// 计算转速:湿度越低、光照越弱,转速越高
int speed = baseSpeed;
if (humidity < lowThreshold) {
speed = MOTOR_FAST; // 湿度不足,满速
} else {
speed = baseSpeed + (lowThreshold - humidity) / 2; // 动态加档
}
// 光照补偿:弱光额外提速
speed += (overallLight < LIGHT_LOW) ? 30 : 0;
speed = constrain(speed, 80, 220);
digitalWrite(VALVE[i], LOW);// 开启阀门
analogWrite(PWM_PIN, speed);// 匹配转速
Serial.print("分区");Serial.print(i+1);Serial.print("湿度");Serial.print(humidity);
Serial.print("光照补偿");Serial.print(compFactor);Serial.print("转速");Serial.println(speed);
} else {
digitalWrite(VALVE[i], HIGH);// 湿度达标,关闭阀门
}
delay(800); // 分区灌溉间隔
}
delay(12000); // 灌溉周期间隔,根据作物生长阶段调整
}
// 计算光照补偿系数,范围0.8-1.2,光照越强,补偿系数越高
uint8_t calcLightCompensation(uint8_t lightVal) {
if (lightVal >= LIGHT_FULL) return 120;
if (lightVal <= LIGHT_LOW) return 80;
// 线性映射0.8-1.2
return map(lightVal, LIGHT_LOW, LIGHT_FULL, 80, 120) / 100.0f;
}
// 读取分区湿度,含滤波
float getZoneHumidity(byte zone) {
uint16_t sum = 0;
for (byte i = 0; i < 3; i++) {
sum += analogRead(SOIL_PIN[zone]);
delay(15);
}
return sum / 3.0f;
}
// 读取分区光照(简化,复用顶部光感值,可替换为分区光感)
uint8_t getLightZone(byte zone) {
return analogRead(LS_PIN);
}
适用场景优化
结合作物生长期调整补偿参数,苗期、花期、果期设置不同光照-湿度阈值,精准匹配需求
增加光照历史数据记录,分析短期光照变化趋势,提前预判需水量,提升灌溉前瞻性
优化分区阈值匹配,根据作物类别(叶菜、果实)设置差异化参数,提升灌溉精准度
6、光感+湿度分区+智能灌溉决策程序(核心:综合环境自适应灌溉)
适用场景:果园、露地经济作物灌溉,机器人融合光感、湿度、温度多源数据,实现智能决策,兼顾作物生长、节水与自动化运行。
核心逻辑
多传感器融合(光感、湿度、温度),构建智能灌溉决策模型
分区检测综合环境参数,匹配作物需水规律,动态调节转速与灌溉时长
结合昼夜规律与环境变化,自主调整灌溉策略,实现无人值守智能灌溉
// 光感+湿度分区+智能灌溉决策程序
// 硬件:光敏、湿度、温度传感器(DHT11)、BLDC水泵、分区阀、OLED屏(可选)
// 功能:果园分区灌溉,多环境融合决策,自适应调节灌溉策略
#include <Arduino.h>
#include <DHT.h>
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// ========== 硬件定义 ==========
const byte LS_PIN = A0;
const byte SOIL_PIN[4] = {A1, A2, A3, A4};
const byte VALVE[4] = {3, 5, 6, 7};
const byte PWM_PIN = 9;
const byte TEMP_LIMIT = 35;// 温度高限,高温时增加灌溉量
const byte TIME_START = 6; // 灌溉开始时间(小时)
const byte TIME_END = 18; // 灌溉结束时间(小时)
// ========== 决策参数 ==========
enum IrrigationMode { STANDBY, LOW, MEDIUM, HIGH }; // 待机、低、中、高
IrrigationMode mode = STANDBY;
uint8_t zonePriority[4] = {1, 3, 2, 1}; // 分区优先级,数值越高越先灌溉
uint8_t maxSpeed = 210;
// ========== 函数声明 ==========
bool isIrrigationTime();
uint8_t calcDecision(float humidity, uint8_t light, uint8_t temp);
void adjustMode(IrrigationMode m);
void setup() {
Serial.begin(115200);
Serial.println("智能灌溉决策系统启动");
dht.begin();
pinMode(LS_PIN, INPUT);
for (byte i = 0; i < 4; i++) {
pinMode(SOIL_PIN[i], INPUT);
pinMode(VALVE[i], OUTPUT);
digitalWrite(VALVE[i], HIGH);
}
pinMode(PWM_PIN, OUTPUT);
analogWrite(PWM_PIN, 0);
}
void loop() {
// 1. 时间判断,非灌溉时段进入待机
if (!isIrrigationTime()) {
mode = STANDBY;
for (byte i = 0; i < 4; i++) digitalWrite(VALVE[i], HIGH);
analogWrite(PWM_PIN, 0);
Serial.println("当前非灌溉时段,系统待机");
delay(5000);
return;
}
// 2. 环境数据采集
float humidity = dht.readHumidity();
float temp = dht.readTemperature();
uint8_t light = analogRead(LS_PIN);
uint8_t lightNorm = (uint8_t)(light / 1024.0f * 100.0f); // 归一化至0-100
// 3. 按分区优先级灌溉,动态决策
// 简易优先级排序(冒泡):高优先级在前
for (byte i = 0; i < 4; i++) {
for (byte j = i + 1; j < 4; j++) {
if (zonePriority[j] > zonePriority[i]) {
byte tmp = zonePriority[i];
zonePriority[i] = zonePriority[j];
zonePriority[j] = tmp;
}
}
}
for (byte i = 0; i < 4; i++) {
float zoneHumidity = readZoneHumidity(SOIL_PIN[i]);
uint8_t decision = calcDecision(zoneHumidity, lightNorm, temp);
if (decision > 0) {
int speed = 0;
switch (mode) {
case LOW: speed = 100; break;
case MEDIUM: speed = 160; break;
case HIGH: speed = maxSpeed; break;
}
// 高温额外提速,补偿蒸腾
if (temp > TEMP_LIMIT) speed += 30;
speed = constrain(speed, 80, maxSpeed);
digitalWrite(VALVE[i], LOW);
analogWrite(PWM_PIN, speed);
Serial.print("优先级");Serial.print(zonePriority[i]);Serial.print("分区湿度");Serial.print(zoneHumidity);
Serial.print("决策");Serial.print(decision);Serial.print("转速");Serial.println(speed);
} else {
digitalWrite(VALVE[i], HIGH);
}
delay(1000);
}
delay(15000); // 循环周期
}
// 判断是否在灌溉时段
bool isIrrigationTime() {
hour_t now = hour();
return (now >= TIME_START && now <= TIME_END);
}
// 智能决策,返回0为不灌溉,1-3对应低、中、高需求
uint8_t calcDecision(float humidity, uint8_t light, uint8_t temp) {
// 夜晚优先不灌溉(时间判断已覆盖,补充光感校验)
if (light < 10) return 0;
// 湿度越高需求越低,线性映射
uint8_t demand = 0;
if (humidity < 30) demand = 3; // 湿度极低,高需求
else if (humidity < 50) demand = 2; // 湿度偏低,中需求
else if (humidity < 70) demand = 1; // 湿度适中,低需求
else demand = 0; // 湿度过高,无需灌溉
// 高温提升需求
if (temp > TEMP_LIMIT) demand = min(demand + 1, 3);
// 弱光降低需求
if (light < 40 && demand > 0) demand = max(demand - 1, 1);
return demand;
}
// 调整灌溉模式
void adjustMode(IrrigationMode m) {
mode = m;
}
// 读取分区湿度,含滤波
float readZoneHumidity(byte pin) {
uint16_t sum = 0;
for (byte i = 0; i < 3; i++) {
sum += analogRead(pin);
delay(10);
}
return sum / 3.0f;
}
适用场景优化
增加土壤类型参数,沙土、黏土、壤土调整灌溉阈值与时长,适配不同土壤蓄水特性
加入降雨历史数据,雨后自动调节灌溉量,避免重复灌溉造成浪费
接入云平台记录灌溉数据,分析作物生长与灌溉关系,优化决策模型,提升长期智能化水平
要点解读
要点1:光感判别需“场景化阈值匹配”,精准实现防误喷与光照补偿
光感是灌溉安全与精准的基础,需结合场景设定差异化规则。
防误喷阈值:针对大田作业,设置环境光阈值,天黑或遮挡时暂停灌溉,避免夜间、雨天或人为遮挡导致的无效灌溉
光照补偿规则:温室场景下,光照强度与作物蒸腾量正相关,弱光时降低湿度阈值并提升灌溉量,弥补光照不足导致的需水差异
昼夜规律适配:露地场景结合自然光照规律,设置灌溉时段(如早6点至晚6点),非时段强制停机,契合农业生产习惯,同时避免夜间灌溉降低病虫害风险
要点2:分区湿度检测需“多点采样+阈值分级”,实现精准按需灌溉
分区灌溉的核心是湿度检测的精准性,需通过采样与分级优化精度。
多分区独立检测:按地块、作物类型划分灌溉分区,每个分区独立采样,避免“一刀切”灌溉,适配土壤湿度差异
多点采样滤波:单分区内设置多个采样点,取平均值消除局部偏差,采用中值滤波过滤异常值,提升数据可靠性
阈值分级控制:将湿度划分为高、中、低多级区间,对应停灌、低速、中速、满速等转速档位,实现转速与湿度的精准匹配,避免过度或不足灌溉
要点3:BLDC调速需“与灌溉需求动态匹配”,兼顾效率与节能
BLDC水泵的调速直接决定灌溉效率与水资源利用率,需与环境需求联动。
转速与湿度联动:湿度越低,转速越高,确保干旱地块快速补水;湿度适中时降速,避免水分渗透过量造成浪费
转速与环境补偿联动:高温、强光时提升转速补偿蒸腾,弱光、低温时降低转速,动态适配作物需水变化
平稳启停控制:水泵启动、调速、停机采用渐变过程,避免水锤效应损坏管路与水泵,延长设备寿命,同时提升灌溉平稳性
要点4:智能决策需“多环境参数融合”,提升灌溉全面性
单一参数易出现灌溉偏差,多源参数融合是智能灌溉的核心。
多传感器协同:融合光感(光照)、湿度(土壤)、温度(环境)等参数,全面判断作物需水状态,避免仅依赖湿度的片面性
参数权重匹配:根据作物类型设置参数权重,如果实类作物温度权重高,叶菜类光照权重高,适配不同作物需求
动态调整策略:结合时间、季节、作物生长期动态调整决策阈值,如花期需水量大,自动提升灌溉优先级与转速,实现自适应灌溉
要点5:系统运行需“安全保护+异常兜底”,保障农业作业稳定
农业场景复杂多变,系统可靠性是长期运行的保障。
传感器异常保护:检测到湿度、光感数据跳变或失效,自动切断灌溉并告警,避免短路、数据错误导致的过度灌溉
设备故障兜底:水泵过流、堵转、阀门卡滞时,自动停机并提示故障位置,防止设备损坏与水资源浪费
环境适配机制:应对暴雨、大风等极端天气,自动触发保护策略(如关闭灌溉),同时记录异常日志,便于故障排查与策略优化,保障无人值守场景下的稳定运行
请注意:以上案例仅作为思路拓展的参考示例,不保证完全正确、适配所有场景或可直接编译运行。由于硬件平台、实际使用场景、Arduino 版本的差异,均可能影响代码的适配性与使用方法的选择。在实际编程开发时,请务必根据自身硬件配置、使用场景及具体功能需求进行针对性调整,并通过多次实测验证效果;同时需确保硬件接线正确,充分了解所用传感器、执行器等设备的技术规范与核心特性。对于涉及硬件操作的代码,使用前务必核对引脚定义、电平参数等关键信息的准确性与安全性,避免因参数错误导致硬件损坏或运行异常。

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)