补肾壮阳吃什么药效果好| 右手无名指戴戒指是什么意思| 什么的糯米| 血压低头晕是什么原因导致的| 吹水是什么意思| 喝酒睡不着是什么原因| 无痛人流和普通人流有什么区别| 圆脸适合什么发型好看| 虫草吃了有什么好处| 唇炎去药店买什么药| 罗可以组什么词| 吃什么降血糖| 甲床是什么| 嘴唇发麻什么病兆| 你在说什么用英语怎么说| 生理期吃什么水果比较好| 鼻梁歪的男人说明什么| 画是什么生肖| 偏头痛有什么症状| 女人腰疼是什么原因引起的| 质子治疗是什么意思| 阿尔茨海默症是什么| 围产期是什么意思| 白细胞满视野是什么意思| 什么是裸分| 原生家庭是什么意思| 兰花是什么季节开的| 12月23日是什么星座| kitchen什么意思| 丞五行属什么| 停车坐爱枫林晚中的坐是什么意思| 两面人是什么意思| 补钙过量有什么害处| 吃山竹有什么好处| 王加民念什么| 咳嗽什么原因引起的| 太阳穴疼痛是什么原因| 大姨妈来了喝红糖水有什么功效| 玩世不恭是什么意思| 武则天是什么星座的| 笃笃是什么意思| 113是什么意思| 暖心向阳是什么意思| 佩戴貔貅有什么讲究与禁忌| 望而生畏什么意思| 噗呲是什么意思| 中元节是什么节日| 双侧胸膜局限性增厚是什么意思| smzco是什么药片| 补肾吃什么药| 什么是关税| 宝宝胎动频繁说明什么| 鸡眼长什么样| 生蛇是什么原因引起的| rta是什么意思| 鸡胸是什么病| 大便隐血弱阳性是什么意思| 注意地看的词语是什么| 前列腺在什么位置| 内热是什么意思| 七月十五是什么节| mirage轮胎什么牌子| 国历是什么意思| 什么体质不易怀孕| 饺子都有什么馅| 靓字五行属什么| 高血压2级是什么意思| 三点水一个希读什么| 罹患率是什么意思| 复刻什么意思| 肋骨突出是什么原因| 胃痛怎么办吃什么药| hgh是什么意思| 九月29号是什么星座| 父亲节送爸爸什么| 喝鲜牛奶有什么好处和坏处| 什么的藤| 马为什么站着睡觉| 男性左下腹疼痛是什么原因| 脑鸣吃什么药| 脸色暗沉发黑什么原因| 左心房增大是什么原因| 含是什么意思| 什么是副乳| 直爽是什么意思| 频繁什么意思| 冰醋酸是什么| 肠子粘连有什么办法解决| 上眼皮浮肿是什么原因| 睿字五行属什么| 取向是什么意思| 真菌镜检阳性是什么意思| 痔疮是什么样的| 你什么意思| 藿香正气水能治什么病| 拍ct挂什么科| 胸膈痞闷什么意思| 葛根粉有什么功效和作用| 半什么半什么| 虾仁和什么包饺子好吃| 一什么所什么| px是什么| 什么人不能吃桃子| 农字五行属什么| 刚愎自用什么意思| 五行什么生水| 绿色心情是什么意思| 28岁属什么生肖| 黄飞鸿是什么生肖| 什么是医院感染| sop是什么意思| 头孢吃多了有什么副作用| 九肚鱼是什么鱼| 血糖高吃什么食物最好最佳| 尿臭是什么原因男性| 滋润是什么意思| 血脂挂什么科| c4是什么驾驶证| 胃不好早餐吃什么好| 男人有卧蚕代表什么| 什么是钼靶检查| 地包天什么意思| 男人什么脸型最有福气| 国树是什么树| 突然和忽然有什么区别| 昔字五行属什么| 降结肠疼是什么原因| 安乐片是什么药| 上火为什么会牙疼| 空鼻症是什么| 红薯什么季节成熟| 什么叫粉丝| 1958年属什么生肖| 嘴里发苦是什么原因| 射频消融术是什么意思| 总胆固醇偏低是什么意思| 厚植是什么意思| 牙齿酸是什么原因| 月经前便秘是什么原因| 桥本氏甲状腺炎吃什么药| 肾衰竭有什么症状| 什么李子品种最好吃| ch是什么意思| 黄晓明的老婆叫什么名字| 宝宝低烧吃什么药| 焗油是什么意思| 2026年是什么命| 清洁度二度是什么意思| 化疗后吃什么增加白细胞| 米油是什么| 店里来猫是什么兆头| 出什么什么什么| 好吃懒做是什么生肖| 咖啡有什么好处和坏处| 内膜居中是什么意思| ntr是什么意思啊| 聚字五行属什么| 意大利全称是什么| 吃什么补镁| 洗钱是什么意思啊| 阿玛尼算什么档次| 曲奇饼干为什么不成形| 观音菩萨保佑什么| 独具一格是什么意思| 湿热吃什么食物| 牛蒡是什么| 什么的奇观| 四点底和什么有关| 全身皮肤痒是什么原因| 子宫粘连是什么原因造成的| 骨关节炎是什么原因引起的| 看好你是什么意思| 双鱼女和什么星座最配| 争议是什么意思| 组织部副部长是什么级别| 割韭菜是什么意思| 什么的溪流| 大学生当兵有什么好处| 奶水不足是什么原因造成的| 易经和周易有什么区别| 伤口不结痂是什么原因| 7月17是什么星座| 前列腺特异性抗原高是什么原因| 什么叫免疫组化| 外感风寒吃什么药| 女生没有腋毛代表什么| 领袖是什么意思| 冰室是什么意思| 软开是什么| everytime什么意思| 嘴苦吃什么药| 什么样的智齿需要拔| 爱马仕配货是什么意思| 女人来月经吃什么好| 上技校学什么专业好| 猴子下山的故事告诉我们什么| 1月17日是什么星座| 甲沟炎有什么药| 冈本是什么| 五月二十一是什么星座| 朱雀玄武是什么意思| 低烧是什么病的前兆| 大腿青筋明显是什么原因| 胃疼吃什么药最有效| 骨挫伤是什么意思| 结缡什么意思| 甲状腺属于什么系统| 捡肥皂什么意思| 6月18是什么星座| 湿疹有什么症状| 电表走的快是什么原因| 牛牛是什么意思| zhr是什么牌子的鞋| 什么什么于怀| 风热感冒用什么药好| 同字五行属什么| 水饮是什么意思| 成人补锌吃什么药| 肾结石能吃什么| 正骨挂什么科| jojo什么意思| 吃苦瓜对身体有什么好处| 铁公鸡是什么意思| 深圳为什么叫鹏城| 九月生日是什么星座| 海关是什么| 什么的元帅| 臣字五行属什么| 喜欢吃冰的是什么原因| 三个马念什么| 妇科炎症是什么原因引起的| 一什么菜地| 什么是厌氧菌感染| 晚上失眠是什么原因| fop是什么意思| 7月31号是什么星座| 带状疱疹可以吃什么水果| 倚老卖老什么意思| 什么体质容易长肿瘤| 罗盘是干什么用的| 7月17号什么星座| 非甾体是什么意思| 军魂是什么意思| 地级市市长什么级别| 芒果是什么意思| 脸上长白斑是什么原因| 表哥的儿子叫什么| 吃阿胶有什么好处| 痴汉是什么意思| 2017年是属什么年| 高处不胜寒的胜是什么意思| 他喵的什么意思| 甘油三酯偏高说明什么问题| 为什么月亮是红色的| 梦见衣服是什么意思| 蓝莓有什么功效与作用| 关税是什么意思| wrong什么意思| 羊刃格是什么意思| 马飞是什么药| 吃什么提神| 小麦淀粉是什么| 10pcs是什么意思| 先入为主是什么意思| 百度
这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 ? 论坛首页 ? DIY与开源设计 ? 电子DIY ? [物联网系列][Aduino]Arduino智能灌溉系统(二) 完整版

