Самодельный автополив с "боевым" прошлым

Что можно сделать полезного из гильзы обычного оружейного патрона? Кулон, зажигалку?.. В этой статье она пройдет путь от орудия войны до распределительного золотника в системе автополива. Конечно, не без помощи электропривода, насоса и электронной системы управления. Под катом разберем внутреннюю кухню, философию устройства, а также перспективы практического применения. Спойлер: теперь стреляем только водой!
Начну с плюсов. Первый — многоканальность полива. Второй — относительная простота реализации. Ну и… все.

Далее автор описывает, что у других все неоптимально, и пора сделать оптимально. Итого предлагает систему на 5 погружных насосов, 5 реле и интерфейс для настройки и управления — ардуино с символьным дисплеем и энкодером. Соответственно, расширяемость системы в N раз потребует увеличения затрат опять же в N раз (практически). Что если я скажу, что можно расширяться куда дешевле?
Мне пришла в голову мысль, что, вообще говоря, нам необязательно поливать все растения одновременно, ведь делать это нужно где-то раз в сутки. А если не нужна одновременность — зачем столько параллельных насосов? Я решил сделать систему с одним насосом и автоматической распределяющей системой на основе движущегося золотника.
В основе — недорогие компоненты: мотор-редуктор, помпа, микроконтроллер ESP8266 (как в умных розетках), пара реле и мосфет. Всё это управляет подачей воды по расписанию или через интернет. Корпус и механические детали я решил напечатать на 3D-принтере. Ну и гвоздь программы — золотник на основе гильзы пистолетного патрона. Да-да!

Все началось именно с него. Просто потому, что я живо у себя в голове представил устройство с движущейся гильзой и несколькими выводами под поливные шланги. Образ был настолько реален, что я незамедлительно приступил к разработке 3д модели распределителя.

Ничего не напоминает? Воображения мне хватило только чтобы сделать какое-то пистолетоподобное устройство с приводом в виде моторчика N20. Внутри устройства должен был двигаться поршень, который приводился бы в движения червячной передачей из строительной шпильки, проворачивающейся вокруг гайки M4.

Поршень же через другую шпильку передавал бы поступательное движение золотнику из гильзы, к которой с «естественного отверстия» подводилась бы вода, а с «искусственного» (просверленного в боку гильзы) она через отверстие в «стволе» поступала бы к выбранному растению. После печати я попробовал собрать устройство, но встретил сразу букет проблем.
Во-первых, гильза не хотела достаточно свободно двигаться в «стволе». Я несколько раз пробовал разные диаметры, и способы печати (вдоль, поперек). Я даже пробовал греть ствол при прохождении гильзы, чтобы она сама расширила себе отверстие. Это не работало. В итоге я все-таки нашел некий внутренний компромисс, чтобы гильза не сильно туго шла, но при этом достаточно плотно.
Во-вторых, я не придумал, как надежно соединить шпильку с золотником. Была идея напечатать некий переходник и склеить, но мне это показалось ненадежным. Повертев устройство в руках, я закинул его «в долгий ящик», пока вдохновение не вернется.

Прошел год… И снова мне на глаза попался этот проект. На этот раз я твердо решил закончить.
Во-первых, я стал гораздо лучше в пайке, поэтому первое, что пришло на ум для соединения шпильки и гильзы — пайка. Оставался вопрос, как все зафиксировать и припаять ровно. Ответ вас удивит. Нужен обычный старый добрый глазомер.

Гильзу я зажал в тиски, а шпильку максимально легонько придерживая, приставил сверху. Все предметы под действием силы тяжести тянет к земле. Но сейчас это плюс, потому что упрощает вертикальное позиционирование. А центровку я выполнил на глаз, целясь в центр выбитого капсюля. Для первой пайки железяк, считаю, вышло неплохо.
И да, собрав устройство в корпус, я убедился, что большого перекоса нет — гильза достаточно свободно ходила внутри.

Окрыленный успехом, я принялся за электронную часть. Схема устройства была собрана «из того, что было». А была парочка мосфетов, двойное реле и esp8266. И разумеется, паял на макетке. Ничего сложного нет ни в ее составлении, ни в ее сборке.


Сама схема довольно простая. Есть два концевика, которые сигнализируют о достижении поршня стенок девайса. Мосфет включает насос. Для насоса сделал еще повышайку, чтобы при желании увеличить мощность. Сдвоенное реле отвечает за управление ходом поршня распределителя. Стоит заметить, что такое использование компонентов не очень-то оптимальное, но об этом поговорим позднее.

Чтобы оживить схему, требуется прошивка микроконтроллера. Учитывая некоторую специфичность конструкции, с ней пришлось повозиться.
Я решил придерживаться ООП для лучшей организации кода и читаемости. В проекте присутствуют следующие классы: WebServer, DataStore, Pump, Router, Machine. Структурно они организованы следующим образом.

Итак, разберемся по порядку. Устройству нужна веб-морда для управления (я считаю, что это значительно удешевляет проект при сохранении эффективности). Для этого и существует WebServer. По сути класс основан на серверной библиотеке для ESP8266. Я заложил в код настройку периодичности полива, времени орошения каждого растения, а также мощность насоса.
Класс DataStore реализует хранилище данных и FTP-сервер для доступа к файлам устройства. В первую очередь это нужно для хранения настроек, во вторую можно динамически менять оформление страницы настроек, закидывая другой файл index.html. Настройки хранятся в файле settings в формате js-переменных. Файл script.js отвечает за динамическое изменение значений при движении ползунков. Сервер при запросе отправляет index.html, добавляя в него содержимое файла настроек и скрипта. Ко всему, такая организация кода позволяет легко добавить функциональность логирования (которую я в прототипе добавлять не стал).
Сама веб-морда выглядит так.

