image
Привет, обитатели ХабраХабр!

Возможно, по сути статьи я ошибся ресурсом, за мое 9 летнее отсутствие появился некий geektimes, возможно, я должен написать это там, но напишу сюда — на хабрахабр. Если не прав — не бейте ногами.

Я люблю делать простые как топор вещи, но одновременно жутко полезные, например, как прошлая статья 9 летней давности — Установка Ubuntu Linux с винчестера. Скрипт, вот и сейчас настал час для такой деятельности.
Под катом вы найдете подробнейшую инструкцию как на основе Arduino и дешевых и доступных средств автоматизировать подачу чистой свежей воды в кофемашину, а также организовать отвод жидкости из поддона кофемашины, на которой не предусмотрено подключение к внешним коммуникациям.


Предыстория и мотивация


История такова, что в маленькой, но очень гордой фирме по производству «громадных квадрокоптеров» SKYF купили кофемашину, ближайшие водопроводные и канализационные коммуникации были в метрах 100 от нее. В процессе эксплуатации оказалось, что коллектив из 30 человек заполнял поддон для капель за ~10 кружек кофе, а потом нужно было идти через три двери до ближайшего санузла, балансируя с заполненным водой поддоном, как на Сабантуе с яйцом в ложке, дабы не пролить, ни капли на коверистый пол, ни, тем более, на штаны. Куда меньшую проблему доставляло наполнение резервуара чистой воды, т.к. диспенсер был в полуметре от кофемашины и нужно было лишь 1-2 минуты постоять в руках с пластиковым резервуаром для чистой воды. Но я твердо решил, что «хватит это терпеть» (с) и вооружившись завалявшейся у меня платкой Arduino Uno, решил автоматизировать процесс наполнения бачка и слива отработанной жидкости.

Предварительно изучил вопрос рентабельности сей идеи автоматизации, оказалось что различие в цене приобретенной кофемашины и кофемашины с возможностью подключения к канализации составляет 2 раза минимум! Приведу пример кофемашин в ценах на начало 2018 года:
— Купленная кофемашина ~60 000 рублей;
— Затраты на дополнение функции подключения к «внешним коммуникациям» ~ 3000 руб;
— Кофемашина с возможностью подключения к водопроводу и канализации — ~от 110 000 до ? руб.
Цены просто небо и земля. Определенно есть смысл автоматизировать купленную кофемашину.

Основной раздел


Цели:
— увеличить интервал слива жидкости с поддона с раз в 1 час на раз в сутки минимум;
— реализовать удобный способ транспортировки отработанной жидкости до канализационных коммуникаций;
— забыть что такое снимать емкость чистой воды и стоять 1-2 минуты около диспенсера для заполнения емкости.

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

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

Решаем поставленные цели в соответствии с выбранным способом.

Наш пациент выглядит таким образом:

image

Слева у кофемашины съемный бачок для чистой воды, в нижней части выдвижной поддон для капель объемом ~400 мл.
Задача решается организационно и с помощью элементов системы автоматического управления:
1) берем две бутылки 19 литров, которые всегда под рукой в офисе, одна будет для чистой воды, другая для отработанной;
2) в случае снижения уровня в бачке кофемашины до минимума подаем из бутыли чистой воды при помощи насоса воду до отметки максимум;
3) соединяем ПВХ трубкой поддон с внешним резервуаром и контроллируем уровень в нем, саму бутыль, дабы не портить аппетит цветом стоков, закрываем чехлом, которые предлагают многие службы доставки воды.
Например, вот такой чехол:
image

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

Выбираем средства автоматизации
Берем Arduino Uno и начинаем автоматизировать. Нам потребуется:
— Датчик уровня воды в резервуаре кофемашины;
— Насос подачи воды из бутыли в резервуар;
— Датчик уровня воды в резервуаре стоков.
Логика проста:
ЕСЛИ уровень в резервуаре кофемашины ниже минимума -> включить насос;
ЕСЛИ уровень в резервуаре кофемашины выше максимума -> остановить насос;
ЕСЛИ уровень в резервуаре стоков выше максимума — вопить.
Казалось бы логика проста, но при реализации оказалось что не все так просто, все подробности в разделе программирования.

Выбираем насос
Требования к насосу:
1) должен проходить в горлышко обычной офисной бутылки воды 19 литров, диаметр горлышка 53 мм;
2) должен иметь напряжение питания не более 12 Вольт, дабы согласовать с питанием Arduino и не иметь опасности поражения электрическим током;
3) желательно должен быть погружным в бутыль, чтобы не захламлять пространство вокруг кофемашины и не попадаться на глаза;
4) должен иметь возможность создать давление для подъема воды на 1.5 метра.

