Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Детектор утечки воды и управление клапаном

Компоненты и расходные материалы

Алюминиевый корпус
× 1
Arduino UNO
× 1
Arduino Ethernet Shield 2
× 1
Источник питания
× 1
Корпус переменного тока
× 1
Комплект светодиодов с резисторами
× 1
Реле (1 двойное 5 В и 1 двойное 12 В)
× 1
Моторизованный клапан
× 1
соединители JST
× 1
Датчик воды
× 1

Об этом проекте

Обзор

Во время разговора с другом я понял, что утечки воды - большая проблема. Моему другу пришлось заменить всю мебель в подвале только потому, что на работе сломалась труба.

Этот проект похож на тот, который я опубликовал для конкурса Microsoft IoT, но он основан на Arduino, а не на Raspberry. Моя точка зрения такова:вместо того, чтобы централизовать многие обязанности на большой платформе (например, RasPi, DragonBoard или ПК), я предпочитаю делегировать простые обязанности перед простыми устройствами (такими как Arduino и другие). Они будут делать то, что должны делать, и, как вариант, они будут подключаться по сети к другим (простым или сложным) устройствам, чтобы предлагать расширенные услуги. В случае сбоя сети они продолжают делать то, что должны.

По сути, он отслеживает утечки воды и запускает такие действия, как закрытие основного входа воды, в зависимости от обнаруженной неисправности.

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

Вот как это выглядит:

Основной водозабор расположен снизу. Первое устройство устанавливается городскими службами водоснабжения для контроля давления воды. Деталь я установил вверху картины. Моторизованный клапан (синий) устанавливается параллельно с ручным клапаном. На этом чертеже ручной клапан открыт, а клапан с электроприводом, следовательно, обойден. Это полезно при отключении электричества. В нормальном режиме ручной клапан должен быть отключен.

Внутри клапана находится двигатель постоянного тока (12 В), который вращается по или против часовой стрелки в зависимости от полярности. Существует петля обратной связи, которая показывает, включен или выключен клапан. Чтобы включить его, просто подайте положительное напряжение на верхнее левое соединение.

Вот контроллер:

Слева направо:вилка переменного тока, кнопка сброса, несколько светодиодов для отображения состояний, разъемы (к датчикам, к двигателю), интерфейс Ethernet и USB.

  • LED1 :Постоянный красный =вода обнаружена локально, мигающий красный =вода обнаружена удаленно, не горит =утечки нет.
  • Светодиод 2 :Постоянный желтый =невозможно управлять клапаном с электроприводом, мигающий желтый =невозможно связаться с брокером MQTT, не горит =все в порядке
  • LED3 :Постоянный синий =все в порядке, мигающий синий =клапан с электроприводом закрыт Не горит =система не работает или не получает питание

Вот датчик, расположенный там, где, как мне кажется, может протекать вода:

Вот что находится под капотом:

ПРЕДУПРЕЖДЕНИЕ!

Источник питания переменного / постоянного тока, который я использую, имеет два выхода:первый - 12 В постоянного тока и используется для питания моторизованного клапана (управляется двумя реле, которые контролируют вращение двигателя), а второй - ТОЧНО 5 В постоянного тока для питания Ардуино. Вот почему я питаюсь напрямую от цепи 5 В, а не от Vin, для которого требуется как минимум 6 В постоянного тока. После подключения переменного / постоянного тока вам НИКОГДА (я сказал НИКОГДА) не подключайте ни разъем Arduino DC, ни USB-кабель Arduino. Если вы все еще хотите отладить через USB, установите самодельный кабель БЕЗ линий электропередач, оставьте только линии данных. Между прочим, связь между корпусом переменного тока и источником питания переменного / постоянного тока составляет 110 В. Никогда не трогайте!

Код

  • Обнаружение утечки воды и управление клапанами с электроприводом
  • Библиотека MQTT