Класс Pump реализует ШИМ-управление насосом и ничего больше. Это не более чем обертка над стандартными методами ядра.
Класс Router намного интереснее. На схеме, как можно заметить, нет и намека на энкодер. Как же мы определяем, где находится золотник? Если коротко, то определяем примерно. Для этого нужно отсчитывать время между активациями мотора распределителя. Кроме того, я решил не заморачиваться с забиванием каких-либо настроек. Напротив, в коде реализована автокалибровка при старте устройства. Так что если конструкция изменится, а принцип — нет (равные расстояния между отверстиями), то код не нужно будет переписывать.
Собственно, калибровка происходит расчетом времени перемещения от начала до конца пути следования золотника. Затем время делится на отрезки между отверстиями и далее при перемещении к конкретному отверстию рассчитывается конкретный период включения мотора и направление движения. Концевики обрабатываются функциональными прерываниями, хотя на самом деле вполне можно опрашивать их состояние и раз в n миллисекунд — большой потери точности не будет.
И наконец, класс Machine включает в себя Pump и Router и управляет ими в соответствии с логикой работы девайса. А именно, задает последовательность перемещения распределителя и включения насоса, а также отслеживает время автоматического полива. В устройстве задан полив 6 растений, а седьмой вывод — сброс, чтобы избежать залития внутренностей роутера водой.
Самое интересное, что теперь главный файл состоит всего из пары вызовов функций!
Теперь осталось сделать только коробку под электронику и поместить насос в емкость для воды.
Итоговое устройство получилось немного аляповатым, но это не финальная ревизия, а заморачиваться мне не хотелось. Вот так оно работает. И правда работает! Правда, сайт почему-то не смог принять в себя гиф больше 8 мегабайт, так что кушаем что дают. В целом устройство перемещает золотник от первого отверстия к последнему где-то за минуту. Но позиционирование работает, и на том спасибо. Здесь я настроил на полив только 5-го горшка.


Но не все столь радужно. Перейдем к самокритике.
Как можно оценить данный проект? По сложности сборки — средняя сложность, плюс достаточно трудно достать под него «золотник», а потом его еще надо спаять и просверлить. Плюс нужна 3д печать, хоть это не такая уж проблема.
По функциональности. Задачу свою выполняет хорошо, но я не слишком рассчитал емкость для полива — в итоге он расходует ее за 2-4 использования. Если растения нуждаются в поливе раз в неделю, может и неплохо (заправлять раз в месяц), но если каждый день — печально. Есть вопросы к надежности погружного насоса — по отзывам мрут как мухи. Также, учитывая конструкцию, лучше сильно не опускать насос относительно рассады — вода может протечь в распределитель во время полива. В целом, это небольшая проблема при поливе мелкой рассады. Позиционирование при этом в целом удовлетворительное — некоторые положения не совсем соответствуют выводам для воды, но с текущим насосом это не проблема. Серьезных протечек он не создает.
По удобству использования — нет интеграции с серверным умным домом, шум при работе распределителя. Да, жужжит эта штука знатно, на ночь полив лучше не настраивать. Иногда, кстати, почему-то не грузится веб-морда, но мне кажется, это библиотека шалит (кто знает, подскажите, пожалуйста).
У меня уже есть мысли, как избавиться от редкого золотника, значительно улучшить надежность и точность позиционирования, а также интегрировать в умный дом. Во-первых, использование диафрагменного насоса. Во-вторых, стандартной водопроводной трубы и напечатанного золотника с резиновыми прокладками (исходная идея наизнанку). В-третьих, «выпрямить» конструкцию, чтобы привод распределителя находился сверху и не боялся бы протечек. Для определения положения реализовать оптический энкодер. По прикидкам, это значительно улучшит все параметры без сильного удорожания (можно еще добавить датчики влажности, но это уже даст некоторое удорожание). В ближайшее время попробую заняться. Есть и еще более продвинутая идея улучшения… Но о ней как-нибудь в другой раз.
В целом, считаю, мне удалось собрать модель, превосходящую по параметрам конструкцию Гайвера, и это было весело! Пришлось, правда,кое-кого продыря.. порыться в поиске гильз, но в итоге это того стоило. А вам желаю использовать свои «маслины» правильно! Не то, что некоторые…
Пролог
Начнем, пожалуй, с «вьетнамских флешбеков». Итак, пару лет назад мне на глаза попалось видео с канала AlexGyver об авоматическом поливе для комнатных растений на платформе Arduino. Видео с ютуба, пожалуй, не все смогут (или захотят) увидеть, потому вот соответствующая статья .Видео
Начну с плюсов. Первый — многоканальность полива. Второй — относительная простота реализации. Ну и… все.

Далее автор описывает, что у других все неоптимально, и пора сделать оптимально. Итого предлагает систему на 5 погружных насосов, 5 реле и интерфейс для настройки и управления — ардуино с символьным дисплеем и энкодером. Соответственно, расширяемость системы в N раз потребует увеличения затрат опять же в N раз (практически). Что если я скажу, что можно расширяться куда дешевле?
Интерлюдия
Мне пришла в голову мысль, что, вообще говоря, нам необязательно поливать все растения одновременно, ведь делать это нужно где-то раз в сутки. А если не нужна одновременность — зачем столько параллельных насосов? Я решил сделать систему с одним насосом и автоматической распределяющей системой на основе движущегося золотника.
В основе — недорогие компоненты: мотор-редуктор, помпа, микроконтроллер ESP8266 (как в умных розетках), пара реле и мосфет. Всё это управляет подачей воды по расписанию или через интернет. Корпус и механические детали я решил напечатать на 3D-принтере. Ну и гвоздь программы — золотник на основе гильзы пистолетного патрона. Да-да!

