Расписание из прошлого урока я поставил в теплицу целиком и получил два поучительных провала за одну неделю. В четверг ночью прошёл ливень, утром в пятницу автомат покорно открыл клапан по плану «пт» — поверх лужи. А во вторник, когда жара за три дня выжгла ящик с рассадой до состояния глины, полив не пришёл: вторник в плане был выходным. Формула «по расписанию, но только если сухо» лежит на поверхности, и именно её делает возможной пара датчик почвы плюс реле: календарь решает, когда полив разрешён, земля решает, нужен ли он вообще.
В этом уроке закрываем проект целиком. Добавим к каркасу расписания два устройства: ёмкостный датчик влажности почвы на аналоговом входе A0 и модуль реле на D7, который коммутирует помпу. Разберёмся, почему показания датчика надо калибровать двумя числами, зачем порогов два, а не один, и почему питание помпы никогда не берут с пина платы. Всё это — три условия в одном if и десяток строк сверх того, что вы уже написали, но именно здесь начинаются грабли, которые сжигают насосы и заливают подоконники.
Удобно думать о системе как о трёх фильтрах, через которые проходит команда насосу. Календарь отвечает на «когда поливать можно»: день в плане, час в окне. Датчик почвы отвечает на «нужно ли»: сухо ли там наверху, где растут корни. Страховка отвечает на «сколько»: максимальная длительность одного полива, чтобы оторвавшийся шланг или пустой бак не превратили полив в вечный. Каждый фильтр — простое сравнение, а надёжность системы растёт от их произведения: чтобы вода полила, должны совпасть все три условия разом, и отказ любого из них виден в журнале по тому, какое из них не пустило.
Датчик почвы: два числа калибровки
Датчик — это либо пара оголённых щупов, либо ёмкостная планка с покрытием. Резистивные щупы — те, что голым металлом втыкаются в землю, — работают по проводимости: сухо — ток хуже, значение analogRead больше; мокро — проводимость растёт, значение падает. Хитрость природы в том, что постоянный ток через мокрые щупы устраивает электролиз, и металл облезает за пару-тройку недель — показания плывут, датчик выбрасывается. Ёмкостные планки (самая ходовая — версия v1.2) измеряют ёмкость грунта вокруг себя, металл закрыт защитным слоем и живёт сезонами, поэтому для установки на месяц и дольше я беру только их. Основное чтение то же: analogRead(A0), сухо — большие значения, мокро — маленькие; основы чтения аналоговых входов повторены в уроке про analogRead.
Калибровать нужно свой экземпляр, потому что значения гуляют от партии к партии и от длины проводов. Ритуал простой и занимает пять минут: датчик в воздухе (это сухой предел, у моих планок около 820–850), затем в стакане воды (влажный предел, около 300). Между ними — реальная земля: свежеполитая грядка ляжет ближе к влажному пределу, пересохшая — к сухому. Порог включения насоса ставят примерно посередине между «свежеполитая» и «воздух» — у меня вышло 700, а порог выключения ниже, 550, и в следующем разделе объясню, почему их именно два. Ещё одна привычка, удлиняющая жизнь датчику: питать его не постоянно, а подавать питание на планку за пару сотен миллисекунд до замера и снимать после — меньше времени под током, меньше электрохимии.
Реле, насос и два порога
Модуль реле подключается тремя проводами: VCC, GND и сигнальный на D7 — digitalWrite(7, HIGH) щёлкает якорем, и помпа на силовых контактах получает питание. Саму помпу питают от отдельного блока — у небольшой 5-вольтовой мембранной помпы рабочий ток 100–200 мА, пиковый при старте выше, а пин Arduino отдаёт порядка 40 мА: попытка крутить насос прямо от пина или от 5V платы просаживает питание и перезагружает контроллер в самый интересный момент. Землю блока питания и земли платы соединяют — общий минус обязателен, иначе сигнал реле не будет иметь смысла. И проверьте свой модуль: немалая доля китайских реле активные-LOW — они включаются от LOW, а HIGH — это «выключено»; если насос работает навыворот, причина именно тут.
Теперь пороги. С одним порогом выходит смешное: земля у значения 650 колеблется — насос включается, чуть полил, влажность прошла порог вниз, он выключается, земля снова сохнет — и так по кругу каждые несколько минут. Помпа греется, реле щёлкает, вода размывает лунку у корня. Лечение — гистерезис: включаем при 700 (суше уже некуда), а выключаем только когда влажность дойдёт до 550. Между порогами состояние помпы не меняется, и включений становится в разы меньше — те же физика и логика, что у термостата с парой градусов запаса. Реле при двух поливах в день отработает сотни циклов за сезон — механике хватит с запасом; если бы полив был частым и плавным, я бы ставил MOSFET-ключ и крутил ШИМ.
Отдельная страшилка бочек и баков — сухой ход: мембранная помпа, оставленная без воды, греется за считаные минуты и умирает, иногда с запахом. Поэтому бак ставят выше насоса (самотёк гарантирует залив) или добавляют датчик уровня, и правило скетча простое: нет воды в баке — насос не включается ни при какой сухой земле. Шланг фиксируют хомутом: сорвавшийся в полдень шланг я искал по луже на подоконнике соседа снизу. И плату с реле ставят в закрытый бокс с вентиляцией — брызги от полива и конденс на холодном утреннем стекле с питанием не дружат.
#include <Wire.h>#include <RTClib.h> RTC_DS3231 rtc; // --- расписание (у RTClib 0 = воскресенье) ---int plan[7] = {0, 1, 0, 1, 0, 1, 0}; // пн, ср, птint nachalo = 7; // окно с 7:00int doChasa = 10; // до 10:00int polyaliDnya = -1; // --- почва и реле ---const int PIN_RELE = 7;const int POROG_VKL = 700; // суше — включаемconst int POROG_VYK = 550; // мокрее — выключаем (гистерезис)int nasosRabotaet = 0; unsigned long nachaloPoliva = 0;const unsigned long MAX_POLIV_MS = 180000UL; // страховка: не дольше 3 минут void setup() { Serial.begin(9600); rtc.begin(); rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); pinMode(PIN_RELE, OUTPUT); digitalWrite(PIN_RELE, LOW); // насос молчит; для активного-LOW инвертируйте} void loop() { DateTime now = rtc.now(); int dow = now.dayOfTheWeek(); int chas = now.hour(); // календарный гейт: день в плане и час в окне int razresheno = 0; if (plan[dow] == 1 && chas >= nachalo && chas < doChasa) razresheno = 1; int suho = 0; int vlazhnost = analogRead(A0); if (vlazhnost > POROG_VKL) suho = 1; // сухо — большие значения // полив: окно открыто, земля сухая, сегодня ещё не поливали if (razresheno == 1 && suho == 1 && polyaliDnya != now.day()) { nasosRabotaet = 1; nachaloPoliva = millis(); polyaliDnya = now.day(); } // выключение: либо промочили до нижнего порога, либо страховка по времени if (nasosRabotaet == 1 && (vlazhnost < POROG_VYK || millis() - nachaloPoliva > MAX_POLIV_MS)) { nasosRabotaet = 0; } digitalWrite(PIN_RELE, nasosRabotaet); // журнал раз в минуту: дата, влажность, состояние if (now.second() == 0) { Serial.print(dow); Serial.print(" chas="); Serial.print(chas); Serial.print(" v="); Serial.print(vlazhnost); Serial.print(" nasos="); Serial.println(nasosRabotaet); } delay(500);}| Показания датчика (мои калибровки) | Сырое значение на A0 | Вердикт скетча |
|---|---|---|
| Датчик в воздухе / пересохшая земля | 820–850 | выше порога 700 — поливаем, если окно открыто |
| Свежеполитая земля | 450–550 | ниже порога выключения 550 — насос молчит |
| Датчик в стакане воды | 280–320 | глубоко во влажной зоне — верный признак «не надо» |
| Провод оторван или датчик снят | 0 или 1023 всё время | значение-сирена: не попадает в разумную вилку — проверяем монтаж |
Сырое значение АЦП с джиттером и гистерезис реле: почему пороги нужны парой.
Подгружаем интерактив…
Строка статуса в симуляторе — это журнал платы, только быстрее: den, chas, plan, okno, v и nasos показывают все три фильтра разом. Сухой ползунок вне окна даст v=810 и okno=0 с молчащим насосом — календарь сильнее датчика; в поливной день в окне сухой ползунок включит реле, а зона между 550 и 700 сохранит состояние — так и виден гистерезис. Команды d0..d6 подменяют день недели — приём только для проверки плана, в боевом коде его убирают, а команды часам мы научились слать в уроке про чтение команд из Serial.
В проекте на плате тот же скелет дополняется секундным тиком из урока про SQW-прерывание: расписание проверяется по тику, а не в каждом круге loop, и плата, если ей есть чем спать, живёт в powerDown между поливами. Дальше по наращиванию: пороги и окно — в EEPROM-настройки, журнал — на SD-карту, и ваш автополив перестанет нуждаться в ноутбуке вообще.
- Подвиньте ползунок влажности к сухому краю и введите час 8 в поливной день: nasos=1, реле щёлкнуло. Верните ползунок к мокрому — nasos=0. Затем оставьте ползунок между 550 и 700: состояние помпы останется прежним — это гистерезис.
- Сдвиньте ползунок в сухую зону вне окна (введите час 15): в строке okno=0 и насос молчит. Календарь сильнее датчика — полив разрешён только в окне.
- Введите d-команду с выходным днём (например, d6 при плане пн/ср/пт в симуляции): plan=0 блокирует полив даже при сухой земле.
- Поставьте оба порога равными 650 и подвигайте ползунок около этого значения: помпа начнёт перецепляться туда-сюда — увидите своими глазами, зачем нужен гистерезис.
- Ёмкостный датчик живёт сезонами, голые резистивные щупы облезают от электролиза за недели — для установки берите ёмкостный
- Калибровка — два числа вашего экземпляра: сухой предел в воздухе и влажный в стакане; пороги ставят между ними
- Гистерезис: включение при 700, выключение при 550 — без второго порога помпа щёлкает вокруг одного значения каждые минуты
- Насос питают от отдельного блока с общей землёй; часть реле-модулей активные-LOW — проверьте щелчком до подключения воды
- Вердикт полива — три условия через И: день в плане, час в окне, почва сухая; плюс страховка по времени на случай утечки
- 1. У ёмкостного датчика на A0 сухая земля. Что покажет analogRead()?
- 2. Зачем порогов два: включение 700 и выключение 550?
- 3. Почему помпу не питают от пина 5V или напрямую с пина платы?
- 4. Реле-модуль оказался активным-LOW. Чем такой модуль включается?
- 5. Почему голые резистивные щупы со временем врут?
Проект собран, и дальше его расширяют уже не схемой, а служебными удобствами. Пороги и окно, которые сейчас вписаны в код, стоит вынести в настройки — как хранить конфиг на плате и не перешивать скетч ради смены порога, показано в уроке про первые настройки в EEPROM; а журнал поливов с датой и влажностью удобно писать на карту памяти — у соседнего раздела есть урок про логирование на SD. Если после сборки что-то работает не так, как в симуляторе, начните с журнала: строка с den, chas, v и nasos показывает, какое из трёх условий не пустило полив, — и проверьте ноль дня недели по прошлому уроку расписания, это самая частая причина сдвига.
Частые вопросы по теме урока
- У ёмкостного датчика на A0 сухая земля. Что покажет analogRead()?
- В сухой земле сигнал выше, во влажной ниже — конвенция «сухо = больше». Точные пределы свои у каждого экземпляра, поэтому калибруют воздухом и стаканом воды. Большое значение — сухо хуже проводит ток
- Зачем порогов два: включение 700 и выключение 550?
- Влажность около порога колеблется. Один порог даёт серию включений-выключений каждые минуты; мёртвая зона между 550 и 700 держит состояние помпы стабильным. Гистерезис: без раздельных порогов помпа щёлкает туда-сюда вокруг одного значения
- Почему помпу не питают от пина 5V или напрямую с пина платы?
- Небольшая мембранная помпа берёт 100–200 мА и выше на старте. Пин такой ток не тянет: питание проседает, плата перезагружается. Насосу — отдельный блок с общей землёй. Рабочий ток помпы — сотни миллиампер, а пин отдаёт порядка 40 мА
- Реле-модуль оказался активным-LOW. Чем такой модуль включается?
- У активных-LOW модулей вход притянут к питанию и срабатывает от земли: LOW включает, HIGH выключает. Симптом — насос ревёт сразу после подачи питания. digitalWrite(7, LOW)
- Почему голые резистивные щупы со временем врут?
- Постоянно запитанные щупы под током в мокрой земле электролитически разрушаются, показания плывут. Ёмкостные планки с покрытием живут сезонами. Постоянный ток устраивает электролиз, и металл облезает за недели