Кот + Arduino =?

в 16:01, , рубрики: arduino, diy или сделай сам, Fibaro, z-wave, котэ, умный дом, метки: , , , ,

Что может быть общего между двумя этими объектами?

Кот + Arduino =?

Идея

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

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

Оборудование и тесты

К плате были подключены сервомашинка Towerpro MG996R, Z-Wave реле Fibaro FGS221 и кнопка со светодиодом. Кнопку добавил в качестве бонуса параллельно реле и вывел ее на стену.

Кот + Arduino =?

По факту сервомашинка питается от БП 5V 2A. От него же запитана плата по USB.

Схема подключения и код:

Кот + Arduino =?

Код для Arduino
#include <Servo.h>            // подключаем библиотеку Servo

Servo flush;                  // создаем объект для управления сервой

const int buttonPin = 2;      // номер пина кнопки
const int led =  4;          // номер пина светодиода

int buttonState = 0;          // переменная для чтения статуса кнопки
int flag = 0;                 // флаг по умолчанию сброшен
unsigned long holdTime = 0;   // время начала события
unsigned long blinkTime = 0;  // время начала события
unsigned long loadTime = 0;   // время начала события

void setup() {
  pinMode(led, OUTPUT);       // задаем пин светодиода как выход
  pinMode(buttonPin, INPUT);  // задаем пин кнопки как вход
  flush.attach(3, 8, 140);    // привязываем серву к пину 3 и задаем мин/макс угол
  flush.write(8);             // поворачиваем серву в положение по умолчанию
}

void loop(){
  buttonState = digitalRead(buttonPin);    // проверяем положение кнопки

  if (buttonState == LOW && flag == 0) {   // если кнопка не нажата и флаг не установлен
    flush.write(8);                        // поворачиваем серву в положение по умолчанию
    digitalWrite(led, LOW);                // включаем светодиод
  }
  if (buttonState == HIGH && flag == 0) {  // если кнопка нажата и флаг не установлен
    delay(100);                            // защита от дребезга контактов кнопки
    flush.write(140);                      // поворачиваем серву на заданный угол
    flag = 1;                              // устанавливаем флаг
    holdTime = millis();                   // включаем таймер удержания кнопки
  }
  if (buttonState == HIGH && flag == 1 && millis()-holdTime > 200) {  // если кнопка была нажата более X мс
    flag = 0;                              // сбрасываем флаг
    blinkTime = millis();                  // включаем таймер мигания светодиода
    do {
      digitalWrite(led, LOW);              // выключаем светодиод
      delay(200);
      digitalWrite(led, HIGH);             // включаем светодиод
      delay(200);
    } 
    while (millis()-blinkTime < 5000);     // мигаем светодиодом X мс
    flush.write(8);                        // поворачиваем серву в положение по умолчанию
    loadTime = millis();                   // включаем таймер ожидания наполнения бачка
    do {
      digitalWrite(led, LOW);              // выключаем светодиод
      delay(200);
      digitalWrite(led, HIGH);             // включаем светодиод
      delay(200);
    } 
    while (millis()-loadTime < 54000);     // мигаем светодиодом X мс (время полного наполнения бачка)
  }
  if (buttonState == LOW && flag == 1 && millis()-holdTime <= 200) {  // если кнопка была нажата менее X мс
    flag = 0;                              // сбрасываем флаг
    blinkTime = millis();                  // включаем таймер мигания светодиода
    do {
      digitalWrite(led, LOW);              // выключаем светодиод
      delay(200);
      digitalWrite(led, HIGH);             // включаем светодиод
      delay(200);
    } 
    while (millis()-blinkTime < 2000);     // мигаем светодиодом X мс
    flush.write(8);                        // поворачиваем серву в положение по умолчанию
    loadTime = millis();                   // включаем таймер ожидания наполнения бачка
    do {
      digitalWrite(led, LOW);              // выключаем светодиод
      delay(200);
      digitalWrite(led, HIGH);             // включаем светодиод
      delay(200);
    } 
    while (millis()-loadTime < 30000);      // мигаем светодиодом X мс
  }
}

Видео первой версии алгоритма с Z-Wave

Эта версия отличается от финальной только задержкой перед возможностью повторного нажатия кнопки

Задержка равна периоду полной перезарядки бачка водой.

Реализация

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

Кот + Arduino =?

Электронная часть размещена в распаячных коробках за инсталляцией.

Кот + Arduino =?

Ручное управление может осуществляться как кнопкой, так и через приложение для Fibaro HomeCenter.

Кот + Arduino =?

Используется два режима спуска:

  1. При коротком нажатии (<200 мс) спускается половина воды.
  2. При удержании кнопки более 200 мс, бачок опустошается целиком.

Z-Wave реле настроено на второй режим.

Демонстрация работы устройства

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

Заключение

К сожалению, котэ на видео не будет, так как он съехал, а желание реализовать задуманное у меня осталось.

Ну и бонусом :)

Автор: sisaenkov

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js