Все началось именно с него. Просто потому, что я живо у себя в голове представил устройство с движущейся гильзой и несколькими выводами под поливные шланги. Образ был настолько реален, что я незамедлительно приступил к разработке 3д модели распределителя.

Ничего не напоминает? Воображения мне хватило только чтобы сделать какое-то пистолетоподобное устройство с приводом в виде моторчика N20. Внутри устройства должен был двигаться поршень, который приводился бы в движения червячной передачей из строительной шпильки, проворачивающейся вокруг гайки M4.

Поршень же через другую шпильку передавал бы поступательное движение золотнику из гильзы, к которой с «естественного отверстия» подводилась бы вода, а с «искусственного» (просверленного в боку гильзы) она через отверстие в «стволе» поступала бы к выбранному растению. После печати я попробовал собрать устройство, но встретил сразу букет проблем.
Во-первых, гильза не хотела достаточно свободно двигаться в «стволе». Я несколько раз пробовал разные диаметры, и способы печати (вдоль, поперек). Я даже пробовал греть ствол при прохождении гильзы, чтобы она сама расширила себе отверстие. Это не работало. В итоге я все-таки нашел некий внутренний компромисс, чтобы гильза не сильно туго шла, но при этом достаточно плотно.
Во-вторых, я не придумал, как надежно соединить шпильку с золотником. Была идея напечатать некий переходник и склеить, но мне это показалось ненадежным. Повертев устройство в руках, я закинул его «в долгий ящик», пока вдохновение не вернется.

Кульминация
Прошел год… И снова мне на глаза попался этот проект. На этот раз я твердо решил закончить.
Во-первых, я стал гораздо лучше в пайке, поэтому первое, что пришло на ум для соединения шпильки и гильзы — пайка. Оставался вопрос, как все зафиксировать и припаять ровно. Ответ вас удивит. Нужен обычный старый добрый глазомер.

Гильзу я зажал в тиски, а шпильку максимально легонько придерживая, приставил сверху. Все предметы под действием силы тяжести тянет к земле. Но сейчас это плюс, потому что упрощает вертикальное позиционирование. А центровку я выполнил на глаз, целясь в центр выбитого капсюля. Для первой пайки железяк, считаю, вышло неплохо.
И да, собрав устройство в корпус, я убедился, что большого перекоса нет — гильза достаточно свободно ходила внутри.

Окрыленный успехом, я принялся за электронную часть. Схема устройства была собрана «из того, что было». А была парочка мосфетов, двойное реле и esp8266. И разумеется, паял на макетке. Ничего сложного нет ни в ее составлении, ни в ее сборке.


Сама схема довольно простая. Есть два концевика, которые сигнализируют о достижении поршня стенок девайса. Мосфет включает насос. Для насоса сделал еще повышайку, чтобы при желании увеличить мощность. Сдвоенное реле отвечает за управление ходом поршня распределителя. Стоит заметить, что такое использование компонентов не очень-то оптимальное, но об этом поговорим позднее.

Чтобы оживить схему, требуется прошивка микроконтроллера. Учитывая некоторую специфичность конструкции, с ней пришлось повозиться.
Я решил придерживаться ООП для лучшей организации кода и читаемости. В проекте присутствуют следующие классы: WebServer, DataStore, Pump, Router, Machine. Структурно они организованы следующим образом.