Обнаружение утечки воды и управление клапанами с электроприводом Arduino
 #include  #include  #include  #include  #include  #include  #include  / * Вот как работает HW Здесь есть три подсистемы:- основной блок:- Arduino Uno с экраном Ethernet - красный светодиод:горит постоянно при обнаружении воды, локально мигает при обнаружении воды удаленно, в противном случае не горит - желтый светодиод:горит, когда клапан неисправен, мигает, когда брокер MQTT недоступен (по любой причине), не горит в противном случае - синий светодиод:горит, когда клапан открыт и система отслеживает утечки, мигает, когда клапан выключен система не работает - кнопка:при нажатии запускается самотестирование - двойное реле для управления дистанционным клапаном с электроприводом - другое двойное реле для определения концевых выключателей открытия / закрытия, установленных на удаленном клапане - набор воды детекторы (все параллельно) (все 3 разъема на передней панели подключены параллельно) Моторизованный клапан имеет следующие разъемы:- желтый и B lue:постоянный ток для питания двигателя - Черный:вход концевых выключателей (в нашей схеме будет установлен на GND) - Красный =переключится на GND, когда клапан достигнет своего полностью закрытого положения (примечание:из-за внутренней конструкции концевого выключателя , нет гарантии, что непрерывность останется после выключения клапана) - Зеленый =переключится на GND, когда клапан достигнет своего полностью открытого положения (примечание:из-за внутренней конструкции концевого выключателя нет гарантии, что непрерывность останется после клапана, если питание отключено) * /// Networkbyte mac [] ={0xDE, 0xAD, 0xBE, 0xCF, 0xFC, 0xEE}; // MAC-адрес Arduino IPAddress ip (192, 168, 12, 215); // IP-адрес Arduino IPAddress server (192, 168, 12, 130); // Адрес брокера MQTTEthernetClient ethClient; // Клиент MQTT PubSubClient (ethClient); #define mqttClientPrefix "GLX" // Префикс для использования любой публикации / подписки MQTT #define mqttClientLocation "BASEMENT" // Вторая часть идентификатора клиента # define mqttClientUID "001" // Последняя часть идентификатора клиента # define mqttClientStatusTopic "Status" // Тема, которая будет использоваться для публикации статуса устройства #define mqttClientFaultTopic "Fault" // Тема, которая будет использоваться для публикации / подписки на Faultsconst int mqttInterval =20; // определяет, как часто система будет сообщать брокеру MQTT (т.е. каждые mqttInterval * mainLoopDelay мс) int mqttIntervalCnt =0; // локальная переменная, используемая для обратного отсчета int isConnectedToBroker =-1; // 1 при подключении, -1 =неизвестно, 0 =невозможно подключиться // Pin-outconst int SystemLedPin =A0; // Синий светодиод const int FaultLedPin =A1; // Желтый светодиод const int AlarmLedPin =A2; // Красный светодиод const int WaterDetectorPin =2; // переходит в НИЗКИЙ при обнаружении воды, в противном случае - до VCCconst int ToggleButtonPin =3; // переходит в НИЗКИЙ, когда кто-то нажимает на кнопку, а затем переходит в ВЫСОКИЙ, когда кнопка отпускается, в противном случае - в НИЗКИЙ, когда кто-то нажимает кнопку; // SD-карта на шилде Ethernet, не используется const int ValveClosedPin =5; // переходит в НИЗКИЙ, когда двигатель достигает предела замкнутого переключателя, в противном случае подтягивается до ВЫСОКОГО значения int ValveOpenedPin =6; // переходит в НИЗКИЙ, когда двигатель достигает предела разомкнутого переключателя, в противном случае подтягивается до HIGHconst int ValveControl1 =8; // для управления первым реле, которое управляет источником питания моторизованного клапанаconst int ValveControl2 =7; // для управления вторым реле, которое управляет источником питания моторизованного клапана // Обратите внимание, не используйте D10, D11, D12 и D13, поскольку эти контакты зарезервированы для экрана Ethernet // WaterLeakage (local) int isWaterDetected =0; // статус по последнему удачному чтению // WaterLeakage (remote) int isWaterDetectedRemotely =0; // статус согласно сообщениям, полученным от других устройств мониторинга // Моторизованный клапанint isValveClosed =-1; // состояние клапана с электроприводом (-1 =неизвестно, 0 =открыто, 1 =закрыто)) const int valveTimeOut =15; // в секундах максимальное время, разрешенное для открытия или закрытия клапана int isConnectedToValve =-1; // 0, если система не может управлять клапаном с электроприводом, 1 =подключено, -1 =неизвестно // Кнопка СБРОС вручную энергозависимое логическое значение isResetRequested =0; // это изменится, когда кнопка вызовет прерывание // Logicconst int mainLoopDelay =500; // фиксированная задержка в основном цикле в msvoid (* resetFunc) (void) =0; // Инициализация void setup () {wdt_disable (); // всегда удобно отключить, если он был включен или вам нужно время инициализации Serial.begin (9600); Serial.println (F («Начало настройки»)); // Настройка аппаратного обеспечения pinMode (SystemLedPin, OUTPUT); pinMode (FaultLedPin, ВЫХОД); pinMode (AlarmLedPin, ВЫХОД); pinMode (WaterDetectorPin, ВХОД); pinMode (ToggleButtonPin, ВХОД); pinMode (ValveOpenedPin, ВХОД); // Реле 12 В постоянного тока по умолчанию не работает. Контакт подключен к нормально разомкнутой стороне реле 1, но есть подтяжка. Таким образом, PIN по умолчанию ВЫСОКИЙ. pinMode (ValveClosedPin, ВХОД); // Реле 12 В постоянного тока по умолчанию не работает. Контакт подключен к нормально разомкнутой стороне реле 2, но есть подтяжка. Таким образом, PIN по умолчанию ВЫСОКИЙ. pinMode (ValveControl1, ВЫХОД); digitalWrite (ValveControl1, HIGH); // Реле 1 постоянного тока 5 В по умолчанию неактивно, т.е. двигатель подключен к GND pinMode (ValveControl2, OUTPUT); digitalWrite (ValveControl2, HIGH); // Реле 2 5V DC по умолчанию не работает, т.е. двигатель подключен к GND pinMode (SdCardPin, OUTPUT); digitalWrite (SdCardPin, HIGH); // отключить SD-карту, поскольку мы ее не используем // Самопроверка testLeds (); // Настройка сети и MQTT client.setServer (server, 1883); client.setCallback (MQTTBrokerCallback); Ethernet.begin (mac, ip); Serial.print (F ("Текущий IP:")); Последовательный.печать (Ethernet.localIP ()); Serial.print (F ("- IP-адрес брокера MQTT:")); Serial.println (сервер); // Изначально мы не знаем состояние клапана, а концевые выключатели не так надежны. // Откроем клапан с электроприводом и дождемся завершения. В худшем случае, если он уже открыт, он просто кратковременно коснется концевого выключателя if (openValve () ==0) {Serial.println (F («Клапан открыт, система теперь контролирует»)); // В доме есть другие устройства мониторинга, давайте послушаем, какие неисправности они могут сообщить брокеру MQTT subscribeToRemoteWaterSensors (); } else {Serial.println (F («Невозможно открыть клапан, система вышла из строя. Используйте байпас для водопровода»)); }; enableInterruptOnResetButton (); задержка (1500); // разрешаем оборудованию само сортироваться Serial.println (F ("Конец настройки")); } // Основной loopvoid loop () {// Светодиоды configureLedsWithInitialStates (); // Реагировать на запрос сброса if (isResetRequested ==1) {Serial.println (F («Кто-то нажал кнопку, чтобы сбросить это устройство»)); publishStatus (); wdt_enable (WDTO_1S); // включить сторожевой таймер, сработает с задержкой в ​​1 секунду (5000); Serial.println (F («это сообщение никогда не должно появляться»)); } // Давайте теперь проверим, не обнаружена ли утечка воды readLocalWaterSensor (); if (isWaterDetected ==1 || isWaterDetectedRemotely ==1) {if (isValveClosed ==0) {closeValve ();}; } // Публикуем в брокере MQTT if (mqttIntervalCnt ==0) {if (isWaterDetected ==1) {publishFault ();} publishStatus (); mqttIntervalCnt =mqttInterval; } else {if (isConnectedToValve ==0) {Serial.println (F («Система вышла из строя - невозможно управлять клапаном с электроприводом. Нет мониторинга на месте»)); } else {Serial.print (F (".")); } mqttIntervalCnt =mqttIntervalCnt - 1; } // Сделаем паузу для отдыха (mainLoopDelay / 2); client.loop (); // светодиоды configureLedsWithFinalStates (); задержка (mainLoopDelay / 2); } //// Управление локальным датчиком воды // void readLocalWaterSensor () {isWaterDetected =! GetDebouncedValue (WaterDetectorPin, 100, 10); Serial.print (isWaterDetected); } //// Управление кнопкой сброса // void enableInterruptOnResetButton () {isResetRequested =0; attachInterrupt (1, onResetRequested, CHANGE);} недействительным onResetRequested () {detachInterrupt (1); isResetRequested =1; } // Управление последовательностью открытия клапана int openValve () {Serial.print (F ("Открытие клапана ...")); // сначала подтверждаем, что клапан был закрыт, заставив двигатель снова кратковременно нажать на «закрытый» концевой выключатель (поскольку эти концевые выключатели не так надежны ...) setupRelays (1); if (waitForEndOfCycle (ValveClosedPin) ==0) {// теперь давайте попробуем открыть клапан setupRelays (2); если (waitForEndOfCycle (ValveOpenedPin) ==0) {isConnectedToValve =1; isValveClosed =0; setupRelays (0); // силовые реле ВЫКЛЮЧЕНЫ Serial.println (F ("")); возврат 0; }} setupRelays (0); // силовые реле выключены isConnectedToValve =0; return -1;} // Управляем последовательностью закрытия клапана int closeValve () {Serial.print (F ("Закрытие клапана ...")); // сначала подтверждаем, что клапан был открыт, заставив двигатель снова кратковременно нажать на «открытый» концевой выключатель (поскольку эти концевые выключатели не так надежны ...) setupRelays (2); if (waitForEndOfCycle (ValveOpenedPin) ==0) {// теперь давайте попробуем закрыть клапан setupRelays (1); если (waitForEndOfCycle (ValveClosedPin) ==0) {isConnectedToValve =1; isValveClosed =1; setupRelays (0); // силовые реле ВЫКЛЮЧЕНЫ Serial.println (F («Клапан выключен. Пожалуйста, внимательно осмотрите все комнаты и детекторы уборки»)); возврат 0; }} setupRelays (0); // силовые реле выключены isConnectedToValve =0; return -1;} // Настраиваем реле для питания двигателя с правильной полярностью. ); digitalWrite (ValveControl2, HIGH); ломать; case 1:// цикл закрытия digitalWrite (ValveControl1, HIGH); digitalWrite (ValveControl2, LOW); ломать; case 2:// цикл открытия digitalWrite (ValveControl1, LOW); digitalWrite (ValveControl2, HIGH); ломать; по умолчанию:Serial.print (F («Неожиданный сценарий ретрансляции:»)); Serial.println (сценарий); digitalWrite (ValveControl1, HIGH); digitalWrite (ValveControl2, HIGH); ломать; }} // Ждем, пока мотор моторизованного клапана не коснется концевого выключателя int waitForEndOfCycle (int limitSwitchPin) {int cnt =valveTimeOut; while (cnt> 0) {if (getDebouncedValue (limitSwitchPin, 10, 10) ==LOW) {return 0; } cnt =cnt - 1; Serial.print (F (".")); задержка (1000); }; Serial.println (F ("- истекло время ожидания при закрытии клапана. Проверьте, правильно ли запитан клапан и подключены ли кабели.")); return -1;} // Эта процедура помогает избежать ложных срабатываний int getDebouncedValue (int inputPin, int intervalInMs, int requiredConfirmations) {int confirmations =1; int currentValue =digitalRead (inputPin); в то время как (подтверждения <=requiredConfirmations) {задержка (intervalInMs); если (currentValue ==digitalRead (inputPin)) {подтверждения =подтверждения + 1; } else {подтверждения =1; currentValue =digitalRead (inputPin); }} return currentValue;} //// Управление светодиодами // void configureLedsWithInitialStates () {clearLeds (); // Переоценить if (isWaterDetectedRemotely ==1 || isWaterDetected ==1) {digitalWrite (AlarmLedPin, HIGH);}; if (isConnectedToValve ==0 || isConnectedToBroker ==0) {digitalWrite (FaultLedPin, HIGH);}; digitalWrite (SystemLedPin, HIGH);} void configureLedsWithFinalStates () {if (isWaterDetectedRemotely ==1) {digitalWrite (AlarmLedPin, LOW);}; если (isConnectedToBroker ==0) {digitalWrite (FaultLedPin, LOW);}; если (isValveClosed ==1) {digitalWrite (SystemLedPin, LOW);}; } void clearLeds () {digitalWrite (AlarmLedPin, LOW); digitalWrite (FaultLedPin, LOW); digitalWrite (SystemLedPin, LOW);} void testLeds () {clearLeds (); digitalWrite (AlarmLedPin, HIGH); задержка (500); digitalWrite (FaultLedPin, HIGH); задержка (500); digitalWrite (SystemLedPin, HIGH); задержка (500); clearLeds ();} //// Функции, связанные с MQTT //// Обработка входящих сообщений MQTTvoid MQTTBrokerCallback (char * subscribedTopic, byte * payload, unsigned int length) {Serial.print (F ("Новое сообщение получено от брокера MQTT. Тема). знак равно Serial.print (подписан на тему); String payloadAsString =(char *) payload; Строка realPayload =payloadAsString.substring (0, длина); // иначе мы получим мусор, так как буфер разделяется между входом и выходом Serial.print (F (", content =")); Serial.print (realPayload); if (realPayload.indexOf ("WaterDetected")> 0 &&realPayload.indexOf (mqttClientLocation) ==-1) // вторая часть теста требуется, чтобы избежать самозапускаемых ошибок {isWaterDetectedRemotely =1; } // for (int i =0; i  

Схема


Производственный процесс

  1. Клапаны для сложного отключения и управления
  2. Управление датчиком и исполнительным механизмом Raspberry Pi
  3. Контроль заполнения бассейна
  4. Двухъядерная отладка Portenta H7
  5. Универсальный пульт дистанционного управления с использованием Arduino, 1Sheeld и Android
  6. ЖК-анимация и игры
  7. Управление монетоприемником с помощью Arduino
  8. Центр управления Arduino
  9. Детектор звуковой частоты
  10. Arduino с Bluetooth для управления светодиодом!