Recent Changes - Search:

Главная страница

Проекты

Статьи

Домашний WiFi роутер

Архив проектов

Загрузки

GitHub

SourceForge

edit SideBar

WMProtect

Система защиты от протечки для стиральной машины.

Введение.

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

Идея показалась мне вполне по силам и я решил ее реализовать: на микроконтроллерах и с моторизированным вентилем.

Для начала я сформулировал требования к разрабатываемой системе:

  • отслеживание состояния стиральной машины: открывать воду вначале стирки и закрывать по окончании;
  • возможность ручного управления вентилем;
  • работа от аккумуляторов и закрытие вентиля в случае разрядки аккумулятора;
  • наличие датчика протечки: перекрывать вентиль в случае, если протечка будет обнаружена.

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

Вроде этого для техзадания хватит. Приступим!

Выбор MCU

Поскольку вся система состоит из двух устройств, то и микроконтроллеров должно быть два. Я поскреб по сусекам и нашел у себя две Atmega8: один в DIP корпусе, а другой — в TQFP. Тот, который в DIP'овском — пошел в монитор, а TQFP — в контроллер. Позже выяснилось, что разросшаяся прошивка контроллера уже не влезает в 8КБ Atmega8, поэтому пришлось сделать апгрейд до Atmega328 – полный аналог, но памяти для программы теперь в четыре раза больше. Кстати, одним из моих мотивов делать подобные проекты — это утилизация электронного хлама, который у меня скопился за многие годы. Правда, по окончании проекта хлама меньше не становится. Его становится еще больше!

Часть первая. Монитор

Взаимодействие со стиральной машинкой

Проблема первая: как определить, чем сейчас занимается стиральная машинка? Вначале проекта эта часть задачи мне казалась очень простой. Всё что нужно было сделать — это определить моменты начала и окончания стирки. На передней панели машинки имеется светодиод, который зажигается и гаснет как-раз тогда, когда нужно. Я рассчитывал подпаяться к нему GPIO ногой микроконтроллера, так что на время отладки просто эмулировал на макете монитора нужные события кнопкой. Нажал на кнопку — светодиод зажегся, стирка началась. Отпустил — все наоборот. Однако, после разбора стиральной машинки, выяснилось, что данный светодиод — это часть динамической индикации, и, увы, нельзя так просто определить: горит он или нет.

Покрутив в руках (пару дней) панель управления я обнаружил, что он реализован на PIC контроллере. Более того, к основной плате он подключен ногами, отвечающими на аппаратный I2C. Ага, подумал я, можно снифернуть I2C шину и таким образом определить, что сейчас делать стиральная машинка. Код I2C снифера для Atmega я нашел в интернете. Разумеется, пришлось кое-что подшаманить.

Скажу честно: полностью протокол я разобрать не смог (да и не пытался особо), однако шаблоны начала и окончания стирки (а также включения и выключения питания) получилось определять довольно точно. Заняло это у меня около недели.

Модель: Candy GC4 1072 D. Компьютер периодически шлет блоку индикации серию из пяти байтовых последовательностей. Первые четыре последовательности имеют формат:

12 A7 00 – NN – X0 X1 X2 X3 X4 X5 X6 X7 – CS

где: 12 A7 00 – заголовок, NN – номер последовательности, X[0..7] – 8 байт данных, CS – контрольная сумма. Пятая последовательность представляет собой какой-то мусор переменного размера, суть которого для меня так и осталась загадкой.

Следующие шаблоны мне удалось разгадать:

POWER ON

12 A7 00 – 01 – X0 X1 X2 X3 X4 X5 X6 X7 – CS
12 A7 00 – 02 – X0 X1 X2 X3 X4 X5 X6 X7 – CS

где X[0..7] хотя бы один не равен 0

START

12 A7 00 – 03 – X0 X1 X2 X3 01 01 01 01 – CS

где X[0..3] – любое число

STOP

12 A7 00 – 03 – X0 X1 X2 X3 00 00 00 00 – CS

где X[0..3] – любое число

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

Логика работы примерно следующая: если мы получаем последовательности POWER ON, но при этом отсутствует START, то начинаем слать в эфир пакеты со статусом 0. Если появляется последовательность START — меняем статус на 1. В остальных случаях — ничего не шлем.

О пакетах, и о том, что такое статус поговорим дальше.

Забавно, но когда я шпионил за I2C пакетами, у меня не было возможности подключиться к сниферу компьютером. Я задействовал для этого Raspberry Pi c powerbank'ом, у которого был алюминиевый корпус. Так вот, стоило только этому корпусу соприкоснуться с корпусом стиралки, так тут же в щитке выбивался УЗО, в квартире гас свет и я с матюками начинал искать фонарик. :) Почему такая фигня происходила — для меня до сих пор остается загадкой.