Этим критериям удовлетворили следующие насосы:
— погружной насос AMP-X157 от «Амперка» на 5-12 Вольт;
image
— погружной насос BI0002156 от китайцев на 6-15 Вольт.
image
Сначала выбрал первый вариант, просто потому что он продавался в моем городе, некогда ждать месяц китайцев, кофе без забот хочется пить прямо здесь и сейчас. Но при эксплуатации выяснилось из-за выступающего штуцера не пролезает через горлышко в другую бутылку. Потом купил китайский насос, он подошел идеально.
Характеристики китайского насоса (полужирным шрифтом выделены важные для нас параметры):
Рабочее напряжение 6-15 В
Номинальный ток: 1.2A
Максимальный расход: 600л/ч
Размеры: прибл. 10.8 х 4 см (В х Ш)
Идеально. Берем. На этот насос в ближайшем строительном магазине прикупил прозрачную ПВХ трубку с внутренним диаметром 12. На первый насос, которая «амперка» шла трубка диаметром 8 и 10 см (внутренний, внешний) длиной 1 м из нее был сделан слив, так что придется купить 2 трубки, кто хочет просто пройтись по инструкции.


Выбираем датчики уровня
Требования к датчику уровня:
1) должен давать информацию о низком и высоком уровне в бачке воды;
2) по возможности не должен требовать вмешательства в конструкцию бачка;
3) должен быть компактным;
4) должен быть эстетичным и не выделяться;
5) должен запитываться безопасным и совместимым с ардуино питанием 5-12 Вольт;
6) должен быть доступным в городе (мое требование здесь и сейчас);
7) должен работать с пресной водой;

Что предлагает нам рынок:
1) Датчик уровня специально для ардуино
image
Удовлетворяет пунктам: 2, 3, 5, 6.
Не удовлетворяет пунктам: 1, 4. По мне он слишком выделяется и не эстетичный, к тому же его длина не позволит измерять всю высоту уровня (высота бачка около 22 см, данный датчик 6.2 см)

2) Поплавковый уровень
image
Удовлетворяет пунктам: 1 (два датчика), 3, 5, 6.
Не удовлетворяет пунктам: 2, 4. Нужно сверлить бак, выделяется, но его приметим, он нам еще пригодится.
Также есть в виде штанги, тоже не подходят — сложно подобрать нужного размера

3) Инфракрасный датчик уровня (оптопара)
image
Удовлетворяет пунктам: 1 (два датчика), 3, 4, 5, 6.
Не удовлетворяет пунктам: 2. Нужно сверлить бак.

4) Ультразвуковой датчик расстояния HC-SR04
image
Удовлетворяет всем пунктам. У бачка есть крышка, к которой можно прикрепить данный датчик и измерять расстояние до поверхности, благодаря что звук от воды отражается обратно на 99% («эхо гуляет по Яхреньгскому озеру» (с) язь), то этот датчик подходит идеально: совместим с ардуино, безопасное напряжение, ничего сверлить не надо, будет скрыт под крышкой (в теории), в магазинах навалом, измеряет уровень полностью от дна до полного.

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


Также потребуется блок питания 220В->12Вольт им запитаем, и Arduino, и насос. Управлять насосом будем с помощью реле ардуино (подойдет любой модуль реле с управляющим напряжением 5 Вольт и не более 20мА, вы можете его сделать сами, а можете просто купить реле от Ардуино).
image

Для общения с человеческим видом ардуинке прикупим пьезопищалку, дабы оповещать о неисправностях, и кнопку, через которую будем считывать хотелки и поведение человека.

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


Собираем, паяем, сверлим, клеим
Итого что нам потребуется (какое то «пока все дома»...):
1) 2 бутылки 19 литров;
2) Arduino Uno;
3) Блок питания 12 Вольт;
4) Насос погружной BI0002156;
5) Ультразвуковой датчик расстояния HC-SR04 (буду называть сонаром);
6) Поплавковый уровень прямой;
7) Кнопка для взаимодействия с человеком;
8) Реле на 5 Вольт;
9) Пьезопищалка;
10) Корпус;
11) До кучи перемычек папа-мама, мама-мама;

Из инструментов: изолента, нож, герметик, сверла, дрель, паяльник со всеми причитающимся.

Общая схема изображена ниже.
image

Собираем по «принципиальной» схеме ниже всю конструкцию. GND от каждого элемента тянем на любой GND выход Arduino, та же история с +5V. Следование номеру каналов даст вам преимущество не переделывать номера пинов в программе, которая будет ниже.

image

Хотелось бы отметить:
1. Я решал проблему с нехваткой разъемов GND и 5В тем, что припаял проводку к этим выводам и нужные мне датчики запитал от клемников WAGA, куда можно 5 проводов подцепить.

2. Сонар удобно крепится резинками к крышке бачка. Постарайтесь добиться перпендикуляторности излучателя к поверхности воды.

3. На бачек с помощью канцелярского зажима крепится шланг чтобы не выскочил из бачка.

4. Отвод капель из поддона я сделал через распечатанный на 3D принтере штуцер. В низшей точке сливного поддона кофемашины сверлим отверстие 9 мм под него, вставляем его туда и герметизируем соединение. Модель для штуцера под шланг диаметров 8/10 мм ниже по ссылке.

Штуцер / Choke by slimercorp on Sketchfab




Программируем
Спасибо Chupakabra303 за статью на GeekTimes! Без таймеров, детекторов фронтов сигнала не справился бы с программированием. Честно говоря, очень тяжело работать с Arduino, который изначально не заточен под псевдопараллельность задач как настоящие ПЛК.

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

Общается Arduino следующим способом. При ошибке он пищит N раз с паузой 10 секунд, N — номер ошибки.