共4条 1/1 1 跳转至

[物联网系列][Aduino]Arduino智能灌溉系统(二) 完整版

工程师
2025-08-03 23:28:23     打赏
百度 对他而言,时间是沉淀,亦是厚积薄发的过程,这一刻的勇气与突破,是为了更好的迎接下一刻的人生挑战。

简介

在上一篇文章中我对当前系统的整个构成进行了概述, 虽然系统的传感器使用的比较多,但是使用的是Arduino 平台,所以对每个传感器的驱动并不复杂, 因此在本篇文章中我将完成所有组件的构建.  


传感器外围部件清单

1 - 土壤湿度传感器(Analog)

2- 水流量传感器YF-S401

3- OLED 0.96

4- SHT30

5- LTR-329

6- NMOS 用于PWM驱动LED灯板

7- LED灯板

8- 继电器 (如果使用5V可以使用NMOS控制开关, 不需要使用继电器)

9- 12V 水泵 (可以调整为5V)


实物俯视图

image.png

实物平视图

image.png


OLED 显示image.png


Flask上位机监控界面

Snipaste_2025-08-03_14-04-53.png图图表一为系统上电时 PID动态调整灯光亮度的曲线图.


系统稳定时即PID调整后的光照输出 (稳定在了亮度200)

Snipaste_2025-08-03_14-05-38.png