Радиоканал

Изначально мне не хотелось дополнительных проводов, идущих от стиральной машинки. То есть, связь должна была быть беспроводной. Отсюда, были три возможных варианта решения проблемы: WiFi, Bluetooth и RF модуль для Arduino. Я остановился на последнем, выбрав модуль FS1000A.

Разумеется, на Хабре найдется много человек, которые упрекнут меня в этом выборе. Они намекнут, что на Али-Экспрессе можно за недорого приобрести модуль ESP с полноценным WiFi. Но я подумал, что это сильно усложнило бы проект, и решил действовать попроще.

Как известно, RF модуль FS1000A нельзя подключать напрямую к RS232 интерфейсу: длинная последовательностей нулей или единиц срывает синхронизацию приемника. Библиотека VirtualWire создана, чтобы решить эту проблему. Однако, эта библиотека написана для Arduino, а я программирую исключительно нативно под Atmega на C. К счастью, код для Arduino очень похож на чистый C, и с небольшими переделками, библиотека была успешно портирована.

Не обошлось и без трудностей: вначале пакеты никак не хотели доходить до приемника. Я во всем винил свои кривые руки, но соединив напрямую выводы контроллеров приемника и передатчика, убедился, что в программной части все работает. Неисправным оказался передатчик заказанный из Китая. Пришлось покупать еще один комплект. Затем я починил старый и у меня теперь два комплекта приемник-передатчик. Помните, что я писал про уменьшение хлама?

Данные пошли, но что именно содержится в этих данных? Вот, что представляет собой передаваемый пакет:

typedef struct {
    uint32_t dst;
    uint32_t src;
#define WMP_MSG_STATUS_ALIVE    _BV(0)
#define WMP_MSG_STATUS_VALVE    _BV(1)
    uint8_t status;
} wmp_msg_t;

#define WMP_ADDR_MONITOR        0x4d504d57
#define WMP_ADDR_CONTROLLER     0x43504d57

Первые два двойных слова — это физические адреса приемника и передатчика. В моем случае они строго фиксированы: 0x43504d57 — приемник (контроллер) и 0x4d504d57 — передатчик (монитор). Фактически, первые 8 байт — эта сигнатура пакета. Значимая информация находится только в последнем байте — битовом флаге. Установленный нулевой бит этого флага означает, что монитор включен и работает — он всегда должен быть 1. Первый бит — это статус вентиля: 0 – вентиль нужно закрыть, 1 — открыть. Все.

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

За целостностью передаваемых данных следит библиотека VirtualWire с помощью CRC32. Мне дополнительных усилий в этом направлении прилагать не пришлось. Красота!

Конструкция

Конструктивно монитор выполнен в виде небольшой платы, которая вклеивается на термоклее «сопли дядюшки Ляо» внутри передней панели стиральной машинки, Разъемами плата подключается в разрыв между компьютером и платой индикации. Сама машинка никакой модификации не подвергалась: в любой момент ее можно привести к исходному состоянию.

Часть вторая. Контроллер.

Радиоканал

Здесь все просто: стоит приемник комплекта FS1000A и приемная часть библиотеки VirtualWire. Пакет разбирается и на выход передается его статус. Приемник VirtualWire занимает TIMER1 в микроконтроллере.

Управление вентилем

В китайском Интернет-магазине был подобран моторизированный вентиль на 3/4”, с питанием 5 вольт, и с выведенными в кабель контактами концевых датчиков. Данный вентиль был установлен между шаровым краном и шлангом стиральной машинки. Для управления вентилем, на том же китайском сайте, был заказан маломощный драйвер шагового двигателя на драйверах L9110. Подключил я его к контроллеру по следующей схеме:

С программной точки зрения особых трудностей не было: по входам VALVE_CLOSE и VALVE_OPEN определяем текущий статус вентиля. В случае, если этот статус нужно поменять, включаем мотор на открытие или закрытие и ждем до тех пор, пока на соответствующем входе не установится логический 0. Однако, поскольку открытие или закрытие занимают некоторое время, хотелось бы не терять в этот момент контроль над всем устройством. Поэтому, на таймере Atmega'и был сооружен примитивный планировщик и контроль за работой вентиля был передан специальной задаче. Заодно, специальный программный модуль WatchDog измеряет время, за которое происходит переключение вентиля, и если оно слишком большое, то генерируется сигнал о его неисправности. Позже, на этот планировщик были навешаны и другие интересные вещи, вроде мигания светодиодами и опроса датчика протечки. Но об этом позже.