Итак, разберемся по порядку. Устройству нужна веб-морда для управления (я считаю, что это значительно удешевляет проект при сохранении эффективности). Для этого и существует WebServer. По сути класс основан на серверной библиотеке для ESP8266. Я заложил в код настройку периодичности полива, времени орошения каждого растения, а также мощность насоса.
#ifndef SERVER_H
#define SERVER_H
#include "DataStore.h"
#include <ESP8266WebServer.h>
class WebServer {
public:
WebServer(DataStore& datastore ): dataHandler(datastore) {
}
void begin() {
serv.begin();
serv.on("/", HTTP_GET, std::bind(&WebServer::handleRootPath, this));
serv.on("/save", HTTP_POST, std::bind(&WebServer::handleSaveSettings, this));
serv.on("/testall",HTTP_GET, std::bind(&WebServer::handleTestAll, this));
}
void handle() {
serv.handleClient();
}
private:
ESP8266WebServer serv;
DataStore& dataHandler;
void handleRootPath() {
serv.send(200, "text/html", dataHandler.getWebPage());
}
void handleSaveSettings() {
if (serv.hasArg("interval")
&&serv.hasArg("power")
&&serv.hasArg("water1")
&&serv.hasArg("water2")
&&serv.hasArg("water3")
&&serv.hasArg("water4")
&&serv.hasArg("water5")
&&serv.hasArg("water6"))
dataHandler.save(serv.arg("interval"),
serv.arg("power"),
serv.arg("water1"),
serv.arg("water2"),
serv.arg("water3"),
serv.arg("water4"),
serv.arg("water5"),
serv.arg("water6"));
}
void handleTestAll() {
Serial.println("test");
dataHandler.setWateringNow();
}
};
#endif
Класс DataStore реализует хранилище данных и FTP-сервер для доступа к файлам устройства. В первую очередь это нужно для хранения настроек, во вторую можно динамически менять оформление страницы настроек, закидывая другой файл index.html. Настройки хранятся в файле settings в формате js-переменных. Файл script.js отвечает за динамическое изменение значений при движении ползунков. Сервер при запросе отправляет index.html, добавляя в него содержимое файла настроек и скрипта. Ко всему, такая организация кода позволяет легко добавить функциональность логирования (которую я в прототипе добавлять не стал).
#ifndef DATASTORE_H
#define DATASTORE_H
#include <ESP8266FtpServer.h>
class DataStore {
public:
DataStore() {
}
void begin() {
root = "/";
SPIFFS.begin();
ftp.begin("engineer", "ftp_fs_begin");
settings="";
html = loadWebPageChunk("index.html");
script = loadWebPageChunk("script.js");
loadSettings();
}
const String getWebPage() {
String page = html+settings+script;
if (page="")
{
html = loadWebPageChunk("index.html");
script = loadWebPageChunk("script.js");
loadSettings();
}
return html+settings+script;
}
void handle() {
ftp.handleFTP();
}
int getInterval() {
return intervalWatering;
}
int getPumpPwm() {
return pumpPwm;
}
long getWateringTime(int index) {
return wateringTime[index];
}
void setWateringNow() {
isWateringNowSet = !isWateringNowSet;
}
bool isWateringNow() {
return isWateringNowSet;
}
bool save(
const String &interval, const String &power,
const String &water1,const String &water2,const String &water3, const String &water4,const String &water5,const String &water6) {
intervalWatering = strToIntervalWatering(interval);
pumpPwm = strToPumpPwm(power);
wateringTime[0] = strToWateringTime(water1);
wateringTime[1] = strToWateringTime(water2);
wateringTime[2] = strToWateringTime(water3);
wateringTime[3] = strToWateringTime(water4);
wateringTime[4] = strToWateringTime(water5);
wateringTime[5] = strToWateringTime(water6);
return storeSettings(
interval, power,
water1, water2, water3, water4, water5, water6);
}
static unsigned long strToIntervalWatering(const String &interval) {
return interval.toInt()*86400ul;
}
static int strToPumpPwm(const String &power) {
return (float)(power.toInt()*1023)/100;
}
static long strToWateringTime(const String &wateringTime) {
return wateringTime.toInt()*1000ul;
}
private:
bool storeSettings (
const String &interval, const String &power,
const String &water1,const String &water2,const String &water3, const String &water4,const String &water5,const String &water6) {
String path = root+"settings.js";
File file = SPIFFS.open(path, "w");
settings = (String)"<script>\n"
+"var interval = "+interval+";\n"
+"var power = "+power+";\n"
+"var water1 = "+water1+";\n"
+"var water2 = "+water2+";\n"
+"var water3 = "+water3+";\n"
+"var water4 = "+water4+";\n"
+"var water5 = "+water5+";\n"
+"var water6 = "+water6+";\n"
+"</script>";
int bytesWritten = file.print(settings);
file.close();
if (bytesWritten>0)
return true;
else
return false;
}
bool loadSettings() {
String path = root+"settings.js";
File file = SPIFFS.open(path, "r");
if (!file) {
Serial.println("Error opening file for reading");
return false;
}
String openTag = file.readStringUntil('\n');
String buf;
String interval = file.readStringUntil('\n');
buf = getValue(interval,'=',1);
buf.replace(";", "");
intervalWatering = strToIntervalWatering(buf);
String power = file.readStringUntil('\n');
buf = getValue(power,'=',1);
buf.replace(";", "");
pumpPwm = strToPumpPwm(buf);
String water1 = file.readStringUntil('\n');
buf = getValue(water1,'=',1);
buf.replace(";", "");
wateringTime[0] = strToWateringTime(buf);
String water2 = file.readStringUntil('\n');
buf = getValue(water2,'=',1);
buf.replace(";", "");
wateringTime[1] = strToWateringTime(buf);
String water3 = file.readStringUntil('\n');
buf = getValue(water3,'=',1);
buf.replace(";", "");
wateringTime[2] = strToWateringTime(buf);
String water4 = file.readStringUntil('\n');
buf = getValue(water4,'=',1);
buf.replace(";", "");
wateringTime[3] = strToWateringTime(buf);
String water5 = file.readStringUntil('\n');
buf = getValue(water5,'=',1);
buf.replace(";", "");
wateringTime[4] = strToWateringTime(buf);
String water6 = file.readStringUntil('\n');
buf = getValue(water6,'=',1);
buf.replace(";", "");
wateringTime[5] = strToWateringTime(buf);
String closeTag = file.readStringUntil('\n');
settings = openTag+'\n'
+interval+'\n'
+power+'\n'
+water1+'\n'
+water2+'\n'
+water3+'\n'
+water4+'\n'
+water5+'\n'
+water6+'\n'
+closeTag;
file.close();
if (settings.length()>0)
return true;
else
return false;
}
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = {0, -1};
int maxIndex = data.length()-1;
for(int i=0; i<=maxIndex && found<=index; i++){
if(data.charAt(i)==separator || i==maxIndex){
found++;
strIndex[0] = strIndex[1]+1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}
const String loadWebPageChunk(const String& filename) {
String path = root+filename;
File file = SPIFFS.open(path, "r");
if (!file) {
Serial.println("Error opening file for reading");
return "";
}
String data = file.readString();
file.close();
return data;
}
String root;
String settings;
String script;
String html;
unsigned long intervalWatering = 30;
int pumpPwm = 512;
long wateringTime[6] = {1000, 1000, 1000, 1000, 1000, 1000};
bool isWateringNowSet = false;
FtpServer ftp;
};
#endif
Сама веб-морда выглядит так.

Класс Pump реализует ШИМ-управление насосом и ничего больше. Это не более чем обертка над стандартными методами ядра.
#ifndef PUMP_H
#define PUMP_H
#include <Arduino.h>
class Pump {
public:
Pump() {
}
Pump(byte digiPin) {
pin = digiPin;
};
void water(unsigned long workTime, int pwm) {
unsigned long t1 = millis();
while(millis()-t1 < 100) {
yield();
}
t1 = millis();
while(millis()-t1 < workTime) {
analogWrite(pin, pwm);
yield();
}
analogWrite(pin, 0);
t1 = millis();
while(millis()-t1 < 100) {
yield();
}
};
private:
byte pin;
};
#endif
Класс Router намного интереснее. На схеме, как можно заметить, нет и намека на энкодер. Как же мы определяем, где находится золотник? Если коротко, то определяем примерно. Для этого нужно отсчитывать время между активациями мотора распределителя. Кроме того, я решил не заморачиваться с забиванием каких-либо настроек. Напротив, в коде реализована автокалибровка при старте устройства. Так что если конструкция изменится, а принцип — нет (равные расстояния между отверстиями), то код не нужно будет переписывать.
#ifndef ROUTER_H
#define ROUTER_H
#include <Arduino.h>
#include <FunctionalInterrupt.h>
//static volatile int pos = -1;
class Router {
public:
Router() {
}
Router(byte frontMotorPin, byte backMotorPin, byte upSwitchPin, byte downSwitchPin) {
commandsWithoutCalib = 0;
this->frontMotorPin = frontMotorPin;
this->backMotorPin = backMotorPin;
this->upSwitchPin = upSwitchPin;
this->downSwitchPin = downSwitchPin;
}
void begin() {
pinMode(frontMotorPin, OUTPUT);
pinMode(backMotorPin, OUTPUT);
pinMode(upSwitchPin, INPUT);
pinMode(downSwitchPin, INPUT);
if (!calibrate())
calibrate();//перекалибровка если измерить dt не вышло
}
int getPos() {
return pos;
}
bool calibrate() {
digitalWrite(frontMotorPin, HIGH);
digitalWrite(backMotorPin, HIGH);
if (digitalRead(upSwitchPin)) {
goToUpPos();
}
unsigned long t0 = millis();
goToDownPos();
dt = (millis() - t0)/5;
if (dt<=100)
return false;
commandsWithoutCalib = 0;
Serial.print("dt=");
Serial.println(dt);
Serial.print("Position is ");
Serial.println(pos);
return true;
}
int move(int targetPos) {
if (targetPos<0 || targetPos>5)
return -1;
if (targetPos == pos)
return pos;
int deltaPos = targetPos - pos;
byte pin = frontMotorPin;
if (deltaPos<0){
deltaPos = -deltaPos;
pin = backMotorPin;
}
attachInterrupt(upSwitchPin, std::bind(&Router::upPos,this), FALLING);
attachInterrupt(downSwitchPin, std::bind(&Router::downPos,this), FALLING);
unsigned long t0 = millis();
unsigned long t1 = 0;
while(t1 < dt*deltaPos) {
digitalWrite(pin, LOW);
t1 = millis()-t0;
pos = -1;
if ((pos==0 || pos==5) && t1>1000)
break;
yield();
}
digitalWrite(pin, HIGH);
commandsWithoutCalib++;
detachInterrupt(upSwitchPin);
detachInterrupt(downSwitchPin);
if (dt*deltaPos - t1<dt*0.05) {
pos = targetPos;
return pos;
} else
return -1;
}
int getNumCommandsWithoutCalib() {
return commandsWithoutCalib;
}
uint32_t deltaT() {
return dt;
}
private:
// void goToEdgePos(byte edgePin, byte motorPin, int target) {
// attachInterrupt(edgePin, upPos, FALLING);
// while (pos!=target) {
// digitalWrite(motorPin, LOW);
// yield(); //interrupt!
// }
// detachInterrupt(edgePin);
// digitalWrite(motorPin, HIGH);
// }
void goToUpPos() {
attachInterrupt(upSwitchPin, std::bind(&Router::upPos,this), FALLING);
while (pos!=5) {
digitalWrite(frontMotorPin, LOW);
yield();
}
detachInterrupt(upSwitchPin);
digitalWrite(frontMotorPin, HIGH);
}
void goToDownPos() {
attachInterrupt(downSwitchPin, std::bind(&Router::downPos,this), FALLING);
while (pos!=0) {
digitalWrite(backMotorPin, LOW);
yield(); //interrupt!
}
detachInterrupt(downSwitchPin);
digitalWrite(backMotorPin, HIGH);
}
IRAM_ATTR void upPos() {
pos = 5;
}
IRAM_ATTR void downPos() {
pos = 0;
}
uint32_t dt = 0;
volatile int pos = -1;
int commandsWithoutCalib = 0;
byte frontMotorPin;
byte backMotorPin;
byte upSwitchPin;
byte downSwitchPin;
};
#endif
Собственно, калибровка происходит расчетом времени перемещения от начала до конца пути следования золотника. Затем время делится на отрезки между отверстиями и далее при перемещении к конкретному отверстию рассчитывается конкретный период включения мотора и направление движения. Концевики обрабатываются функциональными прерываниями, хотя на самом деле вполне можно опрашивать их состояние и раз в n миллисекунд — большой потери точности не будет.
И наконец, класс Machine включает в себя Pump и Router и управляет ими в соответствии с логикой работы девайса. А именно, задает последовательность перемещения распределителя и включения насоса, а также отслеживает время автоматического полива. В устройстве задан полив 6 растений, а седьмой вывод — сброс, чтобы избежать залития внутренностей роутера водой.
#ifndef MACHINE_H
#define MACHINE_H
#include "Pump.h"
#include "Router.h"
#include "DataStore.h"
class Machine {
public:
Machine(Router &router, Pump &pump, DataStore &datastore, int routeWithoutCalib = 5) :
router(router),
pump(pump),
dataHandler(datastore),
routeWithoutCalib(routeWithoutCalib) {
}
void handle() {
if (dataHandler.isWateringNow()) {
duty();
dataHandler.setWateringNow();
}
unsigned long seconds = (millis()/1000ul)%dataHandler.getInterval();
if (seconds == 0) {
duty();
}
}
private:
void duty() {
if (router.getNumCommandsWithoutCalib() >= routeWithoutCalib)
router.calibrate();
int start = 0;
int end = 5;
int dir = 1;
if (router.getPos() == 5) {
start = 5;
end = 0;
dir = -1;
}
for (int pos = start;pos <= end;pos += dir) {
router.move(pos);
pump.water(dataHandler.getWateringTime(pos), dataHandler.getPumpPwm());
yield();
}
}
int routeWithoutCalib;
Router& router;
Pump& pump;
DataStore& dataHandler;
};
#endif
Самое интересное, что теперь главный файл состоит всего из пары вызовов функций!
#include <ESP8266WiFi.h>
#include "WebServer.h"
#include"Machine.h"
const char* ssid = "#####";
const char* password = "****";
DataStore datastore = DataStore();
WebServer webServer = WebServer(datastore);
Pump pump = Pump(D2);
Router router = Router(D1, D0, D5, D6);
Machine machine = Machine(router, pump, datastore);
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to "); // "Подключились к "
Serial.println(ssid);
Serial.print("IP address: "); // "IP-адрес: "
Serial.println(WiFi.localIP());
SPIFFS.begin();
datastore.begin();
webServer.begin();
router.begin();
}
void loop() {
machine.handle();
webServer.handle();
datastore.handle();
}
Теперь осталось сделать только коробку под электронику и поместить насос в емкость для воды.
Итоговое устройство получилось немного аляповатым, но это не финальная ревизия, а заморачиваться мне не хотелось. Вот так оно работает. И правда работает! Правда, сайт почему-то не смог принять в себя гиф больше 8 мегабайт, так что кушаем что дают. В целом устройство перемещает золотник от первого отверстия к последнему где-то за минуту. Но позиционирование работает, и на том спасибо. Здесь я настроил на полив только 5-го горшка.