N писков:
1 – переполнение бутыли для слива или обрыв в линии связи датчика в этой бутыли с контроллером.
2 – проблема с ультразвуковым датчиком уровня (сонар), он либо утоплен, либо отошел какой-либо из проводов.
3 – не подается вода при попытке ее налить. Проблемы: нет воды в бутылке чистой воды, насос, реле, питание, провода.

Чтобы квитировать ошибку (жест «я понял»), человек жмет на кнопку 1 раз, Arduino высоко пищит в течении 1 секунды, говорит что принято, я молчу. Человек в это время принимает меры для исправления проблемы, Arduino в этом режиме пищит 1 раз в 1 минуту, напоминая о себе. После исправления проблемы человек жмет 2 раза кнопку в течении 3 секунд (жест «проверь систему»), далее Arduino либо снова выдаст ошибку писком, либо 1 раз высоко пропищит, сказав что все хорошо, «работаю дальше».

Помимо этого реализовано:
— debug информация по COM порту, для отладки системы, например, отлаживать положение сонара, чтобы он выдавал нужный уровень;
— писк пищалкой без останова исполнения программы (соответственно с контролем нажатий кнопки).

Исходный код:
#include <Ultrasonic.h>
#include <plcStandardLib_1.h>
//=============================================================
//Формальное объявление необходимых триггеров и переменных
R_TRIG R_TRIG1;
R_TRIG R_TRIG2;
R_TRIG R_TRIG3;
R_TRIG R_TRIG4;
F_TRIG F_TRIG1;

bool TrashFull; //Высокий уровень в отходах
bool igotit; //Обратная связь от человека, что он ошибку понял
bool check_pls; //Признак запроса на проверку состояния системы
bool PumpUp; // Начать качать воду в резервуар чистой воды
bool NoFlow; //Признак отсутствия потока воды от насоса
bool Pressed; //Признак того что кнопка нажата
bool beep_pause_superlong; //Признак супер долгой паузы писка
bool beep_pause_superlong_end; // Признак окончания супер долгой паузы писка
bool beep_pause_long; //Признак долгой паузы писка
bool beep_pause_long_end; //Признак окончания долгой паузы писка
bool beep_pause_short; //Признак короткой паузы писка
bool beep_pause_short_end; //Признак окончания паузы писка
bool beep_on; //Признак присутствия писка на выходе пьезопищалки
bool beep_duration_end; //признак окончания писка
bool beep_granted; //Признак разрешения на писк
bool Pressed_now; //кнопка нажата только что
bool UnPressed_now; //кнопка отжата только что
bool time_end; //время контрольное кончилось
bool reset; // сброс контроля по уровню

int mode; //режим программы
int error; //вид ошибки
int n_pressed; //количество нажатий вовремя интервала 2 секунды
int k_beep; //количество писков за контрольный интервал
float us_level_raw; //расстояние от датчика до воды, сырое значение с датчика
float us_level_filt; ////расстояние от датчика до воды, сырое значение с датчика фильтрованный сигнал
float level; //уровень в баке
float level0; //уровень в баке в момент включения насоса
long t0; //Момент времени при котором начался контроль за нажатием кнопки
long time_to_destroy; //Подсчет времени до разрушения контроля за количеством нажатий кнопок в интервале 2 секунды
//=============================================================

//=============================================================
//Настройка железа
Ultrasonic ultrasonic(4, 3); // 3 - Echo, 4 - Trig
const int LevelTrashPin = 2; //Вход для дискретного датчика в сливе
const int RelayPin = 5; // Выход управления реле
const int BeepPin =  6; // Выход пищалки
const int ButtonPin = 7; //Вход кнопки
//=============================================================


//=============================================================
//Настройка таймеров
//мусорка антидребезг на аварию
TON TON1(50); // таймер на 50мс, инициализация 

//кнопка антидребезг на зажатие и отжатие
TON TON2(50); // таймер на 50мс, инициализация кнопка
TOF TOF1(50); // таймер на 50мс, инициализация

TON TON3(10000); // таймер на 10 секунд, инициализация КОНТРОЛЬНОЕ ВРЕМЯ ПРОВЕРКИ РАБОТЫ НАСОСА

TON TON4(1500); // таймер на 1.5с, инициализация ДЛИТЕЛЬНОСТЬ ПИСКА
TON TON5(1500); // таймер на 1.5с, инициализация ДЛИТЕЛЬНОСТЬ КОРОТКОЙ ПАУЗЫ
TON TON6(10000); // таймер на 10 секунд, инициализация  ДЛИТЕЛЬНОСТЬ ДЛИННОЙ ПАУЗЫ
TON TON7(60000); // таймер на 1 минуту, инициализация ДЛИТЕЛЬНОСТЬ СУПЕРДЛИННОЙ ПАУЗЫ

TON TON8(1000); // таймер на 1 секунду, инициализация ПЕРИОД DEBUG INFO
TON TON9(500); // таймер на 0.5 сек, инициализация ПЕРИОД измерений уровня
//=============================================================