Также, к схеме управления вентилем относится трехцветный светодиод состояния и трехпозиционный тумблер ручного управления. В среднем положении тумблера включается автоматическое управление согласно сигналам от стиральной машины и других датчиков. В случае неисправности вентиля поочередно загораются красный и зеленый цвета.

Светодиодная и звуковая индикация

Со светодиодами все просто: они цепляются напрямую на порты ввода-вывода через ограничительные резисторы. Токи там не большие, а порты на Atmega достаточно мощные.

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

Я остановился на схеме с одним транзистором и автотрансформатором, который раскачивает напряжение звука с 5В до 50В. И тогда получилось относительно громко. Не на всех частотах, конечно, а поближе к резонансу.

Вот только во время генерации звука слегка снижалась яркость светодиодов (косяк с питанием), но микроконтроллер не зависал и ход управляющей программы не нарушался. Я подумал, что это особенность отладочного макета и на итоговой плате все будет работать хорошо. Я ошибся — лучше не стало. Хуже, правда, тоже.

Еще одной проблемой стало то, что у меня закончились таймеры и в фоне генерировать звук я не смог. Пришлось период писка задавать sleep'ами. Так что, во время генерации звука Atmega ничего кроме делать не может: прерывания тоже пришлось запретить, иначе тон получается не чистым. Но это оказалось это не очень страшно так как вывод звука не пересекался с другими критичными задачами, вроде управления вентилем или приемом данных по радио.

Далее, я подобрал константы sleep'а таким образом, чтобы они соответствовали нотам и придумал несколько более-менее благозвучных сочетаний: «вентиль открыт», «вентиль закрыт», «стирка окончена» и «протечка». Про сигнал «стирка окончена» отдельно расскажу позже.

Детектор протечки

Детектор протечки изначально планировалось делать на встроенном АЦП микроконтроллера. Эксперименты показали, что это вполне рабочее решение. Однако, я встречал, что иногда в датчик с контактами добавляют конденсатор, чтобы подключен ли он и нет ли где в проводе обрыва. Проверить наличие конденсатора (и измерить его емкость) можно с помощью: RC цепочки, компаратора и часов. В качестве компаратора используется обычный GPIO вход (он же логический и переключается с 0 на 1 при определенном напряжении), а часов в микроконтроллере хватает.

Предполагалось, что я буду время от времени проверять наличие конденсатора на линии, а затем с помощью АЦП определять, не находятся ли контакты датчика в воде. Как оказалось, вполне достаточно измерять только емкость конденсатора: если опустить его в воду, то время заряда увеличится, а разряда — уменьшится. Причем, время изменится на достаточную величину, чтобы его можно было уверенно детектировать.

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

Детектор протечки имеет свой собственный индикаторный светодиод красного цвета. Если сенсор не обнаружен, то он загорается и в эфир передается команда закрыть вентиль. Стоит только восстановить связь с сенсором, светодиод гаснет и вентиль можно открывать (если только машинка находится в состоянии стирки, конечно). Другое дело, если сенсор обнаружит воду. В этом случае индикатор начинает мигать, раздается противный прерывистый звук, и вентиль принудительно закрывается. Но самое главное, что контроллер из этого состояние никогда не выходит. Протечка считается серьезной аварией, и подача воды не возобновится, пока вы принудительно не перезагрузите устройство.

Питание

Питание — самая непонятная для меня часть в этом проекте. Если я немного разбираюсь в цифровой схемотехнике, то в аналоговой, мягко говоря — не очень. Но, спасибо китайцам: я могу приобрести готовые модули DC-DC преобразователей с контроллерами заряда аккумулятора, и на их основе збацать что-то работоспособное.

С самого начала планировалось сделать устройство с автономным питанием, чтобы в случае отключения электричества быть уверенным, что вода будет перекрыта. Кроме того, у меня был блок питания на 9В, который требовалось куда нибудь пристроить. Итого, вводная получилась следующая:

  • от сети приходит 9В;
  • от батареи приходит 3,4~3,7В;
  • для заряда батареи нужно 5В;
  • для питания логических и силовых схем нужно 5В;
  • если пропадает напряжение от сети, переключить питание на батарею;
  • на контроллер необходимо передавать сигнал заряда батареи, напряжение на батарее и сигнал работы от сети.

Структурная схема получилась как на рисунке.

В качестве переключающего элемента задействованы два диода Шотки. Контроллер заряда имеет два светодиода: CHARGE и STANDBY. Сигнал от первого был заведен на GPIO порт контроллера, чтобы монитор мог знать, что батарея заряжается. Также, на порт микроконтроллера подается сигнал от первого DC-DC преобразователя, чтобы определить, работает устройство от сети или батареи. Для контроля уровня заряда, напряжение с аккумулятора подается на АЦП контроллера. В случае, если напряжение слишком низкое, монитор закрывает вентиль и переходит в ждущий режим: не отвечает ни на какие команды, пока не появится напряжение в сети.