Arduino程序设计

#include <Wire.h>
#include "Adafruit_SSD1306.h"
#include "Adafruit_GFX.h"
#include "Adafruit_LTR329_LTR303.h"
#include "Adafruit_SHT4x.h"
#include <ArduinoJson.h>


// OLED 屏幕配置
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire1, OLED_RESET);

// 传感器对象
Adafruit_LTR329 ltr = Adafruit_LTR329();
Adafruit_SHT4x sht4;

// PID 控制相关
const int pwmPin = 3;         // IO2 PWM 输出
const int targetCh0 = 200;    // 目标 CH0 值

float Kp = 0.18, Ki = 0.0825, Kd = 0.002;
float integral = 0, last_error = 0;
unsigned long lastTime = 0;

volatile unsigned int pulseCount = 0;
unsigned long lastFlowCalcTime = 0;
float flowRate_mLps = 0;   // 毫升每秒
float totalMilliLiters = 0;


const int pumpPin = 4;  // IO4 控制继电器
const int soilThreshold = 600;  // 土壤湿度阈值(需根据实际情况调整)
bool pumping = false;
float pumpStartVolume = 0;
volatile bool isTrunonLight = true;

#define FLOW_SENSOR_PIN 2

void flowPulseISR() {
  pulseCount++;
}


void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("Initializing...");

  pinMode(pwmPin, OUTPUT);

  // 初始化 OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 initialization failed!"));
    while (true);
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);

  // 初始化 LTR329
  if (!ltr.begin(&Wire1)) {
    Serial.println("Couldn't find LTR sensor!");
    while (1) delay(10);
  }
  ltr.setGain(LTR3XX_GAIN_2);
  ltr.setIntegrationTime(LTR3XX_INTEGTIME_100);
  ltr.setMeasurementRate(LTR3XX_MEASRATE_200);

  // 初始化 SHT40
  if (!sht4.begin(&Wire1)) {
    Serial.println(F("SHT40 sensor not found!"));
    while (1);
  }
  sht4.setPrecision(SHT4X_HIGH_PRECISION);
  sht4.setHeater(SHT4X_NO_HEATER);

  pinMode(FLOW_SENSOR_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(FLOW_SENSOR_PIN), flowPulseISR, RISING);

  pinMode(pumpPin, OUTPUT);
  digitalWrite(pumpPin, LOW);  // 默认关闭水泵

}