Но не все столь радужно. Перейдем к самокритике.
Развязка
Как можно оценить данный проект? По сложности сборки — средняя сложность, плюс достаточно трудно достать под него «золотник», а потом его еще надо спаять и просверлить. Плюс нужна 3д печать, хоть это не такая уж проблема.
По функциональности. Задачу свою выполняет хорошо, но я не слишком рассчитал емкость для полива — в итоге он расходует ее за 2-4 использования. Если растения нуждаются в поливе раз в неделю, может и неплохо (заправлять раз в месяц), но если каждый день — печально. Есть вопросы к надежности погружного насоса — по отзывам мрут как мухи. Также, учитывая конструкцию, лучше сильно не опускать насос относительно рассады — вода может протечь в распределитель во время полива. В целом, это небольшая проблема при поливе мелкой рассады. Позиционирование при этом в целом удовлетворительное — некоторые положения не совсем соответствуют выводам для воды, но с текущим насосом это не проблема. Серьезных протечек он не создает.
По удобству использования — нет интеграции с серверным умным домом, шум при работе распределителя. Да, жужжит эта штука знатно, на ночь полив лучше не настраивать. Иногда, кстати, почему-то не грузится веб-морда, но мне кажется, это библиотека шалит (кто знает, подскажите, пожалуйста).
У меня уже есть мысли, как избавиться от редкого золотника, значительно улучшить надежность и точность позиционирования, а также интегрировать в умный дом. Во-первых, использование диафрагменного насоса. Во-вторых, стандартной водопроводной трубы и напечатанного золотника с резиновыми прокладками (исходная идея наизнанку). В-третьих, «выпрямить» конструкцию, чтобы привод распределителя находился сверху и не боялся бы протечек. Для определения положения реализовать оптический энкодер. По прикидкам, это значительно улучшит все параметры без сильного удорожания (можно еще добавить датчики влажности, но это уже даст некоторое удорожание). В ближайшее время попробую заняться. Есть и еще более продвинутая идея улучшения… Но о ней как-нибудь в другой раз.
В целом, считаю, мне удалось собрать модель, превосходящую по параметрам конструкцию Гайвера, и это было весело! Пришлось, правда,

