Оглавление:
Видео: Контроль доступа к корму для кошек (ESP8266 + серводвигатель + 3D-печать): 5 шагов (с изображениями)
2025 Автор: John Day | [email protected]. Последнее изменение: 2025-01-13 06:58
Этот проект повторяет процесс, который я использовал для создания автоматической миски для кошачьего корма для моего пожилого диабетического кота Чаза. Видите ли, ему нужно позавтракать, прежде чем он сможет получить инсулин, но я часто забываю взять его блюдо с едой перед сном, что портит его аппетит и нарушает его график приема инсулина. В этом блюде используется серводвигатель, который закрывает крышку над едой в период с полуночи до 7:30 утра. Скетч Arduino микроконтроллера NodeMCU ESP8266 использует протокол сетевого времени (NTP) для управления расписанием.
Этот проект может не подойти более молодым, более активным кошкам. Чаз настолько стар и хрупок, что не склонен пытаться вскрыть миску, но это возможно.
Если вы новичок в Arduino или ESP8266, вам могут понравиться следующие предварительные руководства:
- Учебные пособия по классу Arduino
- Учебный курс "Интернет вещей"
Запасы
- 3D-принтер (я использую Creality CR-10s Pro)
- Нить для 3D-принтера (я использую золотой PLA)
- NodeMCU ESP8266 wifi микроконтроллер
- USB-кабель (от A до microB)
- Адаптер питания USB
- Микро серводвигатель
- Маленькая отвертка и винты
- Монтажный провод
- Выводы заголовка
- Плата Perma-proto
Чтобы быть в курсе того, над чем я работаю, подписывайтесь на меня на YouTube, Instagram, Twitter, Pinterest и подписывайтесь на мою рассылку. Как партнер Amazon я зарабатываю на соответствующих покупках, которые вы совершаете с помощью моих партнерских ссылок.
Шаг 1: детали, напечатанные на 3D-принтере
Держатель миски для кошачьего корма основан на дизайне Арди Лая на Thingiverse. Я сделал его больше, чтобы вместить миску моей кошки, а также сделал его короче, поскольку масштабирование сделало его слишком высоким. Я добавил держатель для микро-серводвигателя и пару отверстий для кабелей, идущих внутрь.
Я смоделировал простую крышку с помощью Tinkercad, предназначенную для крепления к рупору сервопривода. Вы можете получить мой дизайн прямо из Tinkercad и / или загрузить файлы STL, прикрепленные к этому шагу.
Я напечатал детали на своем принтере Creality CR-10s Pro золотой нитью PLA.
Раскрытие информации: на момент написания этой статьи я работал в Autodesk, производящей Tinkercad.
Шаг 2: прикрепите крышку к серводвигателю
Я использовал небольшое сверло, чтобы увеличить размер отверстий на роге сервопривода, а затем использовал винты, чтобы прикрепить сервопривод к крышке, напечатанной на 3D-принтере.
Шаг 3: Создайте схему NodeMCU ESP8266
Схема управляется микроконтроллером Wi-Fi NodeMCU ESP8266. Я использовал контакты на плате Perma-Proto, чтобы сделать микросервомотор легко отсоединяемым. Разъемы сервопривода подключаются к NodeMCU следующим образом:
Желтый провод сервопривода: NodeMCU D1
Красный провод сервопривода: питание NodeMCU (3V3 или VIN)
Черный провод сервопривода: заземление NodeMCU (GND)
Шаг 4: Загрузите код и тест Arduino
Установите мотор / крышку в сборе в вырез в форме мотора на детали держателя чаши, напечатанной на 3D-принтере. Подключите разъем двигателя к контактам разъема платы микроконтроллера и подключите схему к компьютеру с помощью кабеля USB.
Скетч Arduino использует протокол сетевого времени для получения текущего времени, а затем открывает или закрывает крышку в соответствии с жестко запрограммированным расписанием. Скопируйте следующий код, обновите свои учетные данные Wi-Fi и смещение времени UTC и загрузите его на свою плату NodeMCU с помощью Arduino IDE.
#включают
#include #include #include ESP8266WiFiMulti wifiMulti; // Создаем экземпляр класса ESP8266WiFiMulti с именем 'wifiMulti' WiFiUDP UDP; // Создаем экземпляр класса WiFiUDP для отправки и получения IPAddress timeServerIP; // time.nist.gov Адрес NTP-сервера const char * NTPServerName = "time.nist.gov"; const int NTP_PACKET_SIZE = 48; // Отметка времени NTP находится в первых 48 байтах байта сообщения NTPBuffer [NTP_PACKET_SIZE]; // буфер для входящих и исходящих пакетов Servo myservo; // создаем сервообъект для управления серво // двенадцать сервообъектов могут быть созданы на большинстве плат int pos = 0; // переменная для хранения позиции сервопривода void setup () {myservo.attach (5); // прикрепляет сервопривод на выводе 5, также известный как D1, к сервообъекту // по умолчанию открывается крышка Serial.println ("открытие крышки"); for (pos = 95; pos> = 0; pos - = 1) {// изменяется от 95 до 0 градусов myservo.write (pos); // указываем сервоприводу перейти в позицию в переменной 'pos' delay (15); // ожидает 15 мсек, пока сервопривод достигнет позиции} Serial.begin (115200); // Запускаем последовательную связь для отправки сообщений компьютеру delay (10); Serial.println ("\ r / n"); startWiFi (); // Пытаемся подключиться к некоторым заданным точкам доступа. Затем дождитесь соединения startUDP (); if (! WiFi.hostByName (NTPServerName, timeServerIP)) {// Получить IP-адрес сервера NTP Serial.println («Ошибка поиска DNS. Перезагрузка.»); Serial.flush (); ESP.reset (); } Serial.print ("IP-адрес сервера времени: / t"); Serial.println (timeServerIP); Serial.println ("\ r / nОтправка запроса NTP…"); sendNTPpacket (timeServerIP); } длинный интервал без знакаNTP = 60000; // Запрос времени NTP каждую минуту без знака long prevNTP = 0; беззнаковый длинный lastNTPResponse = millis (); uint32_t timeUNIX = 0; беззнаковый длинный prevActualTime = 0; void loop () {беззнаковый длинный currentMillis = millis (); if (currentMillis - prevNTP> intervalNTP) {// Если с момента последнего запроса NTP прошла минута, prevNTP = currentMillis; Serial.println ("\ r / nОтправка запроса NTP…"); sendNTPpacket (timeServerIP); // Отправляем NTP-запрос} uint32_t time = getTime (); // Проверяем, пришел ли ответ NTP, и получаем (UNIX) время if (time) {// Если получена новая временная метка timeUNIX = time; Serial.print ("Ответ NTP: / t"); Serial.println (timeUNIX); lastNTPResponse = currentMillis; } else if ((currentMillis - lastNTPResponse)> 3600000) {Serial.println ("Более 1 часа с момента последнего ответа NTP. Перезагрузка."); Serial.flush (); ESP.reset (); } uint32_t actualTime = timeUNIX + (currentMillis - lastNTPResponse) / 1000; uint32_t EasternTime = timeUNIX - 18000 + (currentMillis - lastNTPResponse) / 1000; if (actualTime! = prevActualTime && timeUNIX! = 0) {// Если с момента последней печати прошла секунда, prevActualTime = actualTime; Serial.printf ("\ rUTC время: / t% d:% d:% d", getHours (actualTime), getMinutes (actualTime), getSeconds (actualTime)); Serial.printf ("\ REST (-5): / t% d:% d:% d", getHours (EasternTime), getMinutes (EasternTime), getSeconds (EasternTime)); Serial.println (); } // 7:30 утра if (getHours (EasternTime) == 7 && getMinutes (EasternTime) == 30 && getSeconds (EasternTime) == 0) {// открываем крышку Serial.println ("открываем крышку"); for (pos = 95; pos> = 0; pos - = 1) {// изменяется от 95 до 0 градусов myservo.write (pos); // указываем сервоприводу перейти в позицию в переменной 'pos' delay (15); // ждет 15 мс, пока сервопривод достигнет позиции}} // полночь if (getHours (EasternTime) == 0 && getMinutes (EasternTime) == 0 && getSeconds (EasternTime) == 0) {// закрыть крышку Serial. println («закрытие крышки»); for (pos = 0; pos <= 95; pos + = 1) {// изменяется от 0 градусов до 95 градусов // с шагом в 1 градус myservo.write (pos); // указываем сервоприводу перейти в позицию в переменной 'pos' delay (15); // ждет 15 мс, пока сервопривод достигнет позиции}} / * // проверка if (getHours (EasternTime) == 12 && getMinutes (EasternTime) == 45 && getSeconds (EasternTime) == 0) {// закрываем крышку Serial.println («закрытие крышки»); for (pos = 0; pos = 0; pos - = 1) {// изменяется от 95 градусов до 0 градусов myservo.write (pos); // указываем сервоприводу перейти в позицию в переменной 'pos' delay (15); // ждет 15 мс, пока сервопривод достигнет позиции}} * /} void startWiFi () {// Пытаемся подключиться к некоторым заданным точкам доступа. Затем дождитесь подключения wifiMulti.addAP («ssid_from_AP_1», «your_password_for_AP_1»); // добавляем сети Wi-Fi, к которым вы хотите подключиться //wifiMulti.addAP("ssid_from_AP_2 "," your_password_for_AP_2 "); //wifiMulti.addAP("ssid_from_AP_3 "," your_password_for_AP_3 "); Serial.println («Подключение»); while (wifiMulti.run ()! = WL_CONNECTED) {// Подождите, пока Wi-Fi подключится delay (250); Серийный.принт ('.'); } Serial.println ("\ r / n"); Serial.print («Подключено к»); Serial.println (WiFi. SSID ()); // Сообщите нам, к какой сети мы подключены Serial.print ("IP-адрес: / t"); Serial.print (WiFi.localIP ()); // Отправляем IP-адрес ESP8266 на компьютер Serial.println ("\ r / n"); } void startUDP () {Serial.println ("Запуск UDP"); UDP.begin (123); // Начинаем прослушивание сообщений UDP на порту 123 Serial.print ("Локальный порт: / t"); Serial.println (UDP.localPort ()); Serial.println (); } uint32_t getTime () {if (UDP.parsePacket () == 0) {// Если нет ответа (пока) return 0; } UDP.read (NTPBuffer, NTP_PACKET_SIZE); // считываем пакет в буфер // Объединяем 4 байта временной метки в одно 32-битное число uint32_t NTPTime = (NTPBuffer [40] << 24) | (NTPBuffer [41] << 16) | (NTPBuffer [42] << 8) | NTPBuffer [43]; // Преобразование времени NTP в метку времени UNIX: // Время Unix начинается 1 января 1970 года. Это 2208988800 секунд по времени NTP: const uint32_t sevenyears = 2208988800UL; // вычтите семьдесят лет: uint32_t UNIXTime = NTPTime - семьдесят лет; return UNIXTime; } void sendNTPpacket (IP-адрес и адрес) {memset (NTPBuffer, 0, NTP_PACKET_SIZE); // установить для всех байтов в буфере значение 0 // Инициализировать значения, необходимые для формирования запроса NTP NTPBuffer [0] = 0b11100011; // LI, Version, Mode // отправляем пакет с запросом отметки времени: UDP.beginPacket (address, 123); // Запросы NTP поступают на порт 123 UDP.write (NTPBuffer, NTP_PACKET_SIZE); UDP.endPacket (); } встроенный int getSeconds (uint32_t UNIXTime) {return UNIXTime% 60; } inline int getMinutes (uint32_t UNIXTime) {return UNIXTime / 60% 60; } встроенный int getHours (uint32_t UNIXTime) {return UNIXTime / 3600% 24; }
Шаг 5: Используйте это
Проложите провода внутрь держателя чаши и подключите кормушку для кошек к розетке с помощью USB-адаптера переменного тока. Как написан простой код, он предназначен для загрузки в «открытом» состоянии и будет изменять положение крышки только в те временные рамки, которые указаны в скетче Arduino.
Спасибо, что подписались! Если вы сделаете свою собственную версию, я бы хотел увидеть ее в разделе «Я сделал это» ниже!
Если вам понравился этот проект, возможно, вас заинтересуют некоторые из моих других:
- Держатель призмы для радужных портретов
- Стена для хранения из фанеры с кошачьей башней
- Светодиодные фонари Mason Jar (крышка, напечатанная на 3D-принтере)
- Сухая коробка с нитью для 3D-принтера
- Аварийный источник питания USB (3D-печать)
- Светящиеся светодиодные жевательные конфеты
- 3D-печатный геометрический кашпо с дренажем
- Светящиеся цветы, напечатанные на 3D-принтере
- Как установить светодиоды под самокат (с Bluetooth)
Чтобы не отставать от того, над чем я работаю, подписывайтесь на меня на YouTube, Instagram, Twitter и Pinterest.