BLDC и магнитный энкодер — рецепт получения позиционного привода из FPV-моторчика
У меня завалялась старая разбитая FPV-шка. Пару моторов у неё живы, поэтому можно поэкспериментировать. Идея этого проекта состоит в том: можно ли собрать достаточно точный привод, чтобы в дальнейшем использовать при создании, к примеру, робота-манипулятора или подвеса камеры. Предполагаемая точность поворота ротора будет порядка 0.5 градуса. Забегая вперёд могу сказать, что AS5600 (энкодер) имеет разрешение 12 бит, что даёт 4096 шагов на 360° - точность 0.089град/шаг. Фактически окажется чуть больше из-за несовершенства конструкции, но всё равно точность для подобного эксперимента будет довольно высокой. Можно было бы взять AS5047 с разрешением 14 бит и точностью 0.022°, но сам FPV мотор для такого не предназначен, и потребовалась бы система высокоточных редукторов и передач, и тогда теряется весь смысл от FPV.
Для этого эксперимента потребуется FOC-контроллер, TTL-преобразователь CH340E, и магнитный энкодер AS5600 - всё это отлично продаётся и покупается на маркетплейсах. Если хочется выжать максимум точности, то потребуется ещё INA240 - усилитель с контролем тока. Я делал без него, т.к. увеличение точности будет не столь велико и для целей эксперимента непоказательно.

FOC-контроллер, который был куплен не глядя, оказался китайской ноунейм копией MKS MINI FOC от Makerbase. Он оснащен микроконтроллером ESP32-WROOM-32E N4, как и в оригинальной плате, поэтому можно смело брать - всё работает. На плате выведены площадки для подключения всей необходимой периферии (CH340E и AS5600).
Подключение периферии не вызывает абсолютной никаких сложностей, однако отсутствие внятной документации на изделие заставило посидеть на этим контроллером с мультиметром не один час.
Разводка пинов следующая:
Фазы A,B,C, Enable: 16, 5, 17, 4BLDCDriver3PWM driver = BLDCDriver3PWM(16, 5, 17, 4);
SDA и SCL для AS5600 - стандартные для этой библиотеки: SDA = 21, SCL = 22;
Весь этот проект построен на открытой библиотеке SimpleFOC (SimpleFOCproject) для управления бесколлекторными моторами. Библиотека имеет поддержку всех необходимых датчиков и драйверов. Разработчик рекомендует работать с библиотекой из ArduinoIDE, что я и сделал.
Эта статья является, по своей сути, одним большим ТРАБЛШУТИНГОМ на пути сборки этого не очень-то и хитрого устройства. Казалось бы: библиотека - есть, готовый драйвер, где даже пины разведены, как в библиотеке - есть, энкодер - есть. Собирай и запускай. Но, как водится, на каждом этапе возникают сложности. Первая из них - версии подключаемых библиотек.
В карточке на маркетплейсе, где заказывался драйвер, было указано, что он уже прошит.
Сразу, как извлёк из упаковки, я подключил фазы, подключил питание, соединил с компьютером - мотор начал подавать признаки жизни - дергался, гудел, но не вращался, как должен. (Без использования энкодера, драйвер и мотор можно запустить только в режиме open-loop, позволяющим только крутить мотор по кругу, выбирая угловую скорость. Сначала запускал так). Не вопрос! Наверное ошибка в коммутации фаз в заводской прошивке. Промерил мультиметром плату, выяснил, что фазы, как писал выше 16, 5, 17 - добавил данные в код примера. Код залился без ошибок. Не работает. Мотор не издавал никаких звуков, не крутился - ничего. Вообще ничего.
Миллион разных попыток переписать код, заглянуть под капот SimpleFOC, и прочих мероприятий привели к мысли, что стоит попробовать другие версии. В итоге дело действительно оказалось в них, и рабочая конфигурация выглядит так:
SimpleFOC 2.3.0 + ESP32 2.0.7
Дело в несовместимости SimpleFOC 2.4.0 и ядра ESP32:#error ESP-IDF version 4 or lower.
Пока искал в чём может быть проблема игрался даже с частотой ШИМ-сигнала. По-умолчанию она 40кГц, но когда мотор беспричинно молчал, я пытался выставлять 20кГц: driver.pwm_frequency = 20000; Это не помогло, и в итоге я вернулся к стандартной.