void loop() {
   if(Serial.available() >0)
    {
      char c = Serial.read();
      Serial.println(c);
      if(c == '1')
      {
        isTrunonLight = !isTrunonLight;
      }
    
    }
  uint16_t ch0 = 0, ch1 = 0;
  float temperature = 0, humidity = 0;

  // 读取光照
  if (ltr.newDataAvailable()) {
     StaticJsonDocument<256> doc;
    bool valid = ltr.readBothChannels(ch0, ch1);
    if (valid && isTrunonLight) {
      // PID 计算
      float error = targetCh0 - ch0;
      unsigned long now = millis();
      float dt = (now - lastTime) / 1000.0;
      lastTime = now;

      integral += error * dt;
      float derivative = (error - last_error) / dt;
      last_error = error;

      float output = Kp * error + Ki * integral + Kd * derivative;
      output = constrain(output, 0, 255);
      analogWrite(pwmPin, (int)output);
      // 每 1000ms 计算一次水流量
      if (millis() - lastFlowCalcTime >= 1000) {
        noInterrupts();
        unsigned int pulses = pulseCount;
        pulseCount = 0;
        interrupts();

        // 每脉冲 ≈ 2.22 毫升(YF401)
        flowRate_mLps = pulses * 2.22;
        totalMilliLiters += flowRate_mLps;

        lastFlowCalcTime = millis();
      }
          
        display.print("PWM: ");
        display.println((int)output);
        doc["pwm"] = (int)output;

    }else{
       analogWrite(pwmPin, 0);
    }
     // 读取温湿度
      sensors_event_t temp_event, hum_event;
      sht4.getEvent(&hum_event, &temp_event);
      temperature = temp_event.temperature;
      humidity = hum_event.relative_humidity;

      // 读取土壤湿度
      int soilValue = analogRead(A5);

      // 显示到 OLED
      display.clearDisplay();
      display.setCursor(0, 0);
      display.print("Temp: ");
      display.print(temperature, 1);
      display.println(" C");

      display.print("Humidity: ");
      display.print(humidity, 1);
      display.println(" %");

      display.print("Light CH0: ");
      display.println(ch0);

      display.print("Target: ");
      display.println(targetCh0);


      display.print("Flow: ");
      display.print(flowRate_mLps, 1);
      display.println(" mL/s");

      display.print("Total: ");
      display.print(totalMilliLiters, 0);
      display.println(" mL");

      if (!pumping && soilValue > soilThreshold) {
        digitalWrite(pumpPin, HIGH);
        pumping = true;
        pumpStartVolume = totalMilliLiters;
      }

      // 已在泵水 -> 检查是否达到100mL
      if (pumping && (totalMilliLiters - pumpStartVolume >= 100.0)) {
        digitalWrite(pumpPin, LOW);
        pumping = false;
        
      }

      int barLength = map(soilValue, 1023, 0, 0, 100);  // 显示湿度条(反映湿度)
      display.drawRect(0, 58, 100, 5, SSD1306_WHITE);      // 条边框
      display.fillRect(0, 58, barLength, 5, SSD1306_WHITE); // 填充条
      display.display();
     

      doc["temperature"] = temperature;
      doc["humidity"] = humidity;
      doc["light_ch0"] = ch0;
      doc["light_ch1"] = ch1;
      doc["target"] = targetCh0;
      doc["flow_mLps"] = flowRate_mLps;
      doc["total_mL"] = totalMilliLiters;
      doc["soil"] = soilValue;
      doc["pump"] = pumping;

      serializeJson(doc, Serial);
      Serial.println();
  }

  delay(500);  // 避免刷新过快
}


在上述的程序中对PID的调整稍微有一点麻烦, 这里有一个调整的思路就是, 首先将KI和KD都设置为0, 首先调整KP, 这里调整KP的时候可能会出现抖动的情况. 当抖动并不是很大的时候(LED闪烁频率没有那么大), 然后调整KI用来消除稳态误差. 当光照逐渐变稳定的时候再尝试调整KD来减缓超调与振荡.  此时LED的亮度已经已经稳定了. 如果觉得LED的亮度上升太慢或者下降太慢的话再逐渐改变KP的值. 到最后我系统中所调整的值为:

float Kp = 0.18, Ki = 0.0825, Kd = 0.002;

使其程序在运行的时候光照强度(可见光 + 红外光) 的亮度稳定在了 200. (上述的PID算法同样可以用于温控系统, 比如说恒温箱等)

核心代码如下所示

      float error = targetCh0 - ch0;
      unsigned long now = millis();
      float dt = (now - lastTime) / 1000.0;
      lastTime = now;

      integral += error * dt;
      float derivative = (error - last_error) / dt;
      last_error = error;

      float output = Kp * error + Ki * integral + Kd * derivative;
      output = constrain(output, 0, 255);
      analogWrite(pwmPin, (int)output);


Python 上位机程序设计

python的上位机是运行在虚拟的树莓派OS中的, 其中和Arduino的通讯主要是采用串口通讯. 其后端框架采用的是Flask, 支持将数据保存到数据库中. 