К сожалению, без косяков тут не обошлось: по какой-то причине, мотор вентиля забирает часть энергии с аккумулятора. Видимо, я ошибся с мощностью сетевого DC/DC преобразователя или с толщиной силовых дорожек на плате. Как результат: после открытия или закрытия вентиля батарея начинает заряжаться.

Для контроля за состоянием питания имеется специальный двухцветный светодиод. Если он горит зеленым светом, то устройство работает от сети. Если красным — то от батареи. Если зеленым, но при этом мигает красный цвет, то идет зарядка батареи.

Логика работы

Ну вот, все аппаратные части и их программная поддержка у нас есть, теперь нужно каким-то образом заставить все это взаимодействовать между собой. Изначально, я видел реализацию логики работы в виде большого цикла (то, что называется main loop) с кучей if'ов внутри.

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

От зоопарка if'ов, которые проверяют состояние различных подсистем контроллера и выносят решение: открыть или закрыть вентиль пришлось отказаться. Очень тяжело такое отлаживать и очень просто в этом запутаться. Вместо этого мне понравилось идея из древней книги Д. Хейзермана: «Как самому сделать робот». В книге предлагалось, чтобы каждый модуль генерировал свои сигналы управления: вперед, назад, поворот и т. д. Далее, из этих сигналов выбирается только тот, который исходит от блока с более высоким приоритетом. Я сделал примерно так же.

Блоки по приоритетам я расставил следующим образом:

  1. Блок протечки
  2. Блок контроля заряда батареи
  3. Блок ручного управления вентилем
  4. Блок управления вентилем по радиоканалу
  5. Блок WatchDog таймера вентиля

Каждый блок генерирует три команды: UNDEFINED, OPEN и CLOSE.

Блок протечки имеет самый высокий приоритет, но у него нет команды OPEN, зато его команда CLOSE однозначно закрывает вентиль, что бы там ни говорили остальные блоки. Блок ручного управления может перебить любой сигнал блока радиоканала, что позволяет управлять вентилем независимо от того, что нам указывает стиральная машинка. Ну и так далее. То есть, появилась логичная иерархическая структура, которую просто понимать и отлаживать.

Теперь, давайте вернемся к сигналу: «стирка окончена». Увы, но моя модель стиральной машинки не имеет возможности оповестить об окончании своей работы с помощью звука: не предусмотрели инженеры Candy такой возможности. С другой стороны, у меня есть дополнительное устройство, которое имеет пьезоизлучатель и в каждый момент времени знает, чем занимается стиральная машина. Почему бы не заставить его сообщать об окончании стирки? Хорошо, сделаем так, чтобы контроллер громко и противно (на частоте резонанса) пищал, когда приходит сигнал закрытия вентиля. Добавим еще пятиминутный защитный интервал, чтобы не слушать этот писк каждый раз, при включении и выключении машинки. Вентиль открыт пять минут — стирка точно началась.

Результаты

Разработка у меня заняла около года неспешной (очень неспешной) работы. Устройство работает уже года два. В эксплуатации оно показало себя вполне удовлетворительно. Но не обошлось и без недостатков. Давайте их честно перечислим:

  1. Я что-то напутал с питанием: мотор вентиля часть энергии берет из батареи.
  2. Схема генерации звука просаживает напряжение питания. Очень хорошо видно, как меняют яркость светодиоды когда звук воспроизводится.
  3. Не очень устойчиво работает радиоканал. Во первых, сигнал пропадает, если человек стоит вплотную к стиральной машине. А во вторых, иногда сигнал ухудшается сам по себе. В этом случае, приходится пользоваться тумблером ручного управления, но такое происходит крайне редко.
  4. Пару раз зависал блок монитора в стиральной машине. Блок контроллера не зависал ни разу.
  5. Звук от пьезоизлучателья очень сильно заглушался внутри корпуса. Я просверлил в копрусе дырку: стало лучше, но не очень. Пришлось выпаивать излучатель из платы и приклеивать к корпусу, прямо напротив дырки.

В целом разработку я считаю удачной и очень полезной. Запускаю машинку с утра и спокойно ухожу на работу: знаю, что в нужное время кран подвода воды будет перекрыт.

Немного фоток.

Вид сверху, со снятой верхней крышкой

Вид сзади, со стороны разъемов

В естественной среде обитания

Установленный вентиль с моторчиком

Датчик протечки

Ссылки

Edit - History - Print - Recent Changes - Search
Page last modified on November 20, 2023, at 10:32 am