Следующая проблема, которая решилась, справедливости ради, быстро встроенными методами SimpleFOC: нехарактерное для FOC-контроллера большое потребление тока и, как следствие, перегрев.
Не сложно заметить по фото, что плата не оснащена никакими радиаторами охлаждения. При этом производитель указывает, что MOSFET'ы на фазах работают 30V/30A, что, конечно, нереально без отвода тепла. Работа в режиме open-loop показала, что после 1A на вход контроллера (блок питания в режиме current control), плата греется свыше 70oC. У разных моделей FPV-моторов свои рабочие обороты, мой мотор достигал энергоэффективного режима на примерно 20-25об/сек при 0.2А, температура не поднималась более 30oC (выравнивались напряжение и противоЭДС). Выставлял программно ограничение voltage_limit =1В на мотор.
Установка и калибровка AS5600. Настройка PID. Не сказать, что это проблема, однако же вопрос имеет много нюансов и тонкостей, через которые пришлось пройти.

Магнит расположен на оси вал и вращается вместе с ней, энкодер считывает изменения магнитного поля. Ось магнита должна быть совмещена с центром микросхемы, для этого требуется её жесткая фиксация, отсутствие вибраций, способствующих смещению с этой оси.
Подключить и сразу запустить в closed-loop не получится. Нужна неспешная подгонка всех параметров, взаимного расположения. Отлично для этих целей подходит пример скетча в самой библиотеке magnetic_sensorI2C_example. Иначе кроме визга двигателя и перегрева ничего получить не удастся.
Конфиги для моей сборки (FPV-мотор 380KV (7 пар полюсов), драйвер на IR2104S, энкодер AS5600, питание 12В, ограничение по току 1А) для closed-loop такие:
// velocity PI controller parameters
motor.PID_velocity.P = 0.2f;
motor.PID_velocity.I = 1;
motor.PID_velocity.D = 0;
// maximal voltage to be set to the motor
motor.voltage_limit = 2;
// velocity low pass filtering time constant
// the lower the less filtered
motor.LPF_velocity.Tf = 0.05f;
// voltage for sensor alignment
motor.voltage_sensor_align = 5.0;
// angle P controller
motor.P_angle.P = 3;
// maximal velocity of the position control
motor.velocity_limit = 5;Эта конфигурация выведена практически, как результат обратной связи от мотора.
motor.voltage_sensor_align = 5.0; - при стандартных 2В мотору не хватало мощности провернуться и откалиброваться - возникала ошибка.
motor.LPF_velocity.Tf = 0.05f; - фильтр энкодера, чтобы не дергался от "шумных" данных
motor.P_angle.P = 3; и motor.velocity_limit = 5; - базовый коэффициент поворота и максимальная скорость. Ограничение скорости поворота до 5 рад/сек, что всё равно много, но выглядит уже плавно, без рывков. Минимальная и максимальные скорости зависят от разницы между двумя показаниями (ошибкой энкодера) - чем она выше, тем быстрее разворот, но не более 5.
Уточню, также, про косметический нюанс в коде. Ввод данных для поворота осуществлялся в радианах, добавил делитель, чтобы вводить в градусах: motor.move(target_angle/57.3);
Результат работы можно посмотреть на видео ниже. В качестве итога хотелось бы отметить, что выбор FPV-мотора для такой задачи является мягко сказать "неоптимальным". Виной всему выступают несколько факторов: малое количество пар полюсов магнитов, что сказывается на сложности удержания мотором заданного положения; мотор рассчитан на высокие обороты и малый момент, от того быстрый рост тока при малом напряжении - перегрев; но даже эти факторы не мешают работать системе с точность 0.5о, и, даже местами 0.2о, как следует из видео. Можно заморочиться ещё больше и сделать контроль по току, а не по напряжению, тем более, что это нативно поддерживает библиотека SimpleFOC. Нужно добавить "токовый усилитель" INA240, и перейти в режим:TorqueControlType::foc_current - это увеличит точность до 0.1-0.3 градуса (и они будут вполне стабильны).
Отдельно замечу, что на видео, после ввода команды -5.8 градусов, энкодер так и не смог поймать положения и вертелся вокруг заданной позиции. Это говорит о необходимости точной и надёжной фиксации энкодера и магнита относительно друг друга.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.