image.png

其主要的核心逻辑即读取串口的JSON输入, 然后通过HTML的定时器定时发送HTTP请求来读取串口数据,然后使用chart.js进行绘图.

串口线程(读取Arduino串口数据)


# 串口线程函数
def read_serial():
    global latest_data
    try:
        while True:
            line = ser.readline().decode('utf-8').strip()
            if line:
                try:
                    data = json.loads(line)  # 解析 JSON 数据
                    latest_data = data  # 更新最新的数据
                    print("Received:", data)
                    insert_data_to_db(data)  # 插入数据到数据库
                except json.JSONDecodeError:
                    print("Invalid JSON:", line)
    except serial.SerialException as e:
        print("Serial error:", e)


# 启动串口线程
serial_thread = threading.Thread(target=read_serial, daemon=True)
serial_thread.start()


返回串口数据用于前端绘图


@app.route('/data')
def get_data():
    return jsonify(latest_data)


定时请求串口数据:

 async function fetchData() {
        try {
            const res = await fetch('/data');
            const data = await res.json();
            document.getElementById("json").textContent = JSON.stringify(data, null, 2);

            const now = new Date().toLocaleTimeString();
            if (labels.length >= maxDataPoints) {
                labels.shift();
                lightData.shift();
                tempData.shift();
                humidityData.shift();
                soilData.shift();
            }

            labels.push(now);
            lightData.push(data.light_ch0);
            tempData.push(data.temperature);
            humidityData.push(data.humidity);
            soilData.push(data.soil);

            [lightChart, tempChart, humidityChart, soilChart].forEach((chart, i) => {
                chart.data.labels = labels;
                chart.data.datasets[0].data = [lightData, tempData, humidityData, soilData][i];
                chart.update();
            });
        } catch (err) {
            console.error("Failed to fetch data:", err);
        }
    }

    setInterval(() => {
        fetchData();
        fetchStats();
    }, 2000);


附件

project_without_env.zip

注意: 系统并不需要使用上位机程序进行监控, 不运行上位机对Arduino的执行没有任何影响




关键词: Arduino     智能灌溉系统     DIY    

专家
2025-08-03 11:39:07     打赏
2楼

感谢分享


专家
2025-08-03 11:42:57     打赏
3楼

感谢分享


专家
2025-08-03 11:44:44     打赏
4楼

学习一下


共4条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]
4月3号什么星座 奴役是什么意思 重生什么意思 间断性是什么意思 有过之而不及什么意思
怂人是什么意思 百鸟朝凤是什么生肖 灵芝和什么煲汤好 42属什么 strange是什么意思
肾不好有什么症状 一什么明珠 喜乐是什么意思 阑尾炎输液输什么药 一什么马车
乙肝表面抗原携带者什么意思 不怕热是什么体质 中医考证需要什么条件 中性粒细胞计数偏高是什么意思 什么米之乡
梦见生姜是什么意思hcv8jop2ns1r.cn 5月22号是什么星座hcv9jop2ns8r.cn 喜欢花的女人是什么性格hcv7jop7ns0r.cn 打虫药什么时候吃合适hcv8jop2ns3r.cn 东面墙适合挂什么画hcv7jop4ns8r.cn
脾脏大是什么原因hcv8jop6ns5r.cn 托帕石是什么宝石hcv9jop8ns0r.cn 药鱼用什么药效果最好hcv9jop5ns8r.cn 瓜婆娘四川话是什么意思hcv8jop0ns6r.cn 小孩头晕是什么原因hcv9jop5ns0r.cn
谭震林是什么军衔hcv9jop0ns3r.cn 甲亢不能吃什么食物hcv8jop0ns1r.cn 孕妇晚上饿了吃什么好hcv8jop5ns1r.cn 焦点是什么意思hcv8jop2ns8r.cn 自闭症是什么病shenchushe.com
猫咪踩奶是什么意思hcv7jop9ns4r.cn 什么叫精神出轨hcv7jop4ns6r.cn 空调抽湿是什么意思hcv8jop2ns3r.cn 晚上吃什么不发胖hcv9jop5ns6r.cn 动脉导管未闭对宝宝有什么影响hcv8jop5ns9r.cn
百度