//=============================================================
//Настройка констант, параметров системы
const int f_mode=500; //Частота в Гц при подтверждении принятия желания человека
const int f_error=100; //Частота в Гц для ошибок
const int t_nc=5000; //Время отсутствия контроля за ошибками после старта ардуино в мс (time_no_control)
const int dLevel_cp=3; //Уровень должен подняться на столько см за контрольный период (cp - control period)
const int button_cp=3000; //Контрольный период нажатия кнопки в мс

const float w_level=0.3; //Вес фильтра сонара
const float us_level_filt_fault=0.1; //Значение уровня при котором и ниже считаем датчик в аварии
const float HeightTank = 20; //Высота резервуара в см
const float HighLevel = 15; //Уровень высокий в см
const float LowLevel = 3; //Уровень низкий в см

const bool debug_on=true; //включить ли отладку по Serial
//=============================================================

void setup() {
Serial.begin(9600); // Это команда для Ардуино : задействовать COM порт для передачи данных.
pinMode(LevelTrashPin, INPUT_PULLUP);
pinMode(RelayPin, OUTPUT);
pinMode(BeepPin, OUTPUT);
pinMode(ButtonPin,INPUT_PULLUP);


igotit=false;
check_pls=false;
NoFlow=false;
beep_pause_long=false;
beep_pause_short=false; 
beep_on=false;
beep_pause_superlong=false;
beep_pause_long=false;
beep_pause_short=false;
beep_on=false;

k_beep=0;
t0=millis();
mode=1;
tone(BeepPin,f_mode,1000); //пищим что все ок, инициализация завершена
}