Самые обсуждаемые обзоры
«Вы не обязаны не держать глаза незакрытыми»
Мне было просто лень с лейкой прыгать, поэтому я сделал вообще просто.
Моторчик от стеклоомывателя, трубочки, форсунки, регулятор струек, выключатель и бачок :)
pikabu.ru/story/prosteyshaya_sistema_poliva_rasteniy_9043293?utm_source=linkshare&utm_medium=sharing
pikabu.ru/story/prodolzhenie_posta_prosteyshaya_sistema_poliva_rasteniy_9130674?utm_source=linkshare&utm_medium=sharing
А зачем тогда сквозняк?
Какое-то p-n-p устройство :)
Надо взять.
Впрочем, если уж делать клапан-переключатель — то я бы, пожалуй, предпочёл классическую конструкцию — шток в виде толстостенной трубки, в ней две проточки под о-ринги, между ними — отверстие для выхода воды. Ну и двигал бы сервой, пожалуй.
А ещё есть mysku.club/blog/diy/103035.html — с такой стоимостью можно, пожалуй, с клапанами и голову не морочить…
Хотя с третей стороны на гравитационную подачу можно поставить расходометр.
пс как перестать считать проезжающие машины на гифке?
Автоматика и ардуины мне не нужны, а вот «механика» интересная.
«Погружной» можно сделать плавающим — на пенопластовом кружечке (такие в реальности 3кВт плавают — откачка из подтопляемых подвалов), и пластик-бутыль с широким горлом есть для этого, от 3-5-10 литров
Тоже периодически думаю о таком устройстве, но мне кажется здесь куда разумнее по соленоиду поставить на каждую линию и открывать их по очереди.
А от шума можно избавиться если взять перистальтическую помпу, или вообще убрать помпу из уравнения поставив бак повыше.
Достаточно было Sonoff (или практически любой «умной» розетки на W600/W800/etc) поставить с Tasmota/ESPhome…
( В корпусе дефендер — зарядка/ акум. 18650/ повышайка до 9 в. Ну и индикатор зарядки)
Ну а фигали нам, ардуины нет, принтеры только эпсон фото и лазерный, програмировать " этим вашим хитростям не обучен", а так " наши руки не для скуки… " )))
Все гораздо проще… один насос и капельный полив… Длительность и частота подбирается экспериментально и все равно не угадаете… необходимо контролировать. ( идеальная это реверсивный полив)Для домашних цветов терпимо, а вот для урожая в теплице мало эффективная система.
Лично у меня организовано через телеграм бот. на есп 8266 и есп 32. Возможности принудительно вкл\выкл некое устройство, по команде вывод информации о наличии воды в емкости, а также наличие доп освещения, снятие с датчиков данные о влажности, темпы и атм давления.При событиях отсутствие\наличие воды, вкл\ выкл освещения шлется информация в телегу.
Полив организован через внешний таймер и при вкл\ выкл насоса шлет сообщение.
даже при таком уровне автоматизации происходят форс мажоры нужно в каждый горшек вставлять датчик влажности почвы с сигнализацией( иногда форсунки забиваются и вода не поступает растению)
Поливать «ровно столько сколько нужно » не получиться, потому что нужно поливать с избытком… куда избыток влаги девать?
на сопляхмодулями. Только прошивку с нуля не писал: поставил Tasmota, всем управлял с роутера из crontab. Обычно перед каждый отпуском всё это достаётся и всегда надо что-то поправлять.А можно было обойтись вообще без него используя лишь великий закон гравитации + 1 клапан на 12-220в + умную розетку с таймером за 3-5 баксов… Индивидуальность каждого канала легко делается копеечными "«системами» из аптеки, с масштабируемостью так же, ноль проблем.
Ну и датчики, понятно, нужны в любом случае — кроме, собственно, контроля правильного объёма полива сигнализация нужна, учитывая, что собираем из китайских дендрофекалий.
А если серьёзно, то нужно учитывать качество компонентов и вероятность их отказа.
Если клапан не закроется до конца — «гравитационный» полив может подтопить соседей.
Если насос будет плохо качать — будет просто недополив. Совсем перестанет работать — не факт что растения успеют засохнуть.
Из того что читал: капельный полив оказался лучше чем всякие сенсоры почвы (не надежные и показывающие погоду на марсе). Хотите равномерный полив — ставьте контроллер, клапан на каждое растение (нагнетаем давление и открываем первый, повторяем n-раз). Еще вариант подводить воду в начале, в конце и середине шланга или использовать разные диаметры труб или разные диаметры форсунок.
Имхо, один из лучших проектов как по железу и чистоте кода — github.com/SasaKaranovic/HousePlantMonitoringSystem
В гидропонике, кстати, корневая гниль вполне является проблемой. Там, правда, её химией гасят.
Охлаждать… что-то мне кажется, что химия дешевле, но зарекаться не буду — не интересовался. В любом случае, залить до гнили не то чтобы сложно, а риск большой, проще «в минус» отрегулировать.
Автор же применил способ менять производительность насоса напряжением… для времени полива 1-2 минуты… и применил сложный механизм распределения воды ну куда проще поставить вот такую капельницу на 2\4 растения?
Напомнило сказку про кашу из топора.
Но круто)
Система инфузионная 200 руб на 10 растений
www.ozon.ru/product/sistema-infuzionnaya-medway-10-sht-up-dlya-kapelnitsy-dlya-vlivaniya-rastvorov-s-plastikovym-866777627
Подводящую трубку просто взять подлиннее и загнуть петлёй, в пределах оборота пусть себе скручивается.
Я лично для полива разным объёмом воды разных растений (разный объём горшка; кроме того, при поливе через одну трубку с тройниками в начале магистрали выливается больше, в конце может вообще не быть воды из-за её расхода) использовал несколько моторчиков. Ещё я тестировал вот такое:
На момент тестирования они вообще обходились в <60 рублей за штуку. Идея была в том, что один насос создаёт давление в магистрали (или наполняет ёмкость для полива «самотёком»), а клапана стоят на ответвлениях и включаются последовательно для полива каждого горшка. Минус в том, что если их размещать у растения — к каждому надо тянуть провода. А если их размещать в одном месте, то преимущество перед пачкой насосов было одно: цена. С другой стороны, я использовал только на время отпусков и все растения стояли в «корытах» (строительные), чтобы было куда вытекать воде и точно ничего не залить, если что пойдёт не так.
Насосы обходились (в 2020 году) в 139 рублей при покупке 21 штуки (под купон) с доставкой:
Клапана как я сказал, были тогда менее 60 рублей (плюс доставка), т. е. примерно в два раза дешевле.
Минус — и те, и другие имеют ограниченный срок службы даже в мягкой воде, так что надо быть готовым их менять. А в жёсткой я даже и не представляю… Я бы там вообще делал полив самотёком из ёмкости с одним клапаном от стиралки/посудомойки, регулируя объём зажимами капельниц.
Клапан или насос заменить (при наличии зипа) — считанные минуты. И купить не проблема.
Не уверен, хватит ли мелкой сервы на вращение золотника. Герметичного, в отличие от показанного выше варианта. И её покупать надо, когда шаговик можно выдрать из хлама. Но да, серва тут самое разумное решение, сама делает всё что надо.
Все отлично работало у человека.
Впрочем, раз есть сторонники у обоих методов то, полагаю, если не пытаемся выжать всё из чего-нибудь вроде теплицы, можно использовать любой… Мне лично капля не нравится ровно двумя вещами — большая капризность и неудобство сопряжения с сенсором. А сенсор я хочу иметь хотя бы как защиту от дурака — от «забыли воду налить в ёмкость» до «нагрели помещение до 35 и всё высыхает мгновенно».
1. Гниют и и умирают
2. Показания очень зависят от многих фактов (типа почвы, ее плотности и тд).
Показания — да, надо калибровать в конкретном горшке. Но это (если температура более-менее стабильная) делается один раз.
Я просто редкостный склеротик, и у меня это единственный вариант, чтобы что-то росло. Но у меня всё тупо — четыре насоса, четыре датчика, ардуина с прошивкой гитхаба. Два лимона, два ящика с травами.
Пивной балон + системы капельницы с аптеки сколько там вам надо и вопрос закрыт. Визуальный кнтроль, контроль вода кончилась в балоне, долейте и все.
И вообще — что за страх простейшей и дешёвой электроники?
А уверены, что банальный емкостной работать не будет? Если разница в весе рукой ощущается — то вроде как воды достаточно много, должен бы…
А нелюбовь к постоянным нагрузкам как проявляется?
https://aliexpress.com/item/1005007038268573.html — резистивный
https://aliexpress.com/item/1005005202930632.html — емкостный.
Оно сгибается со временем, то есть показания постоянно плывут. И если не снять нагрузку отсносительно быстро — то к нулю может и не
вернуться. Может, сделано паршиво, но выбор этих мостиков на умеренные ангрузки никудышный.
Исполнение выглядит относительно многообещающе
По поводу тензо, на правах бреда: сделать площадку на пружинках, регулируемый по высоте микрик под площадку. Но как подумаю, что всё это 130 раз повторять придётся, аж вздрогну. Дешевле ту, которая это хозяйство заводила, заставить их себе забрать. Но это уже совсем другая история.
Мембранный насос качает по времени Дальше стоит капельница со стабилизированным расходом воды. Время полива и частота подбирается экспериментально
Вам проще поддерживать влажность помещения чуть выше средней, ни разу не слышал чтобы в тайских орхидариумах их кто то поливал.
Во-первых, ваша «Тытруба» недоступна у нас в России, в моём регионе точно. И не надо учить дедушку кашлять. Работает только Tor, но с его тормозами и его нафик, сгодится только когда что-то надо посмотреть как отремонтировать…
Во-вторых, многоканальный полив грядок клубники и огурцов с помидорами — это фиаско. У меня 1/4 куба с высоты 1,5 м самотёком, без моторчиков не справляется. Я замумукался на коленках ползать и регулировать капельницы. Отказался, распродал всё.
Ваша тема годится наверное только для 5-ти лучевого на подоконнике, тут программирование точно зайдёт.
Если не лень повесьте клапан за пару баксов и умную розетку за 3-5.
поэтому нужно или насос эл клапан… или руками перекрывать
А можно было взять два готовых строенных электроклапана от старых стиралок-автоматов и не париться с механикой наколеночного изготовления.
А вообще, слишком много
дурацкихкартинок и разговоров про гильзу, хотя её роль в этом проекте явно не основная.Выложили бы фото своей исходной гильзы от травмата и всё ясно было бы, вместо многочисленных бессмысленных картинок с какой-то рожей из компьютерной игры и подписями про маслины. На первой из них, кстати, обычный парабеллумовский патрон 9×19, но это явно не Ваш случай.
Получается что пластиковая трубка просто внутрь вставлена. Ненадёжно механически и герметичность непонятная даже если трубка с подгрызом пластика (судя по фото) вставлена…
Лучше уж подходящую гильзу с дульцем подобрать и уже на дульце пластиковую трубку с натягом одевать.
для задач автора — да.
Ой, да ладно вам, уже и подурачиться нельзя
а вот то, что гильза может иметь небольшую конусность, может приводить к
Бачок омывателя от газели с моторчиком — 500р и умное реле в розетке через которое включается бп от старой мобилы на 5в (на 12 омыватель слишком сильно качает).
Реле устанавливаю на минуту раз в сутки-двое
Добавил краников потом уже на три горшка с регулировкой. А до этого ставил горшки на разную высоту чтоб кто выше тому меньше доставалось. Можно и изгибом шланга регулировать. Система настолько удачная что два года работала и все забилось нахрен плесенью и зацвело. Потому что никто не трогал не чистил не мыл. Тока воды подливали
Хотя в системах полива кстати все это зарастает зеленью мгновенно, даже не медное.
У меня, впрочем, оно вообще автономное, для начала надо хотя бы просто еспшку какую прицепить.
При наличии нормального инструмента на месте выбитого капсюля сверлится отверстие, в нем нарезается резьба, в неё вворачивается на краску шпилька. Всё.
И да, гильза не ТруЪ. Должна быть латунная.
wildberries.ru/catalog/197161121/detail.aspx
Работает на удивление неплохо при всей дешевизне компонентов. Количество воды для разных растений регулируется количеством шлангов, главное чтоб все были одинакового сечения. Правда, у меня она постоянно запитана от БП, комплектный аккум больше как буфер работает.
В целом, опять же можно в неё добавить еспшку с россыпью сенсоров и заменить тупой таймер умным алгоритмом, но чесслово — оно и так нормально
Я изначально пошел по пути насос->расходомер->распределитель.
Вот одна из ранних систем распределителя на шприце (сложно в изготовлении):
Далее делал и такой изврат (тоже сложно в изготовлении):
И пришел к банальным клапанам (просто в изготовлении):
Еще было несколько извратов с распределением воды, поскольку готовлю статью по этому делу не буду все сюда кидать :)
disk.yandex.ru/i/xcIp5t2h2l8Myw
disk.yandex.ru/i/KzB3QG4Tvzi1LA
disk.yandex.ru/i/LV1OYB3ryh8x-g