В этом материале описано проектирование, разработка и сборка прототипа подводного дрона на базе Raspberry PI и управление им с Android-смартфона. Статья может пригодиться как новичкам (изложены азы управления электродвигателями, диодами, камерами, гироскопом), так и опытным инженерам (они могут поглумиться над исполнением и решениями :)). В общем, если вы любитель сделать чего-то электронного своими руками — милости прошу к прочтению.
Я пересмотрел много передач по Discovery про изобретателей, и однажды захотелось сделать самому что-то интересное, да чтобы во все тяжкие: электромоторы, контроллеры, управление, камера. Купив много полезных (и не очень) девайсов, я стал думать, какой же проект будет прикольно сделать. Пришел к выводу, что летающих дронов хоть чем-то жуй, ездящих тоже, а вот с водой какой-то косяк (ха-ха, да я «немного» ошибался).
После серфинга в интернете я нашел довольно много решений, но большинство из них либо еще не вышли в массы и находились в состоянии прототипов, либо стоили некисло дорого (3++к енотов). Если интересно, то можете глянуть пару хороших здесь.
Забегая наперед, скажу, что у меня вышел рабочий прототип, который способен плавать на нескольких метрах глубины, со всеми плюсами и минусами. Сложно сказать, что в результате я получил продукт, которым можно легко управлять и что он сейчас готов сделать что-то большее, чем унять инженерный азарт. Но все узлы у него работают исправно, и главное, что мои ошибки и наработки могут помочь кому-то сделать что-то значимое (даже если для только него самого).
Так как работы было проделано действительно много, можно разделить все по следующим темам:
- В порядке бреда (затравочка)
- Выбор компонентов
- Программирование ESC
- Настройка Raspberry PI сервера
- Управление электродвигателями на Raspberry PI
- Гироскоп
- Управление светодиодами на Raspberry PI
- Протокол общения клиент-сервер
- Приложение на Android
- Видео Stream
- Управление с экрана и джойстиком
- Сборка и тестирование конструкций
- Выводы
В порядке бреда
Скажу сразу: я любитель, и большинство из того, что я делал, было сделано методом научного тыка, ибо собрать что-то и протестить на-а-амного веселее, чем просчитать и понять, что в теории оно не работает. Вариантов конструкции и идей было немалое количество, и были откровенно «глупые» реализации (одна из них будет описана чисто по приколу далее).
Первым и основным заданием было понять, каким образом можно сделать в бытовых условиях герметичный корпус и при этом передать момент на гребные винты.
Как обычно, в начале приходят не самые умные идеи (а думать дважды — не мой подход), и я попытался поэкспериментировать с передачей момента магнитами. Выбрал простую конструкцию и собрал такой вот «высокотехнологичный» девайс:
На шестеренку было прикручено по два магнита и соединены с двигателями (соблюдая все полярности магнитов), между шестернями пластина которая имитирует стенки корпуса. Если у вас проснулось желание закрыть статью и выколоть себе глаза — это нормальная реакция на увиденное, но я вас предупреждал в начале :)
Несмотря на кривизну, после запуска макета можно смело прокричать: «И все-таки она вертится» ©. Момент передается, детали вращаются, но за счет притяжения сильно возрастает трение. Следующий минус, помимо десятков остальных, в том что если стопнуть воображаемый винт, то магниты теряют «контакт» и второй раз уже сцепиться не могут из-за разности скоростей.
Даже если собрать такую конструкцию, использовав подшипники, нормальные шестерни и магниты, это будет далеко не самым лучшим решением, ибо КПД, простота реализации и просто здравый смысл хромают.
В итоге принято решение не выпендриваться и взять бесколлекторный движок, и при надобности залить лаком обмотку. Вынести за корпус (да-да, в самую воду) и просто загерметизировать выведенные провода. Это будет значительно проще, чем думать конструкцию с маслом и сальниками или еще какой-то сложный механизм, для того, чтобы удержать воду вне механики и электроники.
Итак, перейдем к более серьезным вещам.
Выбор компонентов
Далее список того, что было использовано при создании аппарата.
И остальное
- Гребные винты (одна из основных проблем)
- Cable Gland (а как же без них)
- Коробка
- Коробка
- и еще коробки, коннекторы, провода и прочее.
Программирование ESC
К сожалению, Afro ESC из коробки имеет только одно направление вращения, поэтому надо «шить». Самая засада в том, что надо ждать линкер из Китая, остальное детали. Предположим, что он у вас уже есть :)
Совет, который я встретил на просторах интернета, — купить USB хаб, чтобы в случае короткого замыкания сгорел он, а не ваш дорогой ноут. Но каждый волен выбирать свою судьбу :)
Качаем файлпрошивки на диск и программу для прошивки KKMulticopter Flashtool.
Теперь важно не натупить с подключением проводов, ибо последствия могут быть печальные для какого-то устройства. Краткий ликбез по ESC по проводам:
- Пара красный-черный толстых кабелей с бананом «папой» на конце. Силовое питание двигателя. Я подавал 12 вольт и ампер — сколько просило :)
- Красный — ВХОД плюс.
- Черный — ВХОД минус.
- Толстые провода красный-черный-желтый — питание на двигатель. Пока мы их не трогаем, но в дальнейшем будем соединять на аналогичные «цвета» электродвигателя.
- Тонкие провода управления и питания.
- Желтый — это непосредственно кабель, по которому передаем сигнал управления.
- Красный — выход 5в (в целом я его не использовал). Их есть несколько разных типов, если захотите — читайте.
- Черный — минус.
Подключаем тонкие проводак Linker’у: минус к минусу (черные) и сигнал на сигнал (желтые). Тонкий красный не трогаем и не подключаем. Далее даем питание на плату (черный и красный входы). Лично я использовал этот импульсный блок, но подойдет любой с похожими характеристиками.
Открываем программу прошивки и выбираем:
Programmer: Turnigy USB Linker or Afro USB Linker (зависит о того, что у вас есть).
Port: собственно тот USB, куда включили. Благо, выбор там не велик.
Baud rate: 9600.
Controller: atmega
И выбираем уже скачанный файл прошивки. Жмем кнопку «Run» и молимся :) Скоро прошивка успешно зальется на ESC, и все будет готово. Весь процесс можете посмотреть здесь:
Из
Настройка Raspberry PI сервера
Теперь перейдем к настройке Raspberry PI.
- Качаем последний дистрибутив системы тут.
- Скачиваеми устанавливаем Etcher.
- Вставляем пустую microSD флешку в картридер (тут уже сами думайте, где их взять).
- Открываем Etcher и выбираем zip или img Raspbian, который скачали на первом шаге.
- Нажимаем ’Flash!’
- Ждем окончания установки и извлекаем microSD.
- Вставляем флешку в наш Raspberry.
Для тестов нам будет достаточно «малинки», телефона на базе Android и любого Wi-Fi роутера с доступом к интернет. Если вы любитель консольного общения с устройствами, то вам ничего объяснять и не надо, сами справитесь. Для более ленивых — подключаем монитор, клавиатуру (HDMI и USB порты работают на «ура» из коробки), питание от какого-то USB-microUSB и грузим систему. Важно помнить, что на все двигатели подаем 12V, а на Raspberry — 5V. Также важно, если выключить резко питание на малину — может побиться операционная система (связано это с памятью самого устройства). Так что лучше подумать о бесперебойности.
Подключаем к сети Wi-Fi, и в целом система готова. Я бы советовал настроить ваш роутер и дать static IP адресс для малины, ибо подключаться будем именно по IP.
Если вы уже работали с Linux, то дальнейшие действия вам будут не дики. Самым простым способом создать серверное приложение будет NodeJS. Разобраться, что да как не составляет труда, так как в Гугле еще никого не банили. Открываем терминал и поехали:
sudo apt-get update sudo apt-get dist-upgrade sudo apt-get install -y nodejs
И проверочно запускаем node -v
, дабы точно понять, что все установилось.
Можно сразу слить весь проект с репозитория и запустить (ссылка будет в конце статьи), но разве мы здесь ради этого собрались? :) Теперь создаем папку нашего проекта mkdir ~/drone
и переходим в нее cd ~/drone
и инициализируем проект: npm init
. Установщик спросит название и индекс файл — укажем app.js
.
После инициализации ставим express: npm install express
. И создаем файл app.js: touch app.js
.
Для тех, кто работает с GUI (моник и клава), советую поставить Atom. В нем очень даже удобно писать js-код. Для остальных — Vim, Nano, MCEdit (и сами знаете).
Далее добавляем код в app.js и сохраняем файл:
'use strict'; const express = require('express'); const net = require('net'); const app = express(); const server = net.createServer((socket) => { socket.on('data', (data) => { var command = data.toString(); console.log(err); }); }).on('error', (err) => { console.log(err); // handle errors here // throw err; }); server.timeout = 0; // grab an arbitrary unused port. server.listen(49655, () => { console.log('opened server on', server.address()); });
И запускаем из консоли node app.js
в папке(!!) drone. Теперь у вас крутится сервер, который слушает подключения на 49655 порт. Запомним: наш локальный IP (ifconfigв консоли) и все подключения будем производить на IP:49655.
Сейчас давайте усложнять конструкции :)
Управление электродвигателями с Raspberry PI
Итак, начинаем самую веселую часть нашей работы — пишем управление на Raspberry PI. Идем в папку проекта ~/drone и устанавливаем PiGpioбиблиотеку:
sudo apt-get update sudo apt-get install pigpio npm install pigpio
Теперь небольшой ликбез по управлению ESC. Нам надо передать некую частоту на управляемый провод (желтый тонкий) (см. раздел «Программирование ESC»). Прошивка afro_nfet_besc30_r1 имеет диапазон
Создаем файлик engines.jsи в него добавляем JS-код:
//Константа состояния спокойствия const SERVO_ZERO = 1500; //Подключаем библиотеку 'pigpio' const Gpio = require('pigpio').Gpio; //Определяем наши 4 двигателя по пинам расбперри (пиновка будет объяснена чуть ниже) const servo1 = new Gpio(22, {mode: Gpio.OUTPUT}); const servo2 = new Gpio(10, {mode: Gpio.OUTPUT}); const servo3 = new Gpio(9, {mode: Gpio.OUTPUT}); const servo4 = new Gpio(27, {mode: Gpio.OUTPUT}); //Устанавливаем каждой плате состояние “спокойствия” servo1.servoWrite(SERVO_ZERO); servo2.servoWrite(SERVO_ZERO); servo3.servoWrite(SERVO_ZERO); servo4.servoWrite(SERVO_ZERO); //По вызову этого метода пишем значение в наш ESC module.exports.engines = { leftEsc: (value) => { servo1.servoWrite(value); }, rightEsc: (value) => { servo2.servoWrite(value); }, topLeftEsc: (value) => { servo3.servoWrite(value); }, topRightEsc: (value) => { servo4.servoWrite(value); } }
Дабы использовать этот код, пишем в app.js:
const engines = require('./engines.js').engines; engines.leftEsc(*VALUE[1100;1900]*);
Собственно говоря, servo1.servoWrite()
— и есть магическое управление. Подаем 1100 — двигатель крутится в реверсном направлении. Подаем 1900 — max forward. А вот распиновка нашей малины:
Если вкратце, то мы используем оранжевые GPIO. Одна пара GPIO 10 — GPIO 22, вторая GPIO 9 и GPIO 27 (логичнее было бы использовать 27;22 10;9, но при пайке не учел, и пришлось поменять). Если брать по порядочным числам (указаны серым), то это 13;15 и 19;21 контакты. На каждый из них подключаем желтые провода из ESC, а минус же объединяем в один GND, к примеру 39 контакт.
Осталось подключить остальное. Коннектим провода питания (красный и черный) Afro ESC к отдельному блоку питания(12v), подключаем моторы к желтый-красный-черный толстым проводам и уже можем играться. Например, допилить код и по интервалу подавать разные сигналы на пины. Небольшое видео, правда, там управление осуществляется с Android, но это опишу немного позже:
Гироскоп
Подключаем:
VCC к пину 1 (3.3V PWR)
GND к любому минусу
SCL к пину 5 (GPIO 3)
SDA к пину 3 (GPIO 2)
Подключение не сложное, а программно еще проще — хорошие люди сделали все до нас. На помощь спешат библиотеки i2c-busи i2c-mpu6050.
Устанавливаем в проект:
npm install i2c-bus npm install i2c-mpu6050
Создаем файл gyroscope.jsи добавляем:
const i2c = require('i2c-bus'); const MPU6050 = require('i2c-mpu6050'); const address = 0x68; const i2c1 = i2c.openSync(1); const sensor = new MPU6050(i2c1, address); var reading = false; var sensorData = {}; module.exports.gyroscope = { getData : () => { return JSON.stringify(sensorData); }, readRotation : () => { sensor.readRotation(function (err, rot) { if (err) { console.log(e); return; } console.log(rot); }); }, readSensor : () => { if (!reading) { reading = true; } sensor.read(function (err, data) { reading = false; if (err) { console.log(err); } else { sensorData = data; } }); } }
Запускаем метод readSensor
с какой-то периодичностью и забираем данные последнего опроса из getData
. Там будет много составляющих (x,y,z,a) о положении. Разобраться что к чему, честно, не успел. Были важнее задачи с управлением. Знаю, решение такое себе, но оно имело чисто ознакомительный характер, поэтому и актуальность результата не очень важна.
Raspberry PI Flashlight control
Потихоньку продолжаем наращивать функционал и на этот раз займемся светодиодами. У нас есть два XHP-50 диода и драйвер-контроля (см. раздел «Выбор компонентов»). Они очень хорошо греются, поэтому без радиаторов использовать их никому не рекомендую. На том же сайте, благо, они есть. Главное, не напутать с размером.
Итак, прикручиваем диоды на радиатор, паяем минус одного к плюсу другого (на них есть маркировка) и припаиваем минусовой и плюсовой провода:
Далее смотрим на наш контроллер и тоже паяем.
Питание — 12V плюс и минус, можно запитаться тем же, чем и питаем двигатели. Выводы на диод соединяем с ранее припаянными соответственно L- к минусу, L+ к плюсу. Аналоговый контакт (А) в данной реализации не нужен, оставляем пустым.
Теперь нас интересует цифровой вход (D) и земля (G). Коннектим цифру (D) на GPIO 11 и землю на многострадальный GND (любой, можно один). Теперь возвращаемся к нашей Raspberry PI, создаем файлик light.js и добавляем следующее:
//Наша знакомая библиотека const Gpio = require('pigpio').Gpio; //Создаем Gpio для нашего пина const light = new Gpio(11, {mode: Gpio.OUTPUT}); // Значение можно ставить от 0 до 255 (из доков по драйверу светодиода) const LIGHT_MIN = 0; const LIGHT_MAX = 255; //Нужно будет для вычислений const LIGHT_DIAPASONE = LIGHT_MAX - LIGHT_MIN; //Выключаем светодиод изначально (система стартует с включенными на максимум светодиодами) light.pwmWrite(LIGHT_MIN); //Экспортируем методы работы module.exports.light = { on: () => { //Передаем на драйвер значение 255 light.pwmWrite(LIGHT_MAX); }, off: () => { //Передаем на драйвер значение 0 light.pwmWrite(LIGHT_MIN); }, //Здесь принимаем значение в процентах от 0 до 100 set: (val) => { if(val < 0 || val > 100) return; //Вычисляем значение исходя из процента val = Math.round(LIGHT_MIN + LIGHT_DIAPASONE / 100 * val); console.log("Light:"+val); //Передаем на драйвер значение light.pwmWrite(val); } }
Запустить можем из нашего app.jsтак же, как и engines:
const light = require('./light.js').light; light.on(); light.off(); light.set(50);
Видеодемонстрация готового решения:
Если понять главную идею, то все предельно просто: подключил, подал сигнал, смотришь результат. Грубо говоря, это весь функционал контроля, который нам нужен для активизации элементов. Но все это бесполезно без какого-то контроллера, который и будет включать/регулировать все это, а это говорит о том, что надо построить коммуникацию между сервером и клиентом. Значит придумаем протокол :)
Протокол общения
Как вы поняли из первоначальной настройки Raspberry PI, общение будет произведено по сокет подключению. И нужен какой-то набор команд, который будет захардкожен на сервере и клиенте. Так как я сам себе д’артаньян, то решил использовать свой формат, ибо варианты, которые есть, не совсем подходят по критерию вес/читаемость. Строим, основываясь на базе модели управления, а это телефон с Android на борту.
Вот приблизительно и сама модель (программа будет описана чуть ниже). Экран разделен на две части. Левая отвечает за горизонтальную плоскость (вперед и назад), правая — за вертикальную.
Ставите палец в какой-то области — это считается точкой отсчета и контроля парой двигателей, но при этом это точка спокойствия.
Если ведете его вертикально вверх — потихоньку повышается скорость вращения обоих двигателей в прямом направлении с мощностью от 0 до максимума (зависит от расстояния от точки касания до текущей).
Если двигаем вниз: оба двигателя вращаются в реверсном направлении, со скоростью, зависимой от удаления от точки касания.
Если вправо: левый крутится в прямом, правый в реверсном.
То есть по факту нам нужно знать угол отклонения от точки касания (где верх = 90, низ — 90, право 0, лево 180) и коэффициент скорости — удаленность пальца от точки касания (от 0 до 100). Конечные команды выглядит так:
C:L;A:45;V:35; C:R;A:0;V:100; C:LIGHT;V:50;
С — любая команда начинается с этой буквы (command);
:— разделитель ключ-значения;
;— разделитель пар ключ-значение;
L — говорит, что нажатие было в левой части экрана;
R — соответственно в правой;
LIGHT — внезапно, свет :)
A — ANGLE угол отклонения;
V — value значение чего-то.
То есть первая команда говорит: «Горизонтальна пара двигателей, направление 45 градусов (левый на максимуме (но максимум — это 35%, исходя из V), правый стоит), со скоростью вращения 35% от максимума».
Вторая соответственно: «Вертикальная пара двигателей, направление 0 градусов (левый на максимуме, правый на максимальном реверсе), с максимальной скоростью вращения». Третья: «Включить свет на 50% яркости».
Так и шлем по сокету на каждое изменение какого-то значения отдельные команды блоками ключ-значение. Далее магическим способом превращаем это в команды на платы управления. Расписывать преобразование этих данных — сильно скучно, здесь и так много текста. Так что каждый может включить воображение или попытаться разобраться в контроллере.
Приложение на Android
Наконец-то мы «доехали» до создания контроллера для всего этого. В целом, общение состоит из «нажал на что-то на экране — передал значение на сервер». Вкратце пройдемся по базовому приложению. Здесь нет ничего необычного и сверхсложного, поэтому весь код выкладывать не буду. При желании зайдете на репозиторий и посмотрите. Также хочу отметить, что все новомодные паттерны MVVM, MVP, VIPER и т. д. пошли лесом, ибо мне надо было рабочее приложение в минимальные сроки, а не выпендриваться. Юайка простая, так что делается максимально просто.
Первым делом создадим активность с вьюхами отображения состояния.
Лаяутбудет следующий:
- Слой отображения видео (плеер инкапсулирован во фрагмент).
- Слой JoystickView — кастомная вьюха, в которой переопределен метод dispatchTouchEvent и в нем обрабатываем нажатие и перемещение пальцев по экрану. Она же рисует UI-линии от нажатия до текущего состояния. Обязательный аспект — поддержка мультитача, так как управление осуществляется двумя пальцами.
- Слой с TextView текущей температуры Raspberry PI (если что-то пошло не так и она начинает греться — можно прекратить использование раньше, чем она выключится/сгорит). Благо, такого не было.
- Слой отображения данных с гироскопа. Набор TextView в парах label-значение. Выводит «сырые данные» с гироскопа. Планировалось их обрабатывать, но времени не хватило для разбора всего и изобретения крутого отображения.
- Слой с SeekBar — управление светодиодом, простой элемент, при перетягивании которого меняется значение от 0 до 100.
Видео Stream
Тут было проделано достаточно много работы для подбора необходимых способов стриминга.
HLS сразу отпал, так как задержка была порядка 10 секунд. При желании можно было добиться 5, но это все равно далеко не то, что надо. В управлении крайне необходимо передать видео с минимальной задержкой. Но передачу организовать не сложно, что со стороны Raspberry, что отображение с Android.
RTMP уже будет потяжелее. Проблема в том, что не было особо простого варианта реализации на Android (на момент конца 2017 года). Есть платные варианты, с которыми тоже повозиться, есть многострадальный VLC, который надо компилить с C++ и настраивать, есть уже собранный VLC как библиотека, который тоже из коробки не хотел проигрывать. Если прибавить ко всему, что это было как хобби и делалось в вечернее послерабочее время, когда голова не сильно свежая и времени ±2 часа, то эти варианты я отбросил.
Зато нашел очень даже рабочее решение, которое подходило по моим параметрам. RPi Camera Viewer for Android — решение, которое получает Raw H.264 поток с камеры и отображает на TextureView c использованием нативного MediaCodec. Если честно, то я до конца не раскрутил всю логику отображения, но собрал и чуть модифицировал под себя для использования. Собственно, главным со стороны Android выступает DecoderThread. Он коннектится по IP и порту, декодит поток и отдает в Surface, а в случае обрыва или ошибки идет рекконект каждые 2 секунды.
Со стороны Raspberry команда запуска потока будет следующая:
raspivid -t 0 -w 1280 -h 720 -hf -ih -fps 10 -o - | nc -k -l 2222
Raspivid — команда, которая осуществляет «захват» видео с подключенной камеры (но не USB, а именно подключенной шлейфом). Параметры выбирал методом «научного» тыка. Качество 1280×720, частота кадров 10fps. Безумно мало, но минимальная задержка.
И весь поток, который транслируется с камеры передается без изменений командой Netcatна 2222 порт.
Приложение на Android коннектится к нему и уже обрабатывает видео, отображая на экране.
Неделю вечеров пришлось потратить на поиск и тестирование таких простых решений, так как общение с Raspberry для меня было в новизну, как и стриминг с Unix-системы.
Управление с экрана и джойстиком
Как уже было сказано ранее, JoystickView передает угол и значение касания экрана на сокет в виде команды типа C:L;A:45;V:35;
Есть потокподключения к сокету (с реконнектами, колбеками и прочим), в котором находится очередь команд. Циклом выбирает их и отправляет на сервер.
В помощь экранному управлению допилил управление джойстиком.
Данный девайс коннектится по Bluetooth и работает как клавиатура. Следовательно, все данные обрабатываются MainActivity методами onKeyDown
и onGenericMotionEvent
.
Тест управления:
Вроде ничего важного со стороны Android не забыл, если что-то не раскрыл — пишите, объясню, допишу.
Сборка и тестирование конструкций
Теперь мы добрались до следующего шага — засунуть все как-то во что-то (гы-гы). На этапе проектирования и сборки мне помогал один очень хороший человек по имени Сергей. Собственно, он нашел коробку, сделал некую железную платформу, на которую можно было крепить двигатели в разных позициях, и собрал все это вот в такой вариант:
Забегу вперед и скажу, что вариант с
Вот такой адок получился в итоге:
Был забит болт на потери при передаче (кабеля было 10 метров) и на основные косяки такого решения. Потому основная цель была посмотреть:
- Можно ли жить с
4-мя движками? - Можно ли управлять с телефона?
- Будет ли затекать вода в коробку?
Но я упустил один важный момент, о котором Серега меня предупреждал. После теста в ванной все эти контакты надо было хорошенько просушить, ибо они — самое слабое звено. А я забил и получил в итоге комбо из 48 мест(!!!) соединения, которые могут (а если могут — обязательно будут) терять контакт.
Здесь как на всех мемасиках ожидание-реальность.
Тест в ванной:
Его сильно кренит из-за проводов, но он способен перемещаться. Ну и чутка перегружен грузами, так как коробка пустая — не рассчитал. А вот следующий тест в «поле» оказался еще хуже:
Двигатели и контакты чуть поддались коррозии, из-за низкой температуры кабель потерял пластичность, и уже все происходило не так резво. Да и гребные винты были неподходящего размера.
Но, самое главное, что был уже понятен путь доработок и конструкционных изменений. Изначально я пытался как-то оставить питание вне аппарата, но тесты показали, что это просто невозможно. Огромные потери постоянного тока говорили о том, что или надо использовать кабель толщиной с руку, или засунуть батареи во внутрь.
Так как никто не был уверен, что на глубине 10+ метров эта конструкция не даст течь и не зальет электронику — решили сделать усиленный вариант «коробка в коробке». Заказали в Китае все необходимое и приступили к дальнейшей сборке:
В коробке были просверлены отверстия для проводов, которые выходили через cable glands (забыл, как они называются по-другому).
Дополнительно была прикручена коробка для диодов и камеры. Естественно, на резиновую прокладку и плотненько зажата винтами. Далее была спаяна плата соединений, с отдельными разъемами под каждый ESC, драйвер диода и гироскоп.
Дабы упростить из без того нагроможденные конструкции, питание сделали одно (для всех узлов) — от LiPO батареи, так как только она способна выдать такой ток разрядки, который покрыл бы и Raspberry, и диоды, и двигатели. Но дополнительно добавили плату уменьшения напряжения с 12V до 5V, которая питала только малину. «Работаем дальше» ©
Получили вот такой внутренний дата-бокс. 4 вывода мотора, 2 диода и шлейф видео. С ним пришлось повозиться больше всего. Правда, в самый последний момент подключения камера не взлетела (на тестах было все хорошо) — где-то таки переломал шлейф во время бесконечных разборок и сборок. Так как уже не было сил это все пересобирать еще раз — решено было забить, да прикрепить на скотч экшн-камеру в водозащитном кейсе и провести новые тестирования.
Кстати, были заменены также гребные винты на максимально большие из тех, которые продаются для моделей, и заменены двигатели на более мощные. На каждый электромотор, который отвечал за горизонтальную плоскость, было прикреплено по 2 винта, просто потому, что они были :)
В качестве роутера был подключен наш NEXX. То есть из Raspberry PI выходит витая пара и коннектится посредством RJ-45 в маршрутизатор. Он же, в свою очередь, раздает Wi-Fi для Android-телефона. На малине забит статический IP адрес, что позволяет не настраивать каждый раз подключение. Правда опять есть проблемы с подключением — если нет нормального покрытия связи, телефон не может присоединиться нормально по IP. Для этого отключал мобильный интернет и пытался присоединиться несколько раз. После подключения открывал SSH на телефоне и запускал команды запуска node сервера (а после всего — выключения системы).
Пришло время новых тестов и, казалось бы, что может пойти не так? Да все :)
По приезде на киевское водохранилище были обнаружены волны нечеловеческих размеров (ну это я так себя утешаю).
И последствия таких заплывов: полностью забитые двигателя всякой плавающей штукой типа водорослей, песком. Тест был снова провален.
Третий и самый успешный тест был произведен уже на спокойном озере, что давало немалые преимущества по сравнению с первыми двумя.
Выводы
Главное, что из этого всего получилось — большой опыт в построении таких вот связок и систем. В процессе разработки было использовано немалое количество различных девайсов, и их управление оказалось намного проще, чем это выглядит издалека.
Конструкция на четырех двигателях не сильно оправдала свои ожидания — управлять таким девайсом крайне тяжело. В идеале надо делать четыре вертикальных двигателя, минимум два горизонтальных. При этом стабилизировать все гироскопом, ибо человек теряется в управлении, и ему надо помогать (как это делают все летающие собратья).
Также все моторы, которые есть в продаже для воздуха очень быстро забиваются песком и прочим, поддаются коррозии отдельных элементов (что логично) и вряд ли подойдут под такие проекты. Конкретно моторов для подводной работы я не нашел (точнее на них может и написано, что waterproof, но это от брызг и глубины до метра).
После этого проекта любой умный дом не кажется таким уж сложным. Сервер, команды на реле, да и все. Главное, время и желание. Остальное придет.
А смысл?
А его нет.
Обещанные ссылки:
Для запуска используем файл app.js
.
Всем добра.