void loop() {
//=============================================================
//Секция считывания данных
//Полный - высокий уровень, Пустой - низкий уровень, Обрыв - высокий уровень.
//антидребезг появления признака переполнения, смена состояния с ПОЛНОГО на ПУСТОЙ происходит без задержки
  TrashFull=TON1.Run((digitalRead(LevelTrashPin))); 
  
//антидребезг появления признака нажатия и отжатия
//кнопка нормально разомкнута, вход с подтягиванием, один конец на земле поэтому
//никто не нажимает - уровень высокий  на входе
//кто то нажал - уровень низкий на входе
//никто не нажимает на кнопку, но прошелся кот и выдернул провод - обрыв
//обрыв - уровень высокий на входе, диагностировать линию в данной конфигурации нельзя,
//но не очень то и нужно (с) Путин
//не очень то и хотелось (с) Таня

  if (TOF1.Run((digitalRead(ButtonPin)))==false) {Pressed=true;}
  if (TON2.Run((digitalRead(ButtonPin)))==true) {Pressed=false;}

//фильтрация значений с датчика уровня
  if (TON9.Run(!TON9.Q)) {us_level_raw=ultrasonic.distanceRead();};
  us_level_filt=(1-w_level)*us_level_filt+w_level*us_level_raw;
  //Уровень в бачке кофемашины от 0 до HeightTank в см;
  level=constrain((HeightTank-us_level_filt), 0, HeightTank) ; 
//=============================================================


//=============================================================
//Секция интерпретирования поведения системы
//NoFlow,igotit,check_pls
  //при нормальной работе за контрольное время работы уровень поднимается на dLevel_cp см и больше.
  //Если такое не происходит, значит у нас либо не работает насос, либо нет воды в бачке
  time_end=TON3.Run(PumpUp && !reset);
  if ((R_TRIG1.Run(PumpUp)==true) | (reset==true)) {level0=level;} //запоминаем уровень при старте насоса
  if ((time_end==true) && (level-level0<dLevel_cp)) {NoFlow=true;} else {NoFlow=false;} //после контрольного времени смотрим изменение уровня
  
  if ((time_end==true) && (NoFlow==false)) {reset=true;} else {reset=false;} //сбрасываем контрольное время и заново контролим уровень
  
//В режиме ошибки и ожидания наблюдаем за нажатиями на кнопку. Считаем сколько раз нажали за контрольный интервал
  Pressed_now=R_TRIG2.Run(Pressed); //Контроль момента нажатия кнопки
  UnPressed_now=F_TRIG1.Run(Pressed); //Контроль момента отжатия кнопки

  if ((mode==2) | (mode==3))
    {
      time_to_destroy=(button_cp-(millis()-t0)); //от button_cp сек через 0 и до минус бесконечность
      if ((Pressed_now==true) && (n_pressed==0) && (time_to_destroy<0)) {t0=millis();} //сбрасываем таймер разрушения только когда пройдет контроль предыдущего отрезка времени
      if ((UnPressed_now==true) && (time_to_destroy>=0))  {n_pressed=n_pressed+1;} //считываем сколько раз отпустили кнопку
      if (time_to_destroy<0) {n_pressed=0;}
    }
    
  //Считываем жест человека - "i got it"/я понял. Это означает что человек подтвердил сообщение о неисправности
  //и принял в работу для исправления, пищать больше не нужно. Человек показывает это следующим действием:
  //нажимает кнопку 1 раз за 3 секунды
  if ((mode==2) && (n_pressed==1)) {igotit=true; n_pressed==0;}

  //Считываем жесть человека - "check_pls"/проверь пожалуйста. Это означает что человек предпринял меры для устранения
  //неисправности или провел необходимые работы по пополнению бутыли исходной воды и слива отработанной воды и предлагает
  //вернуться к работе. Человек показывает это следующим действием:
  //нажимает кнопку 2 раза за 3 секунды
  if ((mode==3) && (n_pressed==2)) {check_pls=true; n_pressed==0;}
//=============================================================




//=============================================================
//Секция переключения режимов
  //Если появился признак переполнения в бутыли слива или обрыва датчика, то переходим в режим ошибки и сообщаем код ошибки 1
  if ((mode==1) && (TrashFull==true) && (millis()>t_nc)) {mode=2; error=1;}
  //Если появился признак обрыва до датчика или утопление самого датчика, то переходим в режим ошибки и сообщаем код ошибки 2
  if ((mode==1) && (us_level_filt<us_level_filt_fault) && (millis()>t_nc)) {mode=2; error=2;}
  //Если появился признак отсутствия подачи воды от насоса, то переходим в режим ошибки и сообщаем код ошибки 3
  if ((mode==1) && (NoFlow==true) && (millis()>t_nc)) {mode=2; error=3;}

  //Если у нас есть ошибка и человек подтвердил - переход в режим ожидания и сбрасываем код ошибки
  if ((mode==2) && (igotit==true)) {mode=3; error=0; igotit=false;}
  
  //Если мы в режиме ожидания и нас попросили проверить все ли ок с системой то переходим в нормальным режим и сбрасываем запрос проверки
  if ((mode==3) && (check_pls==true)) {mode=1; check_pls=false;} 
//=============================================================



//=============================================================
//Основная логика работы в зависимости от режима
   //статус программы: 1 - ВСЕ ОК, работаем; 2 - ОШИБКА, не подтвержденная; 3 - ОШИБКА подтверждена, ожидаем отмашки от человека;
  if (mode==1)
  {
    //Проверяем уровень
    if (level<=LowLevel) {PumpUp=true;} //Уровень ниже минимума - включаем насос
    if (level>HighLevel) {PumpUp=false;} //Уровень выше максимума - выключаем насос
   }

  if ((mode==2) | (mode==3)) {PumpUp=false;} //тут же выключаем насос  чтобы не перегрелся
//=============================================================


//=============================================================
//Секция действий по результату работы программы (Digital Output)
//включаем и отключаем насос по признаку
if (PumpUp==true) {digitalWrite(RelayPin, LOW);} else {digitalWrite(RelayPin, HIGH);}

//Нижестоящий код реализован для писка без delay, который тормозил бы программу и делал бы ее неработоспособной

//При переходе в режим 1-ый делаем секундный писк, что все ок, я перешел
if (R_TRIG3.Run(mode==1)==true) {tone(BeepPin,f_mode,1000); beep_on=false; beep_pause_short=false; beep_pause_long=false; beep_pause_superlong=false; k_beep=0;}


beep_duration_end=TON4.Run(beep_on); //отсчет длительности писка
beep_pause_short_end=TON5.Run(beep_pause_short); //отсчет длительности короткой паузы
beep_pause_long_end=TON6.Run(beep_pause_long); //отсчет длительности длинной паузы
beep_pause_superlong_end=TON7.Run(beep_pause_superlong); //отсчет длительности супер длинной паузы

//пищим в режиме 2-ом, количество писков соответствует номеру ошибки
if (mode==2)
{
  //блокировки писка:
  beep_granted=!beep_pause_long && !beep_pause_short && (k_beep<error);   
  //включаем писк если дали разрешение
  if (beep_granted==true) {tone(BeepPin, f_error); beep_on=true;} 

  //когда длительность писка закончилась, включаем паузу, короткую или длинную, в зависимости от кол-во озвученных писков и номера ошибки
  if (beep_duration_end==true)
  {
    noTone(BeepPin);
    k_beep=k_beep+1; //кол-во озвученных писков
    beep_on=false; //выключаем признак писка
    if  (error>k_beep) {beep_pause_short=true; beep_pause_long=false;} else {beep_pause_long=true; beep_pause_short=false;}
  }
  //когда закончилась короткая пауза, выключаем признак
  if (beep_pause_short_end==true) {beep_pause_short=false;}

  //когда закончилась длинная пауза, выключаем признак
  if (beep_pause_long_end==true) {beep_pause_long=false; k_beep=0;}
}

//при переходе в другой режим, пищим высоко и инициализируем переменые писков
if (R_TRIG4.Run(mode==3)==true) {tone(BeepPin,f_mode,1000); beep_on=false; beep_pause_short=false; beep_pause_long=false; beep_pause_superlong=true;}

//пищим если мы в режиме ожидание, пищим раз в супердолгий интервал
if (mode==3)
{
  beep_granted=!beep_pause_superlong; //не пищим если только у нас есть пауза длительностью в 1 минуту  
  if (beep_granted==true) {tone(BeepPin, f_error); beep_on=true;} 
  //когда длительность писка закончилась, включаем паузу супердолгую
  if (beep_duration_end==true)
    {
      noTone(BeepPin);
      beep_on=false; //выключаем признак писка
      beep_pause_superlong=true;
    }
  //когда закончилась супердлинная пауза, выключаем признак
  if (beep_pause_superlong_end==true) {beep_pause_superlong=false;}
}
//=============================================================


//=============================================================
//Секция Debug, активируется из секции констант
if ((debug_on==true) && (TON8.Run(!TON8.Q)))
{
 //Чистим окно у клиента 
  Serial.write(27);
  Serial.print("[2J"); // clear screen
  Serial.write(27);
  Serial.print("[H"); // cursor to home
 //И начинаем писать всякую информацию о состоянии системы
  Serial.println("=================Debug info of ArduOsch=================");
  Serial.println("=================DicreteInputs==========================");
  Serial.print("LevelTrashPin="); Serial.print((digitalRead(LevelTrashPin)));  Serial.print("| ButtonPin="); Serial.print(digitalRead(ButtonPin)); Serial.print("| US_raw="); Serial.print(us_level_raw); Serial.print("| US_filtered="); Serial.println(us_level_filt); 
  Serial.println("=================DicreteInputs after processing=========");
  Serial.print("TrashFull="); Serial.print(TrashFull);  Serial.print("| ButtonPressed="); Serial.print(Pressed); Serial.print("| Level="); Serial.println(level);
  Serial.println("=================NoFlow condition=======================");
  Serial.print("PumpUp="); Serial.print(PumpUp); Serial.print(" Time_end="); Serial.print(time_end); Serial.print(" Reset="); Serial.print(reset);  Serial.print("| Level0==="); Serial.print(level0); Serial.print("| TON3_EST="); Serial.print(TON3.PT-TON3.ET); Serial.print("| NoFlow="); Serial.println(NoFlow);
  Serial.println("=================How mush was man clicked on button?====");
  Serial.print("TimeToDestroy="); Serial.print(time_to_destroy); Serial.print("| t0="); Serial.print(t0); Serial.print("| n_pressed="); Serial.println(n_pressed);
  Serial.println("=================What is the system state?==============");
  Serial.print("Mode="); Serial.print(mode); Serial.print("| error="); Serial.println(error); 
  Serial.println("=================Beep code==============");
  Serial.print("beep_granted="); Serial.print(beep_granted); Serial.print("| beep_pause_superlong="); Serial.print(beep_pause_superlong); Serial.print("| beep_pause_long="); Serial.print(beep_pause_long); Serial.print("| beep_pause_short="); Serial.println(beep_pause_short);
  Serial.print("k_beep="); Serial.print(k_beep); Serial.print("| beep_on="); Serial.println(beep_on);
}
//=============================================================

}




