Всем добрый день, сегодня я хотел бы поделиться своим опытом проектирования ракеты с управлением вектора тяги. Так получилось, что я долго сидел дома и решил купить 3D принтер, ну и конечно первое же, что я решил распечатать - модель ракеты типа «Батут-М», которую можно приземлять и беспроводной меч-огнемет. Занимался ли я созданием ракет раньше? Никогда!!! Ну правда в одной моей iOS игре на самописном Objective-C движке «Minimal Man» - можно из ракетомета стрелять ракетами, например ограбить магазин, выпустив ракету по продавцу. В игре все ракеты взрываются. Я выбрал 3D-принтер «Creality Ender-5», но сейчас уже доступна версия «Creality Ender-5 Pro» с тихими драйверами. Мои же драйвера шаговых моторов пищали при печати, но я купил обновленную плату с Aliexpress и прокачал принтер до «Pro» версии вручную. Теперь он работает бесшумно. Ох, первое что я печатаю в жизни - и уже ракета, которую я хочу приземлить!!! Ну так запускаем программу SketchUP и проектируем 3Д модель. По моему замыслу, все детали ракеты должны быть напечатаны на 3Д принтере, включая рычаги сервомоторов, собираться отверткой, без использования клея, проволок и прочих деталей, как обычный конструктор. Для каркаса я купил пачку алюминиевых трубок диаметром 6мм, но конечно в дальнейшем их хочу заменить на более легкий пластик из ЧПУ станка. Как видно на 3Д модели нижней части ракеты - для отклонения вектора тяги я использую самые дешевые сервомоторы SG90 с Aliexpress, которые конечно же желательно заменить на более элитные. Я заказал дорогие аналоги данных сервомоторов с сайта HobbyKing - но к сожалению мне их так и не доставили, вернули деньги. Сейчас я все еще ищу качественные сервомоторы, если можете что-нибудь посоветовать, отпишите в комментариях, буду очень рад совету. Пробуем распечатать 3Д модель нижней части ракеты, которую я называю «Система трех колец» или «Нагибатор двигателя» Естественно, я сделал мобильное приложение «Ракета» для управления ракетой через iPad, iPhone, с джойстика от PlayStaton или с любой другой bluetooth кнопки, подключил сервомоторы и все оттестировал. Несмотря на то, что я печатаю в первый раз, распечатать все получилось очень легко, и буквально за несколько минут мне удалось собрать тестовую модель отверткой. Очень советую аккумуляторную отвертку от Xiaomi, с ней собирать делали очень даже приятно, детали собираются просто, как конструктор.  Я сразу же распечатал переходники для разных типов двигателей, включая твердотельные. Затем я подключил соосные моторы к системе отклонения «трех колец» через дешевые китайские регуляторы бесколлекторных моторов на 30А и протестировал тягу с iPad и с джойстика и убедился, что тяга есть. Собираем нашу модель отверткой, прикручиваем держатели для Arduino Nano и аккумулятора. Почему же я решил делать все на итальянском микроконтроллере Arduino, да и еще на версии Arduino Nano? Все дело в том, что многие разработчики дронов и коптеров из России во всех своих статьях пишут, что не нужно разрабатывать полетный контроллер самому, нужно покупать готовые. Напомню, что полетный контроллер - это так называемые «мозги» устройства, то есть другими словами все советуют покупать готовые «мозги» (зарубежного производства).  Так-так-так, то есть все считают, что разработать свой полетный контроллер «с нуля» - это очень сложно. Из аргументов - «там сложно реализовать PID контроллер». Вообщем для того, чтобы выяснить в чем сложность, я решил начать с платы Arduino, все-таки это хобби у меня такое - ракету собирать, почему бы и не попробовать на Arduino. Если ее мощности не будет хватать, я смогу заменить ее на более мощную плату. Если вы знаете, на какую плату ее можно заменить, пожалуйста посоветуйте что-нибудь подходящее в комментариях. Что же такое PID регулятор и почему его так боятся? Пропорционально-интегрально-дифференцирующий (ПИД) регулятор, согласно Википедии, имеет единственное предназначение -  в поддержании заданного значения r некоторой величины y с помощью изменения другой величины u. Посмотрим формулу: Так, ну да, видимо интеграл в формуле выглядит довольно пугающе, сразу вспоминаются флешбеки с лекций по математическому анализу, когда ты на скорость переписываешь закорючки с доски, поначалу вникая, но в какой-то момент просто отпускаешь все мысли и перерисовываешь все с доски, как иероглифы, в надежде, что разберешься позже. Но дело в том, что в интернете много готовых реализаций классов PID контроллера, которые выглядят просто как готовая функция, которой передаешь отклонение ракеты и она просто возвращает угол, на который нужно повернуть ракету! Всего-то! Итак, определим два параметра нашей ракеты, числа «input_x» и «input_y»: «input_x» - отклонение ракеты влево-вправо от вертикального положения «input_y» - отклонение ракеты взад-вперед от вертикального положения Если «input_x» больше нуля, значит ракета наклонилась вправо на «input_x» градусов, если меньше нуля - значит ракету отклонили влево. Тоже самое и для «input_y». Значит при нулевом «input_x» и «input_y» - ракета стоит вертикально. Данные значения получаем от IMU сенсора с помощью функции IMU.readAcceleration, который уже встроен в мою версию Arduino Nano (так же в моей Arduino Nano уже есть встроенный барометр, для определения высоты, датчик температуры, bluetooth модуль, микрофон и другие датчики. И все это - на крохотной плате): IMU.readAcceleration(input_z, input_x, input_y); Теперь у нас есть значения отклонения ракеты, можно инициализировать PID контроллер: double P = 1.0, I = 0.05, D = 0.03; double refresh_time = 10; PID xPID(P, I, D, refresh_time); PID yPID(P, I, D, refresh_time); xPID.setpoint = 0; // Ноль - для вертикальной стабилизации по оси X yPID.setpoint = 0; // Ноль - для вертикальной стабилизации по оси Y При создании PID регулятора нужны три числа: P - Пропорциональная составляющая I - Интегрирующая составляющая D - Дифференцирующая составляющая refresh_time - интервал, с которым мы будем опрашивать наш PID контроллер и получать значение для сервомотора, например раз в 10 миллисекунд. Данные коэффициенты подбираются вручную либо при помощи специальной библиотеки PIDtuner на стенде, попробую немного объяснить, на что влияют эти коэффициенты: P - Пропорциональная составляющая для получения выходного сигнала, противодействующему отклонению регулируемой величины от заданного значения (в нашем случае нуля), наблюдаемому в данный момент времени. Допустим мы установим коэффициент P=1, тогда при отклонении ракеты вправо на 15 градусов, сервомотор отклонит мотор в противоположную сторону на 15 градусов для того, чтобы ракета смогла восстановить вертикальное положение. Если бы коэффициент мы установили в значение P=2, то при отклонении ракеты на 15 градусов, сервомотор отклонил бы вектор тяги на 30 градусов в противоположном направлении. I - Интегрирующая составляющая, коэффициент, благодаря которому ракету меньше «колбасит влево-вправо», пока она пытается стабилизироваться в вертикальном положении. Коэффициент, который пытается загасить волну отклонений «влево-вправо» как можно быстрее. D - Дифференцирующая составляющая, коэффициент, который предсказывает, что пока ракету колбасит «влево-вправо» её может заносить по инерции, то есть этот коэффициент позволяет затормозить ракету заранее перед тем, как она приняла вертикальное положение, то есть избежать попадания ракеты в дрифт. Дрифт коэффициент, я его называю именно так. Естественно, данные описания этих коэффициентов я привел в своей упрощенной интерпретации, подробнее можете сами почитать на википедии. В реальном проекте конечно есть много нюансов, например из-за значения «I» внутри функции PID-контроллера накапливается интегральная ошибка, которую нужно обнулять перед запуском, либо хранить ошибку в массиве чисел и удалять старые значения методом FIFO (англ. first in, first out — «первым пришёл — первым ушёл»), но это все экспериментальные функции, для общего понимания можете про это пока не думать.  С коэффициентами разобрались, это просто три числа, которые мы пытаемся подобрать, ничего сложного. Теперь раз в 10 миллисекунд нам нужно получить значение для отклонения сервомоторов «output_x» и «output_y»: // Получение значений отклонения для сервомоторов из PID-регулятора: xPID.input = input_x; yPID.input = input_y; output_x = xPID.getResultTimer(); output_y = yPID.getResultTimer(); На данном этапе у нас есть значения  «output_x» и «output_y» - поворачиваем наши сервомоторы на это значение. Все!!! Так легко, просто кайф!!! Ну конечно же в реальном проекте я еще фильтровал значения с акселерометра через фильтр Калмана, для того, чтобы исключить шум на графике, но даже без фильтров с современных акселерометров приходят довольно точные значения отклонения, а некоторые IMU сенсоры уже содержат встроенный фильтр Калмана.  Для того, чтобы получить значения P, I, D коэффициентов автоматически, я распечатал тестовый стенд, на котором ракета может свободно вращаться, затем подключил библиотеку PIDtuner, запустил, ракета немного покачалась туда-сюда и на выходе PIDtuner я получил в логе коэффициенты: double P = 0.55, I = 0.05, D = 0.03; Теперь вписываем эти коэффициенты в мобильное приложение и пробуем запустить ракету Первый запуск показал, что тяга действительно есть, ракета способна летать, но я все-таки запускал ракету в комнате, поэтому очень не хотел ее разбить, на гашетку я давил не в полную силу. Также видимо нужно более тщательно подобрать PID коэффициенты, просмотрев видео с запуском, можно заметить, что ракета все таки немного заваливается. Сборку ракеты я записал на видео (ссылка ниже), на видео видно, что ракету в полете немного закручивает по часовой стрелке, все дело в китайских регуляторах моторов, которые раскручивают один мотор немного быстрее, чем другой. Но ничего, в следующих обновлениях я попробую заменить регуляторы или добавить еще один ПИД-регулятор на «повороты» - и если ракету начнет закручивать, можно попробовать использовать значение из ПИД-регулятора для понижения скорости мотора, который крутится быстрее другого. В теории - к данной ракете можно прикрепить крыло - и попробовать приземлить ракету горизонтально. Либо прикрепить шар с водородом - и получится дирижабль с управлением вектора тяги. Ну либо можно попробовать вместо электромоторов попробовать сконструировать ракету на турбореактивной тяге (в продаже есть неплохие двигатели для моделей реактивных самолетов), правда придется переместиться в гараж. Полное видео сборки можете посмотреть по ссылке: Так же я по быстрому записал видео про сборку «беспроводного меча-огнемета», это видео вы так же можете найти на YouTube канале: https://www.youtube.com/c/МаксимГеймдев Да и в целом я написал эту статью для поиска единомышленников, если вы тоже увлекаетесь робототехникой или разработкой дронов, скидывайте свои проекты в комментарии либо пишите, что бы вы хотели увидеть в следующих постах. Заранее большое спасибо за фидбэк и критику :) iOS Developer / iOS Team Lead