Итак, мы будем делать автопилот для лодки, который будет содержать довольно простую механическую часть, а все вычисления будут производиться прямо в веб-приложении браузера.
Чего?
Возможно, это тот вопрос, который у вас сейчас в голове. Эта идея пришла мне в голову около месяца назад, когда в очередной раз, проходя маршрут по воде от пирса до точки отдыха, я подумал:
Как же надоело все время подруливать лодку, держа курс и обходя острова, почему бы ей самой это не делать?
И вправду, ведь у моего телефона есть GPS, и если я выставлю ему точки, которые нужно пройти, он, зная где он сейчас и где ему нужно быть, мог бы отправлять команды на какое-нибудь устройство, чтобы рулить за меня. Такие системы уже есть и придуманы были миллион лет назад, но стоят довольно больших денег. Я хотел сделать простое, не сильно дорогое, компактное устройство, которое будет устанавливаться на любую лодку, поворачивающую за счет пера руля или мотором, плюс всегда интересно получить новый опыт. И еще больше устройство удешевит то, что большая часть работы переносится на телефон, который и так есть у всех и его стоимость можно вычесть, оставив только механику. Вначале, это была просто безумная идея в голове, но в какой-то момент, я понял, что у меня полностью сложилась картинка и я, кажется, знаю как реализовать все этапы этого проекта.
Не было смысла сразу делать физическое устройство. У меня было не сильное желание отлаживать его работу с ноутбуком на воде, поэтому сперва я хотел сделать эмулятор, и когда все будет обкатано на нем, можно будет делать само устройство.
На чем писать? (choose your destiny)
Не люблю я делать андроид приложения, их надо пихать на маркет и постоянно пересобирать и обновлять там или все время обновлять руками у себя на телефоне. А зачем, ведь андроидный хром позволяет делать полноэкранные приложения из специально настроенных веб страниц и ничего не надо обновлять на устройствах, залил на сервер и у тебя в телефоне сразу последняя версия. А еще он может дать приложению доступ к GPS, акселерометру и даже BLE. Если первые два пункта я уже проверял в другом проекте, то последнее надо было проверить, ведь без этого реализация не имеет смысла. Я накидал тестовое приложение для подключения по блютус и поставил ответную его часть на плату ESP32. На сегодняшний день BLE работает только в Хроме, но и на Windows и на Android одинаково хорошо (на яблоках скорее всего работать не будет). Я понимаю, что для такой дачи web-app это не серьезно, но я не продаю вам рыбов, я даю вам удочков. В общем, пойдет, едем дальше. JS фреймворки я тоже не сильно жалую, чистый JS кажется мне таким простым, что я не вижу смысла его еще как-то оборачивать, поэтому это чистый JS для приложения на телефоне и C++ для части на ESP32. Архитектурно было задумано так, что все расчеты делаются в приложении на телефоне и на физическое устройство будет по BLE отправляться уже готовое значение положения руля, которое требуется установить. Устройство будет смещать румпель в нужное положение и периодически слать статусы, в каком положении румпель сейчас. Но это все потом, для начала поясним за теорию.
Немного школьной математики
Честно говоря, я никогда не любил математику в школе и у меня почти всегда по ней была тройка. Тройка вообще была моей любимой оценкой по многим предметам, она позволяла пройти дальше не сильно напрягаясь, а освободившееся время тратить на то, что тебе действительно интересно. Учителя и преподаватели постоянно бросали мне вызов, говоря, что я никогда никем не стану, если не выучу их предмет, надеясь что это меня разозлит и я возьмусь за учебу. Но я всегда улыбался в ответ. Мне хватало тройки. Зачем делать то, что мне не нравится, чтобы что-то доказать людям до которых мне нет дела? Жизнь, она же должна быть в кайф, иначе зачем это все? В студенчестве у меня один раз даже случился парадокс: я не был допущен до экзамена по С++, потому что не ходил на лекции С++, потому что ложился спасть слишком поздно, потому что писал свои Pet-проекты на С++. Хотя в те времена это еще даже не называлось Pet-проектами.
С появлением интернета мы стали жить в удивительное время, когда формулу больше не нужно помнить, нужно просто знать, что она есть, а если знаешь, что она есть, то её без проблем можно найти. Но за последние пару лет время стало ещё удивительней, и теперь можно не знать и не помнить вообще ничего, достаточно уметь поставить задачу чату-гпт и он все сделает за вас (иногда хорошо, иногда плохо). И моя лень не смогла пройти мимо этого способа, и я любезно попросил чат-гпт написать нужные мне функции сразу на JS, а он любезно согласился. Но, все-таки, я считаю, что нельзя делать то, сам не понимаешь что, поэтому понимание сначала сложилось у меня в голове, а потом я обратился в ИИ за автоматизацией процесса.
Итак, мы не управляем скоростью лодки, мы предполагаем, что она всегда движется вперед, скорее всего, с постоянной скоростью. Поворот руля меняет её курс правее или левее, и чем сильнее перо руля повернуто, тем сильнее меняет. Для начала нам нужно понять текущее направление движения лодки. Пусть север будет 0/360 градусов, тогда юг - 180.
Пока лодка стоит на месте, направление её движения мы определить не можем, но как только она сдвинулась и у нас есть 2 её координаты задача становится простой. Имея точки A и B, мы можем найти точку C и получить треугольник. А дальше, зная координаты точек A, B и C, мы можем получить все углы треугольника, но нам нужен только угол A. И получив этот угол, мы уже сможем узнать угол движения лодки от 0 до 360 градусов
У нас есть точки маршрута к которым мы хотим двигаться, расстояние до точки считаем по всем известной теореме Пифагора, ведь длина катетов нам известна, значит можем посчитать и гипотенузу.
Теперь, как заставить лодку двигаться к точке? Точно также, сперва мы определяем угол, куда лодка движется сейчас, а потом, тем же методом треугольника, только взяв текущее положение лодки и точку куда надо идти, мы получаем угол, куда лодка двигаться должна. И в зависимости от того, насколько текущий угол отклонятся от требуемого, мы начинаем крутить пером руля в том направлении, в каком повернуть оптимальнее, чтобы встать на нужный курс.
По мере уменьшения разницы между требуемым курсом и фактическим, мы уменьшаем поворот пера руля, чтобы не перекрутить поворот. Помним базу, что поворачивает корма лодки, а не её нос, примерно, как автомобиль при езде задним ходом, поэтому учитываем этот момент в эмуляторе.
Ну вот же, вот оно! Я все сделаль! Нет. Это все прекрасно, но работать будет только в идеальном мире эмулятора (возможно еще в альфа версии матрицы). А в реальном мире (и более поздних версиях матрицы) на лодку действуют другие, неподвластные нам силы, такие как, например, течение и ветер. И если у вас нет хороших связей с Зевсом и Посейдоном, эти законы вам не нарушить. Добавим течение с юга на север в эмуляторе и посмотрим, что будет.
Ну... формально... точка пройдена. Но... не хотел бы я однажды проснуться в мире, где все корабли ходят вот так. Помимо того, что проходить точки таким способом - это верх идиотизма, тут есть проблема посерьезнее. Вполне возможно, что тот, кто проставлял точки подразумевал движение лодки вдоль линий, т.к. маршрут мог составляться с использованием карты отмелей и препятствий. А как известно лодка может ходить только по воде, а по дну она ходить не может. А разбившись о камни, она может ходить только ко дну и только один раз. Поэтому, мы не хотим, чтобы она сильно отклонялась от линии между точками. И если есть силы, которые пытаются нас от линии сместить, нам нужно это компенсировать. Для начала надо понять, как далеко мы от линии. Тут снова треугольники.
Итак, мы знаем точку откуда начинается линия, знаем точку куда идем и знаем точку где мы сейчас. Это треугольник, длину всех сторон, которого мы можем посчитать. А если у нас есть длина всех его сторон, мы можем найти его высоту, а она то нам и нужна, это расстояние от нашей лодки до линии. Теперь, удаленность от точки будет иметь какой-то вес и чем он больше, тем больше мы будем подруливать в сторону линии. Внедряем алгоритм в работу и смотрим результат.
Я сделаль? Все еще нет. Теперь лодка пытается скомпенсировать снос течением от линии, за счет большего поворота пера руля. Но у самой точки, у нас всплывает еще одна проблема. Проход точек. В начале у меня это было сделано просто — когда лодка оказывается на определенном расстоянии от точки, точка считается пройденной и мы идем к следующей. Но тут много чего может пойти не так. GPS может быть недостаточно точным, и точку мы просто пролетим. Или течение снесет нас так сильно, что мы пройдем на большем расстоянии от точки, чем нужно для её «взятия». Или мы просто начали движение с середины маршрута и не хотим возвращаться обратно на первую точку, но никто нас спрашивать не будет. Если бы это были какие‑нибудь соревнования, попытки вернуться на еще не взятую точку, чтобы её взять, были бы логичны, но при простом следовании маршруту, это маниакальное желание «взять точку» выглядит странно. Нужно было менять алгоритм, который считает точку пройденной. Я думал над этим какое‑то время и треугольники снова пришли на помощь.
Координаты точек A,B и C нам известны, значит можем найти все три угла. Но три не надо. Надо только A. И дальше элементарно. Если угол А острый, мы не прошли точку. Как только он отупел - точку мы прошли. Таким образом мы можем пройти точку на любом расстоянии от неё, в каком направлении бы не пролегал маршрут. Забиваем это в эмулятор.
Ну теперь-то я сделаль? Сделаль? Почти.
Проблемы, которые я предвидел
Скорость движения румпеля. Важный момент, механика которую я собирался создавать, не поставит руль в нужное положение мгновенно, перевод руля из крайнего правого положения в крайнее левое займет N секунд. А скорость лодки остается постоянной. Предположим у нас большая скорость лодки и маленькая скорость движения румпеля. Посмотрим, как алгоритм с этим справится.
Он честно пытался... Алгоритм пытается погасить тот хаос, который сам же и создает, но он не успевает и выглядит, как та черепаха из советского мультфильма, которая не успевала за временами года. Руль меняет свое положение слишком медленно, а его влияние на курс лодки, при её большой скорости, слишком высок. Твориться настоящее безумие, и меньше всего мне бы сейчас хотелось оказаться на этой лодке. Поэтому я решил добавить ещё пару улучшений. Мы можем ограничить зону в которой ходит румпель, таким образом мы не позволим лодке делать слишком крутые повороты, и скорость перевода руля из одного крайнего положения в другое возрастет. Чем быстрее будет двигаться лодка, тем меньше у алгоритма будет зона в которой ходит руль. Это скорее костыль, но практика показала, что костыль работает.
Ну что ж. Из минусов: повороты теперь возможны только по большим дугам. Из плюсов — хаос прекратился, и лодка более менее идет по линиям и проходит точки даже на большой скорости с медленным рулем.
Дальше следует еще один важный момент — GPS. Обычно он обновляется не чаще пару раз в секунду + я усредняю последние 3–4 точки, чтобы избежать произвольных смен курса из‑за неточности GPS, а значит он не только будет сообщать информацию не так часто, как хотелось бы, он будет сообщат немного устаревшую информацию. Но это проблема завтрашнего меня, а пока, раз программная часть готова — сегодняшний я начинаю ковать паять железо.
Время останавливается, завтрашний я появляется из будущего:
— Вчерашний я был редкостным идиотом. Пытаясь предотвратить проблему которой даже еще и не было — он её создал. Он загрубил GPS координаты до 5го знака после запятой, а еще игнорировал смену позиции, если она менее, чем в 5 метрах от предыдущей. Это привело к тому, что получилась очень большая задержка данных от GPS, и мне пришлось все это расхлебывать.
Завтрашний я уходит назад в будущее, время продолжает ход.
Железо
Шаговый двигатель NEMA 17
Плата ESP32
Драйвер шагового двигателя A4988
Плата расширения для драйвера A4988 (можно и без неё, а можно с ней)
Подшипник опорный фланцевый KFL08 8мм (2 шт)
Линейный подшипник LM8UU (2 шт)
Круглая направляющая 8мм 500мм (2шт)
Жесткая соединительная муфта 5x8
Гайка для винта TR8 шаг 2мм, ход 8мм
Трапециевидный винт TR8x8 500 мм
Аккумулятор на 12 вольт
Понижающий преобразователь до 5 вольт
Болты М3х10мм-12мм (4шт), М3х16мм (4шт)
Болты М4х15мм (12шт)
Болты М5х30мм (2шт), М5х25мм (1шт), М5х50мм (6шт), М5х10мм (2шт), М5х60мм (1шт)
Гайки М4 (12шт)
Гайки М5 (12шт)
Также для повторения проекта понадобится 3Д печать. Я использую пластик PETG с углеволокном. Он стоит подороже обычного, но немного прочнее и выглядит визуально значительно приятней.
Если вдруг будет интересно, то вот мой путь к 3Д печати
Про 3Д печать я узнал много лет назад, когда это только начинало становиться доступным для простых обывателей. И мне всегда это было интересно, но т.к. принтеры всегда стоили средних денег, целесообразность его покупки вызывала у меня сомнения. Если бы он стоил больших денег дилеммы бы не было, я бы точно знал, что это слишком дорого и я это покупать не буду. Если бы он стоил малых денег, я бы просто купил его и все. Но вот он стоил именно средних денег, и я сомневался. И первое, что заставляло меня задуматься — это то, что я не умел 3Д моделировать. Когда я еще был студентом, мы изучали всякие 3Д макс и прочее, но очень вскользь, типа: «Ну вот тут есть цилиндр, кубик, бобик и шарик, из них можно делать сложные фигуры». Ну вот, примерно так я и моделировал, на уровне детского конструктора, и выглядело это соответствующе.
Поэтому я рассматривал только вариант, что я буду печатать готовые модели. Периодически я заходил на сайты, где они были собраны и если сейчас есть Thingiverse или Printables, где реально есть много всего интересного и полезного, то тогда, заходя на сайты с моделями я ожидал, что сейчас увижу кучу крутых эргономичных вещей, которые будут полезны в быту, запчастей для разных устройств, за которые больше не надо будет платить большие деньги и т. д. а видел я в основном... Фигурки персонажей звездных войн, полу или полностью раздетых женщин, всякие декоративные украшательства, еще куча всякой фанатской дребедени... И тогда мне хотелось закричать: «Люди, да что с вами не так?! Вам дана возможность создать все что угодно. ВСЕ. ЧТО. УГОДНО. И вот так вы этим распоряжаетесь? Серьезно? Серьезно?! Фигурки стар‑варс?!» Ну ладно, на самом деле все логично. 3Д моделированием чаще увлекаются творческие люди, а им в большинстве своем неинтересны всякие там устройства, запчасти и т. д. И интересна художественная ценность вещей, а не практичность их применения, поэтому они и создают художку. Для всего нужно время, и придет день когда этим заинтересуется больше креативных инженеров, и среди моделей будут не только фанатские украшательства.
Так шли годы и в какой‑то момент я понял,что созрел для того, чтобы купить 3д принтер и что‑то спроектировать для печати самому. Надоело ходить по строительным магазинам и искать то, не зная что, что бы можно было приспособить для моих проектов. И я стал искать для себя маленькую, быструю, удобную и безглючную программу для 3д моделирования. Я не хотел ничего покупать, как и использовать криво сломанное ПО. Чтобы это был не монстр на несколько гигабайт, а что‑то компактное, желательно портабельное. FreeCad — я понял что без уроков я в нем не разберусь, SolidWorks — огромный, тяжелый и тоже сложный монстр, Fusion — привязан к онлайну, OpenSCAD — это что, тут программировать чего‑то еще надо на каком‑то его собственном языке? Нахрен. Компас — уже не помню, что мне не понравилось в нем, но точно понял,что не мое. Среди многого, чего я посмотрел, мне очень понравилась миниатюрная, мало кому известная Solve Space. Я сразу понял как в ней работать и даже спроектировал пару моделей. Это была идеальная маленькая, быстрая и безглючная программа, но постепенно, по мере, того, как я делал более сложные модели, она теряла свои свойства. Вначале я понял, что не такая уже она и быстрая, а потом, что не такая уж и безглючная. Ну маленькая — да, тут не поспоришь. И уже тогда я точно определился, что любая модель, которую я делаю всегда имеет четкие размеры, все отверстия и выступы имеют диаметры и координаты, и желательно иметь возможность все это быстро менять. И тогда я еще раз решил посмотреть на OpenSCAD. Говорите, тут чего‑то программировать надо, ну ладно, посмотрим...
И вот она, та программа на которой я остановился. Да, тут визуально ничего не порисуешь и не подвигаешь, но когда у тебя для всего четкие размеры, оно как бы и не надо. Все размеры можно задавать в переменных вначале, а в самом коде модели использоваться только вычисления с ними. И все просто, надо тебе сделать другой размер какой‑то части, ты просто меняешь значение переменной на нужное и все. Да, для того, чтобы это работало именно так, сперва нужно хорошенько попрограммировать, но это не страшно, ведь в моем дипломе так и написано — программист.
Итак, в OpenSCAD я спроектировал устройство по частям и отправил их на принтер. В этот раз мне повезло, я нигде не ошибся с размерами и мне не пришлось перепечатывать ни одной детали. Ладно одну перепечатал. Ладно 4 раза. Но больше ни одной! Ладно еще зажимы для румпеля сделал потом острее. Но теперь точно все.
Если расположить все так, как оно должно быть собрано, то получается такая вот картинка. Черные детали пластиковый, белые — резина (TPU)
И я начал собирать все это.
Теперь, что куда паять. С платой расширения все получается максимально просто. Вставляем драйвер A4988 в плату расширения. От платы расширения припаиваем:
E (плата расширения) = GPIO4 (ESP32)
D (плата расширения) = GPIO16 (ESP32)
S (плата расширения) = GPIO17 (ESP32)
GND (плата расширения, любая GND из двух рядом) = GND (ESP32)
5v (плата расширения) = 3v3 (ESP32)
9v (плата расширения) = 12v+ (источник питания, разъем для подключения аккумулятора) P.S. Да, и 12 вольт будет работать и ничего не сгорит)
Теперь от разъема аккумулятора:
12v+ (источник питания, разъем для подключения аккумулятора) = IN+ (12v => 5v понижающий преобразователь)
12v- (источник питания, разъем для подключения аккумулятора) = IN- (12v => 5v понижающий преобразователь)
От понижающего преобразователя:
OUT+ (12v => 5v понижающий преобразователь) = 5v (ESP32)
OUT- (12v => 5v понижающий преобразователь) = GND (ESP32)
Вот так, вроде ничего не забыл (но это не точно). Компилируем и заливаем прошивку на ESP32, тут не буду подробно описывать, как это делается, я использовал Arduino IDE.
Принцип действия устройства такой: шаговый двигатель крутит трапециевидный винт, он смещает гайку которая крепится к средней секции, в которую в последствии будет вставлен румпель.
Проверяю как движется механизм. По скорости можно сделать немного быстрее, но незначительно. Механика все равно медленная, для ускорения нужны более быстрые драйверы, но пока нет смысла их покупать. Я не делаю гоночную систему и такой скорости может вполне и хватить. Ситуации, когда нужно срочно перевести руль из крайне-левого положения в крайне-правое, не должно возникать. Автопилот не предназначен для ведения лодки по узким проемам, он больше для длительных перегонов с большими пространствами, где медленный перевод руля не должен быть серьезной проблемой.
Для фиксации румпеля я решил сделать довольно простой механизм. Нужно было добиться того, чтобы я мог быстро блокировать/разблокировать направляющую фиксации румпеля. Можно было сделать просто, чтобы болт, вкручиваясь, упирался в направляющую, блокируя её, но так пластиковая направляющая будет деформироваться и изнашиваться, я хотел сделать более долгоживущее решение, и оно оказалось хорошим. Резинка (или деталь отпечатанная из TPU пластика) намертво блокирует направляющую не требуя как-то туго затягивать винт. Работает вот так:
Зачем руль, спросите вы? Ну, у телефона, же есть акселерометр. Ну есть же! Ну... сечёте, куда я клоню? Сечёте?! Ну конечно же, я должен был это попробовать! В середине предусмотрено крепление для телефона и при повороте руля, используя акселерометр, можно будет рулить в ручном режиме. Да с задержкой, ведь механика медленная, но ведь можно же!
К тому же мне хотелось обкатать другую технологию. Как вы видите на фото выше, через руль проходят швы. Это потому, что в простой домашний 3д принтер такая модель не поместится, и её надо печатать частями. Но если просто нарезать модель ровными резами, то при склеивании будет трудно ровно совместить части, особенно, когда их больше двух. Небольшое отклонение на линии склеивания приводит к большой проблеме на другом конце, едут углы, ошибка накапливается при склейке следующих деталей, все становится криво и косо. Поэтому я написал для OpenSCAD функцию нарезки елочкой, чтобы все сразу вставало, как надо, зубчики в зубчики. В результате не идеально, но приемлемо. Можно заполнить эти швы шпатлевкой, вышкурить (как и всю модель) и покрасить, чтобы она выглядела хорошо, а не как напечатанная страшная дичь. Обычно я так и делаю, но т.к. руль был сделан для прикола, то я не стал тратить на это время и оставил как есть.
Мой любимый навесной монтаж, но чтобы ничего не закоротило, развел компоненты по этажам. Нужно еще термоклеем зафиксировать, но я не стал пока тестирую.
Устройство имеет 0 кнопок и 0 индикаций. Минимализм, как он есть, просто подключаешь к нему питание 12вольт и с ним сразу можно соединяться приложением на телефоне по блютус.
Не люблю я Li-Ion, как-то раз я немного накосячил и у меня загорелась одна ячейка 18650. Было неприятно, попортился ламинат, прожегся диван, пришлось выкинуть простыню, одеяло и немного нервных клеток, опыт интересный, повторять не рекомендую. С тех пор, я больше люблю более безопасные и не особо горючие LiFePo4, у которых хоть и поменьше емкость на вес, примерно на 25%, но зато бонусом идет значительно большее количество циклов заряд/разряд, более высокие токи отдачи и работа на холоде. Поэтому использовал сборку из 4х32700 емкостью 7000мач. Двигатель у меня потреблял где-то 0.25А, а значит сборки явно хватит на много часов работы.
Еще один момент - это влагозащищенность. В текущей версии её нет. Нет, если брызнет немного воды, думаю, ничего страшного не случится, но к сильному дождю или погружению устройство не готово, поэтому не рекомендуется для установки на Ноев ковчег.
Первые тесты
Когда устройство было собрано, пришло время его проверять. И первый тест был попроще - руль и акселерометр.
Первичное тестирование прошло хорошо. По большому счету, это все, что я мог протестировать дома. Тест с имитацией движения по маршруту я тоже провел, чтобы убедиться, что все это будет работать долгое время и ничего не зависнет. У работы веб приложений на андроиде есть свои минусы. Нельзя гасить экран телефона и сворачивать его, оно не будет работать в фоне, поэтому я добавил режим темного экрана, когда весь экран заливается черным цветом и остается немного серого текста в середине. Это хорошо экономит заряд на OLED экранах. По идее есть ServiceWorker который может работать и в фоне, но ему, вроде как, блютус никто не даст. Подозреваю эту проблему можно решить как‑то иначе, но я пока не стал заморачиваться и ограничился тем, чтобы просто программно не давать устройству гасить экран. Правда один Service Worker я все‑таки завел, чтобы приложение работало без интернета. Достаточно один раз зайти в него с интернетом и дальше, если интернета нет, он будет брать страницу из кэша, если есть — возьмет из интернета и заодно обновит в кэше. Еще я написал скрипт, который собирает мне все мои JS скрипты, картинки и стили в один index.html. Знаю, таких сборщиков, как экскрементов за парной, но я написал свой, потому что могу, и мне было лень разбираться, как работают чужие. Итого приложение получилось примерно 320кб.
Карты оно не подтягивает, хотя знаю, в теории это возможно реализовать, и было бы неплохо, возможно когда-нибудь, я это сделаю. Но сейчас, я строил маршрут в другой программе, потом экспортировал GPX файл и в своем приложении его загружал. Поддерживается импорт KML (из navionics) и GPX.
Калибровка
Колибри на корабле калибровали — калибровали, да не выкалибровали
(это реально сложнее, чем оригинальная поговорка, попробуйте)
Калибровку нужно проводить каждый раз, когда устройство включается. Дело в том, что при включении, оно понятия не имеет в каком положении каретка находится в данный момент. А должна находиться посередине и это для неё будет точка 0. Вначале я думал, что будет так: на выключенном устройстве нужно будет вручную подвинуть каретку в середину (ну примерно) и потом включить устройство. При включении текущее положение будет 0 и вроде все хорошо. Но потом я решил, что так на глазок руками в центр двигать негоже, можно это сделать гораздо точнее. Я ведь заранее могу посчитать сколько шагов двигателя нужно, чтобы пройти от края до середины. Значит сперва нужно дойти до края, а от этой точки уже легко будет придти четко в середину. Нормальный, разумный человек поставил бы концевик у одного из краев и заставил бы каретку двигаться к краю до тех пор, пока она не упрется в него. Но я человек не такой, поэтому сделал, чтобы она просто двигалась максимальное количество шагов, требуемое чтобы пройти от одного конца до другого. Если она упрется в край раньше — да и хрен с ней, ну попропускает двигатель шаги какое‑то время, не умрет, а потом уже каретка пойдет к центру. Дальше, когда держатель румпеля находится в середине, нужно поставить сам румпель на лодке ровно, в таком положении зафиксировать в держателе и уже после этого крепить устройство к лодке. Так, а собственно, как его крепить?
Крепление
С креплением все интересно. Нужно было придумать что‑то максимально универсальное, чтобы это можно было установить на любую лодку, а не на какую‑то конкретную, это может быть надувная моторная лодка с транцем сзади, может быть небольшая яхта с утками или леерами, может быть что‑то еще, и крепление должно подходить везде. Какое‑то время я покрутил в голове, как такое крепление могло бы выглядеть, но мне не пришло в голову ничего удобнее уже готовых Magic Arm'ов. Я много раз крепил с их помощью камеру на яхту и они хорошо себя показали, а у меня их оказалось как раз 2 штуки. Сделаны они из алюминия и если хорошо затянуть — держат очень крепко. Ими можно зацепиться за что угодно, за транец, за борта, за утку и т. д. и выставить устройству любое положение.
Теперь как эти руки крепить с устройству? можно было напечатать «уши» как у GoPro, но я не очень доверяю пластиковым напечатанным ушам. Из трех возможных положений печати, чтобы они были прочными, их нужно печатать только в таком горизонтальном:
Тогда слои будут идти так, чтобы не давать ушам сломаться при нагрузке. При печати в других положениях они могут ломаться по слоям и у меня они ломались в других проектах. Поэтому я не стал заморачиваться с ушами, а впаял по краям две гайки 1/4, такие же как в фотоаппаратах и прочей технике, это прочнее.
Опасался ли я, что алюминиевые волшебные руки не удержат мое устройство ровно, и если румпель будет идти тяжело, они могу съехать? Да, опасался. Также я опасался, того, что руль может идти так туго, что двигатель Nema 17 не справится и начнет пропускать шаги. Но, в конкретно моем случае, ни одно из опасений не оправдалось.
Ну... Погнали!
Но перед тем как я покажу небольшое видео, нужно сообщить немного информации. Устройство использовалась на небольшой 6 метровой парусной яхте. Шла она под маломощным мотором, т. к. для хождения под парусами к автопилоту совсем другие требования. Максимальная скорость в таком режиме получалась 10–12 км/ч. Крепилось все за 2 утки позади яхты.
Итоги выезда
Итак, устройство вполне себе работает. И наверное это один из немногих случаев, когда что‑то на первых же полевых испытаниях показало себя хорошо, не было ни критичных багов, ни зависаний и оно работало почти так, как задумано. Почему почти? Вот теперь о недостатках.
Первый недостаток — это как раз та самая задержка позиционирования, которую я создал. Сам по себе Web‑API GPS работает нормально, но надо немного усреднить данные, чтобы не было вихляний лодки из‑за неточности + я немного загрубил данные, округляя до 5 знаков после запятой и сделал, чтобы изменения не обрабатывались пока разница между координатами не достигнет 5 метров, отсюда лодка никогда не становилась на курс ровно, она всегда вихляла пересекая линию то в одну, то в другую сторону. Чтобы их уменьшить мне пришлось поменять некоторые настройки на ходу — максимальный диапазон движения руля. У меня длина направляющих 50см, из которых полезных чуть более 40, т. е. 20 см в каждую сторону. Но эта длина оказалась избыточна, и чтобы предотвратить бессмысленные и беспощадные вихляния лодки, а также уменьшить время перевода руля, я выставил программе использовать всего 30% от этого диапазона. Для лодки идущей 20+ км/ч я бы, наверное оставил 15–20%, а то и 10%.
Ухожу в прошлое, чтобы сообщить вам этот спойлер о проблеме GPS, а потом возвращаюсь обратно
Но, ограничивать зону движения руля — это костыль, а не панацея. Но есть пару мыслей на будущее.
Мысли на будущее
Прогнозирование. Сейчас этого нет, программа рассчитывает действия только на текущую ситуацию, но если ситуация не совсем актуальная или время обновления слишком большое, программа не успевает реагировать, что приводит к вихлянию лодки. Но программа знает скорость лодки и может рассчитать скорость поворота, и вполне могла бы учитывать эти данные при расчете положения руля. В теории это должно еще больше уплавнить движение лодки и уменьшить вихляния рулем.
Компас. Эту идею подкинула мне подруга, занимающаяся яхтингом. Для определения курса лодки можно использовать компас, который будет работать быстрее GPS. Реализовать это можно двумя способами, либо аппаратный компас на самом устройстве, либо брать информацию с телефона. Но во втором случае придется особо не трогать телефон во время работы автопилота. Но я не хочу использовать абсолютное вычисление курса по компасу. Это принесет собой требования к точной установке компаса в определенном положении на лодке + на правильность работы компаса может влиять много внешних факторов. Поэтому я придумал другой алгоритм. И суть его работы в том, что мы просто фиксируем показания компаса когда получаем координаты GPS и пока нам не пришли новые координаты, мы будем использовать разницу показаний компаса, чтобы скорректировать курс лодки. Как только имеем новые координаты GPS тут же пересчитываем курс на более точный и повторяем процедуру с запоминанием показаний компаса. Таким образом, нам правдивость показаний компаса и не нужна пусть хоть на юг показывает и с честным лицом политика говорит, что там север. Главное, чтобы при повороте его стрелка смещалась в нужную сторону.
Кстати, пока я писал эту статью, этот функционал я попробовал реализовать. Работает интересно, и кажется стало лучше. Надо будет протестировать в боевых условиях, но пока, хоть угол поворота лодки и немного дергается с приходом новых координат GPS, но курс лодки теперь корректируется плавнее и быстрее и это должно принести свои плоды.
И еще одно важное обновление:
Начав менять алгоритм работы с GPS мне удалось, выкинув ненужный код, существенно уменьшить задержку получения данных. На воде это еще не тестировал, но при ходьбе пешком скорость изменения курса нравится мне намного больше. Кажется я стал умнее и больше не допущу таких глупых ошибок.
Время останавливается, завтрашний я появляется из будущего:
— Ни хрена он не стал умнее, как был идиотом, так и остался. Знаете, что он сделает? Знаете? Хотя ладно, не буду спойлерить, так даже интереснее...
Завтрашний я уходит назад в будущее, время продолжает ход.
Ах, да, где это все взять?
→ Здесь
→ А тут готовое веб-приложение
На всякий случай напишу инструкцию, как работать с приложением.
Подаем питание на устройство, и если все было собрано правильно, оно сразу же начнет говорить о своей доступности по блютус.
Открываем ссылку только в Хроме и если у вас андроид, то нажимаем «добавить на главный экран».
Открываем добавленное приложение, если спрашивает разрешения — все разрешаем не читая, если считаем себя глупыми людьми. Если считаем умными — сначала, читаем, потом все разрешаем.
(Левая часть экрана в приложении скроллится, если что)
Нажимаем кнопку «Connect Bluetooth» и дальше в списке должно быть устройство «EasyBoatContoller», подключаемся к нему.
Жмем кнопку «Calibration...» и там в «Run auto zero calibration» кнопка «Run», ждем пока калибровка закончится и каретка встанет в середину.
Ставим руль вашей лодки или мотор по середине, чтобы шла ровно, зажимаем румпель в зажиме и дальше фиксируем устройство в таком положении.
Можем нажать «Accel Drive» и рулить наклоном телефона
Когда наигрались, нужно создать GPX маршрут, в программе типа Navionics или тут например.
Нажимаем в программе «Route Management...» и там «Import...» загружаем наш GPX файл. И она либо загрузит его, либо
умрет пытаясьскажет, что не смогла.Дальше выходим из настроек, убеждаемся, что наше текущее положение лодки, действительно, рядом с этим маршрутом. А то ведь программа не обсуждает ваши приказы, она их выполняет. И если окажется, что текущая координата находится в России, а маршрут где‑нибудь в районе индии — она ведь поплывет к нему. Причем поплывем по прямой. И её ничего не смутит.
Когда убедились, что ошибок нет, можно нажать кнопку «Start Navigation» и заводить мотор.
Ну и все. Положите телефон, откиньтесь на спинку кресла и съешьте уже этих мягких французских булок.
Там есть еще и настройки, их значения расписаны на ГИТе. По умолчанию настройка «Use Compass Between Gps Steps» выключена, если на телефоне есть компас, можно включить, потестировать работу компаса. Остальное — ну смотрите сами.
MIT — поэтому делайте с этим что хотите и мозг мне не любите) Шучу, можно задавать вопросы в комментариях, что смогу — отвечу.