Видео и фото



Видеодемонстрация как все это работает:


Кому не хочется смотреть видео, вот пару фоточек:

image







Как чехол использовал почти единственно доступный чехол в Казани, просто серый, как временное решение (что постояннее, чем временное?), потом можно будет красивые чехлы заказать, например, с логотипом фирмы.

Вместо заключения


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

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

Всем всех благ!

Комментарии (58)


  1. advan20092
    14.03.2018 21:44
    +6

    А отработанные таблетки кофе не нужно выкидывать? Или они как-то в общий поддон попадают? В моей кофемашине для них предусмотрен отдельный контейнер, который можно вытащить только вместе с поддоном для воды.


    1. cab404
      15.03.2018 18:34

      Тут же не капсульная, а зерновая машина.
      upd: глупость сказал


  1. ukrazzz
    14.03.2018 21:44
    +1

    Слив капель — понятно. Но «твердые» отходы (aka жмых) все равно переполняют соответствующий контейнер за 10-15 чашек (на моей Jura 14 чашек). Так что не только раз в 4 дня бутыль менять :)


  1. Slimer Автор
    14.03.2018 21:47

    Отвечаю на одинаковые вопросы выше. Да, действительно, контейнер для кофейной гущи, нужно менять часто, но это не напрягает, выдвинул поддон, вытащил контейнер с гущей, выкинул в ведро, все задвинул обратно, да и знаете, если сделать полную автоматизацию уборки отходов — люди просто забьют на то, чтобы заглядывать в поддон, в итоге там будет плесень, грязь, что не стоит делать.
    Были конечно у людей мысли и это автоматизировать, но это требовалось бы большого вмешательства в конструкцию: отсасывать эту гущу? Это дырявить конструкцию кофемашины, не пойдет, да и надо какой то пылесос задействовать. Можно просверлить поддон в месте куда падает кофейная гуща, вроде как и само дно кофемашины + стол, подставить вниз мусорную корзину и контролировать переполнение корзины с помощью ИК датчика препятствия. Можно, но не хочется портить кофемашину, стол этими дырками, все таки была идея минимального вмешательства в конструкцию.


    1. kapunik
      14.03.2018 22:27

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


    1. ClearAirTurbulence
      14.03.2018 23:42
      +3

      вытащил контейнер с гущей, выкинул в ведро

      Зачем так делать, берете жмых, подсушиваете, смешиваете с чем угодно густым-жидким-мыльным (гелеобразное т.н. банное мыло отлично подходит), и имеете отличный скраб для лица\тела.


      1. semen-pro
        15.03.2018 00:05
        +2

        У нас в городе можно купить отработанный жмых по цене 50% от стоимости кофе)


        1. todd22
          15.03.2018 10:25

          У нас в городе его в кофейнях раздают бесплатно.


        1. Stannis
          15.03.2018 23:06

          Я очень хочу верить, что это шутка…


        1. Squoworode
          17.03.2018 09:50

          Можно купить или можно продать?


    1. safari2012
      16.03.2018 07:12

      Кофемашина у вас в собственности, или, как это часто бывает, в лизинге? Если второй вариант, то как фирма, владеющая и обслуживающая агрегат, отнеслась к данному моду?


  1. little-brother
    14.03.2018 23:41
    +2

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


    1. latonita
      15.03.2018 01:08
      +3

      А нельзя без ардуинов? Просто поставить бак с водой выше и самотёк по трубке. Назовём это «модифицированная поилка для птиц». Зачем тут электричество вообще?)


      1. Slimer Автор
        15.03.2018 07:34

        как доливать воду в бак? если менять бутыли, то как обеспечить герметичное соединение новой бутыли и шланга?


        1. axmetishe
          15.03.2018 08:39

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


        1. latonita
          15.03.2018 09:38

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


      1. HueyOne
        15.03.2018 14:45

        Переполнение стоками наступит неожиданно..


    1. KonstantinSpb
      15.03.2018 01:13
      +3

      Такие же мысли, поплавковый клапан и бутылка сверху и вуаля, сразу не нужны насос, ультразвуковой датчик и доп. шланг.
      На али ищется по названию float valve switch
      image


      1. belyvoron
        15.03.2018 07:27

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


        1. Slimer Автор
          15.03.2018 07:35

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


          1. elve
            15.03.2018 08:45

            Деревянный каркас для установки бутыли + приемная часть от любого самого дешевого кулера. А оттуда уже шланг к резервуару и клапану =).


    1. Slimer Автор
      15.03.2018 07:33

      Идеи интересные, спасибо. Но вот с доливом не согласен. При обдумывании идеи, я тоже думал поместить бутыль выше, но для этого нужно делать какое то крепление бутыли, например к трубе (фото), но не у всех такая труба вообще есть и как сделать разъемное, герметичное соединение шланга и бутыли в перевернутом виде? (по типу диспенсера наверно?), а насчет помпы от батареек, то видимо придется нажимать кнопку ручками, тогда это уже не автоматическая систему, а постоянно держать помпу включенной, но держать клапан закрытым, тоже идея не состоятельна.


      1. latonita
        15.03.2018 09:42

        Разъёмное соединение и трубочки надо взять в аквариумном магазине. Там и соединители и краники для воздуха есть. Подойдут.


  1. robux
    15.03.2018 09:43

    Всё отлично сделано — не слушай критиков.
    Только под левую бутылку низкую табуретку (подставку) поставь, чтоб не наклоняться, когда меняешь бутыль.
    А вместо правой бутыли было бы неплохо каналью… но она у вас далеко, да, я помню.


  1. Mishootk
    15.03.2018 10:25

    Вот что-то фантазия у вас разыгралась с доливом, клапаны какие-то, емкости… Откройте машину, от гнезда, куда подсоединяется контейнер с водой, отходит силиконовая трубка. Два способа:
    1. Отсоединить трубку от гнезда и нарастить трубкой до бутыли. Теряете возможность пользоваться штатным бункером для воды (на случай одна девочка в офисе, кофе хочется, вода кончилась, новых 19л не закинуть на подставку).
    2. В разрыв трубки поставить тройник, обратный клапан в сторону бункера. Полный комфорт и автономность.

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

    Извините, что без электроники.


    1. Slimer Автор
      15.03.2018 10:27

      думаете не будет проблем с прошивкой кофемашины? ведь он требует наличия какого то давления в бункере воды, иначе вываливает ошибку о низком уровне, насос постоянно держать включенным?


      1. Mishootk
        15.03.2018 10:34

        Не требует. Датчик уровня поплавковый с герконом. Перемыкается/размыкается обманкой (можно выключатель вывести, который будет всегда говорить «вода есть». Даже давление не нужно создавать. Подсос идет вибрационным насосом, который даже завоздушивание просасывает. С пола воду конечно не поднимет, но из бутыли на уровне стола по тонкому шлангу должен всосать. Только шланг должен быть не длинный, машина при слишком большой воздушной пробке (таймаут работы насоса всухую) встает в ошибку.
        При желании можно внешний подсасывающий насос релюшкой подключить к штатному (но в нем надобности нет). Не бойтесь разобрать машину, сложная там только плата управления, а все исполнительные механизмы тривиальные и управляются без всякой цифры (только питание и замыкание-размыкание). Только датчик температуры сопротивление в плату отдает, остальные датчики — это концевики.


      1. Mishootk
        15.03.2018 10:37

        А вот полезное, что можно для вас сделать — это холодильничек для молока. Иначе к вечеру капучино кисленький получите.


        1. safari2012
          16.03.2018 07:20

          не получится. из молока, которое даже только «задумалось», не то что прокисло, пенки не будет.


    1. DiJey
      15.03.2018 14:42

      Где купить можно? :)


      1. Slimer Автор
        15.03.2018 14:43

        Обращайтесь в телеграм, соберу, о цене договоримся :)


  1. serafims
    15.03.2018 11:56

    Было бы интересно в поддон капельный «пшикать» чистой водой для его промывки и недопущения образования там залежей отходов. И все это смывалось бы вниз…
    Еще для размышлений — вставить между кнопкой «свари кофе» и платой условно монетоприемник, чтобы каждый, кто хочет выпить кофе — кидал рублей 20, а тот, кто почистил аппарат, мог себе забрать «куш»)


    1. little-brother
      15.03.2018 12:19
      +1

      Контакт с деньгами перед едой — не лучшая идея с точки зрения гигиены.


    1. safari2012
      16.03.2018 07:21

      там очень быстро нарастает бактериальная пленка, которую смыть можно только с моющими средствами.


  1. norguhtar
    15.03.2018 13:16
    -2

    Фига заморочились. А надо было то купить обычное пластиковое ведро на 5 литров :) Туда можно сваливать сливать все отходы и тащить их как наполнится до туалета. И нести удобно и сливать.


    1. Slimer Автор
      15.03.2018 14:44

      поправка — кофемашина стоит около стола переговоров, ведро с гадостями вообще не к месту будет)


      1. norguhtar
        15.03.2018 15:59

        А сейчас прям верх эстетики :) Ведро можно заныкать куда-то недалеко.


  1. HueyOne
    15.03.2018 14:38
    +2

    На заднем фоне труба для кофе?


  1. Lodeon
    15.03.2018 14:44

    Да ну нафиг.

    У меня дома профессиональная кофемашина, там по умолчанию (из коробки) забор воды из фильтра и бутыли организован и слив из поддона в бутыль или канализацию. У меня конкретно стоит фильтр брита для кофемашин и слив в канализацию. А выбить из рожка жмых в кнок-бокс вообще секундное дело, и в отличие от автоматов требует минимального обслуживания.

    Так что наши руки не для скуки


    1. Slimer Автор
      15.03.2018 14:44

      сколько стоит такая профессиональная кофемашина?)


      1. Lodeon
        15.03.2018 14:47

        Нет, ну мысль понятна. Но там совсем другая история со вкусом кофе.

        Но да, цена в Мск на Alex Duetto 182 тыр. Нужна еще очень недешевая кофемолка… у меня с коническими жерновами.


    1. safari2012
      16.03.2018 07:23

      Так у него проблема с канализацией. Так что одного ведра все равно не избежать.


  1. bluetooth
    15.03.2018 16:42

    Уберите тройник подальше от кофемашины! Техника безопасности прежде всего!


  1. amaksr
    15.03.2018 17:11

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


  1. cab404
    15.03.2018 17:49

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

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


  1. Alex_Sa
    15.03.2018 23:02

    «Честно говоря, очень тяжело работать с Arduino, который изначально не заточен под псевдопараллельность задач»
    Рессурсов атмеловских микроконтроллеров вполне хвататет для FreeRTOS. А там гораздо проще работать с мультипоточностью.
    Вот есть конкретно под ардуино — create.arduino.cc/projecthub/feilipu/using-freertos-multi-tasking-in-arduino-ebc3cc


  1. pavel_raskin
    15.03.2018 23:07

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


  1. edgi
    15.03.2018 23:07

    Есть такой интересный уровень жидкости Xkc-y25-v бесконтактный уровня жидкости. Очень хорошие отзывы у него на mysku. Определяет жидкость через 2 толстых 2х сторонних скотча


    1. safari2012
      16.03.2018 07:31

      там внутри самый обычный емкостной датчик на ttp223, с ценой готового модуля (красный с круглой антеннкой) в 10 раз дешевле…


  1. qq315
    15.03.2018 23:07

    Идея отличная, но есть сомнение в том что насос и шланг от него предназначены для питьевой воды.


    1. Alex_Sa
      16.03.2018 00:06

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


  1. kolu4iy
    16.03.2018 09:30

    Полгода уже думал, что хабр не торт и теперь все ICO майнинг webpack. А нет, всё хорошо :)


  1. AndreyYu
    16.03.2018 10:40

    Я правильно понимаю из написанного вначале, что вместо того, чтобы переставить кофе-машину поближе к месту возможного сливания жидкости вы решили придумать как туда не ходить и изобрели «катетер»?:)


  1. SantaCluster
    16.03.2018 10:53

    ну чего вы на человека накинулись? ну да, можно было сделать самотёк, без электроники, купить дорогущую технику и тп. но во-первых, человек заморочился сделать автоматизацию с помощью имеющегося ардуино; а во-вторых, самотёк или покупка — не соят внимания аудитории хабра. Я прочитал с интересом, написано достаточно увлекательно. Наверняка кого-то эта статья натолкнёт на новую идею или решение проблемы.
    Молодец, продолжай дальше


  1. eexo
    16.03.2018 10:57

    Круто) Для полноты прогресса осталось на 3д принтере напечатать крышку ёмкости для воды, сразу со штуцером для шланга и крепежом для сенсора.


  1. borisxm
    16.03.2018 12:28

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


    1. safari2012
      16.03.2018 16:31

      У меня точно такой же датчик над аквариумом года 3-4 трудится. До сих пор, как новенький.


  1. Jeyko
    16.03.2018 21:20

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