Умный лабиринт для крыс на Iskra JS
- Платформа: Iskra JS
- Язык программирования: JavaScript
- Тэги: Iskra JS, лабиринт, крыса, конструктор ПВХ.
Что это?
Простота содержания хомячков, мышей и крыс обманчива — зверькам нужен простор для игр, а в квартире найти его непросто.
Для наших питомцев мы придумали и сделали интерактивный лабиринт — чтобы крысам было где побегать и порезвиться, а мы могли следить за их самочувствием, контролировать количество съеденной пищи и играть с ними даже не находясь дома.
Множество дверей, подсветка и даже кормушка управляются через веб-интерфейс, а логика работы контроллера написана на JavaScript.
Что нам понадобится?
- Микросервопривод FS90 17 шт.
- Пластина мега (#Структор) 42 шт.
- Блок питания 5 Вольт 5 Ампер
- Блок питания 12 Вольт 2 Ампера
- Большая плоская коробка
- Прозрачная крышка
Как собрать?
- Возьмите три пластины «мега». Две из них разрежьте так, чтобы получились четыре пластины 13×7 шипов. Они будут стенами лабиринта. Вставьте стены в третью пластину «мега» #структора.
- С помощью двух панелей «крепление микросервопривода 3×4 шипа» и трех панелей («пластина 2×3 шипа») сделайте «домик» для микросервопривода. Полностью домик собирать не обязательно.
- Возьмите пластину «мега» и разрежьте её на три части 15×5 шипов. Это будут двери лабиринта. Возьмите качалку для микросервопривода овальной формы. Вставьте её в панель #структора «крепление качалки 2×4 шипа» и прикрутите к валу сервопривода. Прикрепите дверь к качалке с помощью панелей #структора 2×3 шипа.
- Готовый механизм двери разместите внутри стен лабиринта так, чтобы дверь в закрытом состоянии перекрывала проход для крысы. Для этого сделайте вырез в стене шириной чуть больше ширины двери. Сделайте в середине блока отверстие для вывода проводов. Проденьте провода в это отверстие.
- Сделайте 11 блоков стен и 15 дверей. Разместите их так, чтобы крысе было интересно бегать между ними. Для удобства поставьте перемычки между блоками из оставшихся деталей #структора длиной 5–6 шипов.
- Соберите карусельку с помощью #структора из набора «крепления моторов и датчиков линии». Установите на вал мотора втулку, а затем пластину «мега».
- Управление каруселькой сделайте с помощью инфракрасного датчика движения и силового ключа. Схема подключения приведена на рисунке.
- Разместите датчик и силовой ключ в пустом блоке лабиринта.
- В другом свободном блоке соберите кормушку. Дверцу кормушки сделайте по аналогии с дверями лабиринта.
- Разместите лабиринт внутри большой плоской коробки. В дне коробки сделайте отверстие для проводов и мотора карусельки. В крышке коробки сделайте прорези для дверей.
- Возьмите Iskra JS и установите на нее Ethernet Shield 2. Выше установите Troyka Shield.
- С помощью 3-проводного шлейфа «папа-мама» удлините кабели микросервоприводов и подведите их к Iskra JS.
- Iskra JS имеет 18 выводов ШИМ, к которым можно подключить сервоприводы. Используйте Troyka Shield для подключения 3-проводных шлейфов. Аналогично используйте пины SCL и SDA. Пин P3 оставьте свободным для подключения к нему светодиодной ленты. Возьмите гнездо питания 2,1 мм и с помощью проводов «папа-папа» и соедините пин 5V Iskra с плюсом клеммника, а пин GND Iskra с минусом клеммника. В результате должна получиться такая схема:
Не стоит пробовать питать лабиринт от USB компьютера. Подключайте USB только при включенном источнике питания!
- По периметру коробки проложите светодиодную ленту. Подключите ее к источнику питания 12 Вольт. Управляющий провод ленты подключите к пину P3 на плате Iskra JS. Соедините «минус» источника питания с «минусом» Iskra JS.
- Подключите один конец патч-корда витой пары в разъем Ethernet своего устройства. Второй конец подключите к своему Wi-Fi роутеру.
- Подключите кабель microUSB к Iskra JS и своему компьютеру.
- Теперь осталось только подключить камеру и настроить трансляцию on-line.
Алгоритм
- Устанавливаем socket-соединение c сервером по протоколу TCP.
- Обновляем данные с помощью TCP-запроса к серверу.
- Открываем или закрываем двери лабиринта по команде сервера.
- Включаем подсветку диодной лентой, если приняли команду «напугать».
- Открываем кормушку, если приняли команду «покормить».
- Повторяем TCP-запрос и его обработку каждые 3 секунды.
Исходный код
- Создайте блок для сервоприводов. Каждые 100 миллисекунд необходимо обновлять углы открытия дверей. Такая частота необходима для плавной работы дверей. Минимальные и максимальные углы сервоприводов подберите экспериментально.
// подключаем библиотеку 'servo' для работы с сервоприводами var servo = require('@amperka/servo'); // создаем объект для хранения информации о 15 сервоприводах. // servo - объект для работы с сервоприводом. // state - текущее состояние двери ('o' - открыто, 'c' - закрыто) // angle - угол сервопривода в данный момент // min - минимальный угол сервопривода. Соответствует полностью закрытой двери // max - максимальный угол сервопривода. Соответствует полностью открытой двери var doors = { d1: {servo: servo.connect(A0), state: 'c', angle: 45, min: 6, max: 50}, d2: {servo: servo.connect(A1), state: 'c', angle: 45, min: 19, max: 60}, d3: {servo: servo.connect(A2), state: 'c', angle: 45, min: 5, max: 50}, d4: {servo: servo.connect(A3), state: 'c', angle: 45, min: 17, max: 50}, d5: {servo: servo.connect(P0), state: 'c', angle: 45, min: 20, max: 60}, d7: {servo: servo.connect(P2), state: 'c', angle: 45, min: 0, max: 50}, d9: {servo: servo.connect(P5), state: 'c', angle: 45, min: 19, max: 70}, d10: {servo: servo.connect(P6), state: 'c', angle: 45, min: 10, max: 50}, d11: {servo: servo.connect(P8), state: 'c', angle: 45, min: 1, max: 50}, d12: {servo: servo.connect(P9), state: 'c', angle: 45, min: 0, max: 50}, d13: {servo: servo.connect(P11), state: 'c', angle: 45, min: 5, max: 60}, d14: {servo: servo.connect(P12), state: 'c', angle: 45, min: 5, max: 50}, d15: {servo: servo.connect(P13), state: 'c', angle: 45, min: 20, max: 90}, d16: {servo: servo.connect(SDA), state: 'c', angle: 45, min: 14, max: 75}, d17: {servo: servo.connect(SCL), state: 'c', angle: 45, min: 4, max: 50} }; // каждые 100 миллисекунд обновляем состояние сервоприводов setInterval(function() { for (var door in doors) { // если для сервопривода установлено состояние 'c' ("закрыто") if (doors[door].state === 'c') { // если дверь закрыта не полностью, уменьшаем угол сервопривода if (doors[door].angle > doors[door].min) { doors[door].angle -= 2; } } // если для сервопривода установлено состояние 'o' ("открыто") if (doors[door].state === 'o') { // если дверь открыта не полностью, увеличиваем угол сервопривода if (doors[door].angle < doors[door].max) { doors[door].angle += 5; } } // изменяем управляющий сигнал на сервопривод doors[door].servo.write(doors[door].angle); } }, 100);
- Создайте блок управления диодной лентой.
//Настраиваем управляемую диодную ленту SPI1.setup({baud:3200000, mosi:P3, sck:A5, miso:P2}); //Резервируем память для управления 32 диодами var arr = new Uint8ClampedArray(32*3); // будем включать пугатель на scareCooldown миллисекунд var scareCooldown = 3000; // функция активации пугателя function activateScare() { var c = 0; // каждые 100 миллисекунд обновляем цвет ленты var timerID = setInterval(function () { c++; // пиксели окрашиваем в красный цвет в помощью функции синуса for (var p = 0; p < arr.length; p += 3) { arr[p ] = (1 + Math.sin(c*2) ) * 126; arr[p+1] = 0; arr[p+2] = 0; } // записываем в ленту новые значения цветов SPI1.send4bit(arr, 0b0001, 0b0011); }, 100); // устанавливаем время мерцания ленты scareCooldown миллисекунд setTimeout(function () { // по истечению этого времени останавливаем таймер мерцания clearInterval(timerID); // каждый пиксель зажигаем белым светом for (var i = 0; i < arr.length; i += 3) { arr[i ] = 100; arr[i+1] = 100; arr[i+2] = 100; } SPI1.send4bit(arr, 0b0001, 0b0011); }, scareCooldown); }
- Теперь по аналогии с дверями создайте блок управления кормушкой.
// аналогично создаем объект для кормушки var feed = {servo: servo.connect(P1), angle: 0, min: 9, max: 57, cd: 0}; // будем включать кормушку на feedCooldown миллисекунд var feedCooldown = 10000; // активируем кормушку function activateFeed() { // будем открывать кормушку только на feedCooldown миллисекунд feed.cd = feedCooldown; // а обновлять состояние кормушки каждые updatePeriod миллисекунд var updatePeriod = 100; // по аналогии с дверями лабиринта сделаем плавное открытие var timerID = setInterval(function() { // плавно открываем кормушку if (feed.cd > 0) { if (feed.angle > feed.min) { feed.angle -= 5; } } else { // если время истекло, плавно закрываем кормушку if (feed.angle < feed.max) { feed.angle += 2; } else { clearInterval(timerID); } } feed.servo.write(feed.angle); // с каждой итерацией feed.cd уменшается на updatePeriod feed.cd -= updatePeriod; }, updatePeriod); }
- Создайте блок сокет-соединения. Каждые 3 секунды на сервер отправляется запрос, ответ на который содержит данные о состоянии всех дверей в лабиринте, а также кормушки и светодиодной ленты.
// Настраиваем соединение с Ethernet Shield 2 SPI2.setup({baud: 3200000, mosi: B15, miso: B14, sck: B13}); var eth = require('WIZnet').connect(SPI2, P10); // подключаем библиотеку 'net' для работы с сетью Интернет var net = require('net'); // подключаем Ethernet Shield 2 к интерфейсу SPI2 eth.setIP(); // создаем сокет-соединение на указанный IP адрес сервера и порт net.connect({host: '192.168.10.178', port: 1337}, function(socket) { // каждые 3000 миллисекунд посылаем запрос на обновление состояний дверей setInterval(function() { socket.write('Get'); }, 3000); // обрабатываем получение данных от сервера socket.on('data', function(recieved) { // разворачиваем принятые данные в javascript объект var data = JSON.parse(recieved); if (data === undefined) { return; } // для каждой двери обновляем текущее состояние for (var door in data.doors) { doors[door].state = data.doors[door].st; } // если с сервера пришла команда открыть кормушку, активируем ее if (data.feed === 'o') { activateFeed(); } // то же самое для накаливания обстановки if (data.scare === 'o') { activateScare(); } }); // обрабатываем отключение от сервера socket.on('close', function() { print('WARNING: connection closed'); }); });
- Теперь объедините все блоки кода в один файл и вы получите готовый скрипт для работы лабиринта. Не забудьте перенести функции
require()
в начало своего скрипта.
Исходный код проекта целиком доступен на github’е.
Демонстрация работы устройства
Что дальше?
В данном проекте можно использовать любую другую плату с выходом в интернет. Если у вас уже есть Iskra JS, можно добавить к ней Wi-Fi модуль ESP8266 или даже GPRS Shield, немного изменив скрипт. Фантазия не ограничивается дверями и каруселькой. Можно добавить любые сенсоры в форм-факторе Troyka Module.