Предыстория

Некоторое время назад я сделал обратный маятник. После нескольких итераций с шаговыми моторами равновесия достичь не удалось. Тогда у меня было мало опыта и понимания проблемы, поэтому я переделал его с мотором постоянного тока, как большинство учебных проектов. Однако, встречаются статьи о том, как сделать балансирующего робота на шаговых моторах. По сути это одна и та же задача, поэтому я к ней решил вернуться и разобраться с прошлых неудачах. Ниже я опишу все, что нужно знать, чтобы сделать своего робота, и трудности, с которыми столкнулся.

Постановка задачи

Сделать балансирующего робота из доступных компонентов с возможностью управления и дальнейшего расширения как платформы.

Используемое железо:

  • Arduino Nano (Keywish BLE-Nano) последовательный порт аппаратно проброшен через Bluetooth, что устраняет расходы процессора на коммуникацию. Можно использовать классический контроллер Arduino Nano, код совместим, но не будет управления

  • MPU6050 - популярный инерциальный модуль для определения угла наклона робота

  • A4988 x2 - драйверы шаговых моторов

  • Nema17 motor x2 - шаговые моторы

Цена компонентов: ~75$

В чем привлекательность использования шаговых моторов? В задачах удержания равновесия нужно создавать силу, действующую на тело робота или стержень, в случае обратного маятника. Значит, нужно управлять угловым ускорением вала. В случае с шаговыми моторами это можно сделать программно, без обратной связи, если предположить, что двигатель не пропускает шаги. Однако, тут важно своевременно формировать импульсы на шаг. Об этом речь пойдет ниже. В случае с коллекторным мотором нужен энкодер для обратной связи и контур управления моментом.

Мат. модель

Движение робота описывается следующими уравнениями:

\ddot{\phi} = \frac{mR(L\dot{\theta}^2sin{\theta} + b_1\dot{\theta}cos{\theta} - gsin{\theta}cos\theta) - b_2\dot{\phi} + u}{I + mR^2sin^2\theta},\ddot{\theta} = \frac{gsin{\theta} - R\dot{\phi}cos\theta - b_1\dot{\theta}}{L},

где R - радиус колеса; I = 1/2*M*R^2 - момент инерции колеса; b1 - трение в оси колеса; b2 - трение качения.

Моделирование с разными способами управления приводится здесь. Так, например, выглядит свободная модель без трения и управления, и со стабилизацией.

Свободная модель без управления
Свободная модель без управления
Модель со стабилизацией по положению
Модель со стабилизацией по положению

Алгоритм стабилизации

Для удержания равновесия нужна обратная связь по углу, а чтобы робот не уехал со стола в процессе отладки, нужно занулить скорость, поэтому схема выглядит так:

Контур скорости задает желаемый угол, а внутренний контур его достигает. В реальности координата X не измеряется, в ходе вычислений уже есть скорость V, которую, как предполагается, шаговый мотор точно выдает.

Управление скоростью

Управление скоростью автоматически получилось по схеме выше: чтобы заставить робот ехать вперед или назад, нужно задать входную скорость.

Но как быть с поворотом? Если добавить константу скорости прямо на двигатель, это не повлияет на равновесие, т.к. ускорение не изменится. Предполагается, что скорость, которую задает пользователь, изменяется гораздо медленее, чем реагирует робот на изменение угла. Тогда для поворота можно добавить скорость к одному двигателю и вычесть у другого. Стоит обратить внимание на насыщение мотора, если поворачивать очень быстро, то при попытке балансировать скорости на одном колесе сложатся, момент упадет, и двигатель начнет пропускать шаги; либо контроллер не будет успевать генерировать импульсы с достаточной частотой.

Сложности реализации

Управлять шаговым мотором просто, когда скорость не критична. В данном случае, нужно управлять ускорением, поэтому следует учесть два параллельных процесса: подача импульсов для шага и пересчет задержки между шагами.

Оценим требуемую частоту импульсов на шаг. Пусть максимальная скорость - 1 оборот в секунду (при колесе от роликов диаметром 72мм, ~22 см/с), двигатель настроен в режиме 1/8 шага, 1600 импульсов на оборот, значит, как минимум процесс, отправляющий импульсы на шаг должен работать с частотой 1.6kHz, причем время должно выдерживаться точно, значит, нужно использовать прерывания по таймеру. Но достаточно ли этого?

Здесь возникает понятие - разрешение (resolution) по скорости, т.е. насколько малые приращения по скорости контроллер способен выдать. Задержка между шагами - это целое количество прерываний таймера (1.6kHz, 800Hz, 533Hz, 400Hz, ...) Программой ниже можно оценить насколько точно можно аппроксимировать желаемые изменения скорости в зависимости от частоты прерываний.

Код
import numpy as np
import matplotlib.pyplot as plt

from math import pi

PULSES_PER_REVOLUTION = 1600

def get_physical_velocity(velocity, frequency):
	ticks_per_pulse = round(2.0 * pi * frequency / (velocity * PULSES_PER_REVOLUTION))
	return 2.0 * pi * frequency / (ticks_per_pulse * PULSES_PER_REVOLUTION)

times = np.linspace(0, pi, 1000)
velocities = np.sin(times)
physical_velocities = list(map(lambda x: get_physical_velocity(x, 1600), velocities))

physical_velocities_2 = list(map(lambda x: get_physical_velocity(x, 50000), velocities))

plt.plot(times, velocities)
slow_label, = plt.plot(times, physical_velocities, label="1.6kHz")
fast_label, = plt.plot(times, physical_velocities_2, label="50kHz")
plt.legend([slow_label, fast_label], ['1.6kHz', '50kHz'])
plt.grid(True)
plt.show()
Аппроксимация скорости шаговым мотором
Аппроксимация скорости шаговым мотором

тоесть, чем ниже частота, тем хуже можно аппроксимировать скорость в области высоких скоростей, что для робота будет равносильно удару. Я использовал 50kHz. Стоит помнить, что чем выше частота прерываний таймера, тем медленнее работает основной цикл.

Второй процесс - рассчет задержки между шагами, в идеальном случае, если робот движется с ускорением, то после каждого шага нужно пересчитать задержку до следующего шага, т.е. это было бы правильно делать прямо в обработчике прерывания таймера, но формула содержит деление ticks_per_pulse = round(2.0 * pi * frequency / (velocity * PULSES_PER_REVOLUTION)), и обработчик может не успеть закончить работу до наступления след. прерывания. Поэтому задержка пересчитывается в основном цикле как можно чаще.

Несколько советов, как ускорить программу:

  • Wire.setClock(1000000UL); - ускоряем коммуникацию с MPU6050

  • Использовать DMP (Digital Motion Processor) встроенный в MPU6050, а не реализовывать комплиментарный фильтр или фильтр Калмана, это дало ускорение обработки основного цикла в 5 раз (2.5kHz)

  • Использовать пин прерывания на IMU и читать данные только тогда, когда закончена обработка, чтобы не опрашивать его постоянно, это ускорило основной цикл еще в 8 раз до 19kHz

  • не забыть откалибровать IMU, иначе измерения угла все время будут плыть.

Код проекта доступен здесь.

Схема

Ниже схема, по которой я заказал печатную плату в JLPCB. Хотелось бы получить обратную связь от опытных схемотехников, особенно по части разведения питания.

Результат

Т.к. в BLE-Nano встроен Bluetooth, и не надо писать дополнительный код, легко добавить управление. Я переделал SerialTerminal под Android и сделал из него пульт управления.

План дальнейшего развития:

  • Сделать расширяемую платформу (другой контроллер или Raspberry будет делать всю высокоуровневую работу, а Nano будет предоставлять API по настройке и управлению)

  • Добавить сенсоры (препятствий, линии под роботом, микрофон, камеру)

  • Добавить индикаторы (заряда батареи, угла, скорости)

  • Присоединить телефон и установить конференц-связь

Буду рад, если кто-то захочет присоединиться.

Ссылки

  1. Код проекта

  2. Симуляции на Kaggle

  3. Схема на easdyEda

  4. Подобная реализация робота

  5. Как работать с акселерометром и DMP

Комментарии (22)


  1. vlakir
    02.09.2021 07:58
    +5

    Отлично! Добротная инженерная разработка, стиль изложения и оформление тоже на высоте.

    А нет мысли реализовать осциллирующий подвес? Была бы мегаинтересная платформа для экспериментов. Или энергозатраты не позволяют сделать такое на автономном источнике? Не пробовали прикинуть?


    1. zjor Автор
      02.09.2021 09:53

      Спасибо, послушал Максима Ильяхова и выкинул половину слов :)

      Имеете ввиду маятник Капицы? Можно, в принципе, как раз план сделать платформу, чтобы можно было и механические модули прикручивать, а питание раздавать на всего робота.


      1. vlakir
        02.09.2021 10:09

        Технарь, читающий Ильяхова - редкое явление) Результат налицо.

        Ага, я про маятник Капицы. Его же при желании можно загнать в хаотический режим, там вообще поле непаханное для экспериментов.


  1. lab412
    02.09.2021 10:48

    Хорошая игрушка получилась. А насколько быстро оно ездить может? разонгать бы до десятков километров в час - было бы куда интереснее. Я тут не специалист, но чаще всего когда такие вот роботы в мультиках или кино (нарисованные короче) ездят - они наклоняются вперед а не стоят вертикально. Это "киношный эффект" всего лишь или реально при больших скоростях стабильное положение будет с наклоном вперед?


    1. LynXzp
      02.09.2021 12:33

      Не киношный эффект www.youtube.com/watch?v=WOVhm-JA-wg (не лучший ролик для демонстрации, но что-то найти можно)

      Ну и за одно десятки км/ч. Правда не чисто от робота, но балансирует вперед-назад исключительно робот.


    1. zjor Автор
      02.09.2021 18:18

      Тут робот сильно отклоняется: https://www.instructables.com/Brushless-Gimbal-Balancing-Robot/

      Скорее нужно бесколлекторные моторы использовать и какой-нибудь отдельный контроллер типа ODrive (тоже в планах)

      Но можно рассмотреть требования к железу, если разгонять до 10км/ч: это 2.7m/c, при диаметре колеса 72мм, угловая скорость ~12 оборотов в секунду. При микрошаговом режиме, 1600 пульсов на оборот, почти 20kHz только для того, чтобы вращать колеса, но надо еще надо учесть разрешение по скорости для плавной аппроксимации ускорения, т.е. частоту прерываний бы раз в 10 увеличить, итого 200kHz только на таймер. Но если взять контроллер побыстрее, например, ESP WROOM32, 240MHz, то вполне осуществимо, но надо еще учесть, как уменьшится момент мотора при такой скорости.


  1. Eddy71
    02.09.2021 10:55

    Вопрос, обратный предыдущему: каковы энергозатраты в случае если надо чтобы платформа не ехала, а стояла на месте (вертикально)?


    1. kvazimoda24
      02.09.2021 17:41

      Думаю, основные затраты там - электрлника и ток удержания моторов. Это при минимальных дестабилизирующих факторах.

      А так, если поставить на ветру да ещё и на наклонной плоскости, то, конечно, затраты будут в разы больше. Правда, и вертикально он стоять не будет :)


      1. heone
        08.09.2021 13:37

        Постоянный воздушный поток, это из области аэротрубы. В природе нет идеального ветра. Поэтому и дестабилизирующие факторы скорее всего не будут минимальными.


    1. zjor Автор
      02.09.2021 18:03

      контроллер и акселерометр потребляют пренебрежимо мало по сравнению с моторами, но их можно отключать, когда робот близко к положению равновесия (даже если он наклонен, противодействуя ветру). Он может оставаться к покое из-за трения, а как только будет выходить из равновесия, моторы сразу включатся. В след. версии схемы добавлю линии enabled для драйверов, и можно будет собрать статистику, сколько энергии на этом получится сэкономить.


  1. Bench2501
    02.09.2021 19:02

    А если моторами двигать противовесы?


    1. d33
      03.09.2021 00:59
      +2

      Кажется, вы только что изобрели хвост


  1. Mc_Key
    03.09.2021 01:59
    +1

    Классный проэкт. На GitHub есть отличный проэкт робота балансира на bldc моторах с применением векторного управления (FOC) на базе arduino.

    https://github.com/simplefoc/Arduino-FOC-balancer


  1. Andy931
    06.09.2021 14:13
    +1

    Класс! Вдохновляет! Обязательно попробую свою реализацию!

    Отличное, ëмкое и понятное изложение без воды! Спасибо!


  1. barabanus
    07.09.2021 22:08
    +1

    Небольшая ремарка насчёт matplotlib: вы уже указали label при вызове plt.plot(), поэтому достаточно вызвать plt.legend(), чтобы сгенерировать автоматическую легенду. Такое использование гораздо лаконичнее.

    Ещё одна ремарка относительно PID: для контроллеров обычно используют целочисленную арифметику. Если уже считаете с плавающей точкой, то для накопительных переменных надо брать число с большей точностью для избежания переполнения, иначе малые приросты просто перестанут менять перменную.


  1. Smileedition
    08.09.2021 05:25

    генерировать импульсы программно не лучшее решение, тем более на таких частотах, нужно использовать выходы самого таймера, а в коде только менять параметры его работы


    1. zjor Автор
      08.09.2021 12:04

      я только за, если таймер может генерировать импульс в широком диапазоне частот, а у нас есть только делитель частоты и прерывание по переполнению счетчика. Плюс импульс на шаг выглядит как LOW->HIGH, подождать как минимум микросекунду, HIGH->LOW - уже какая-то логика, к тому же 2 двигателя - 2 таймера, а в Nano их три и не все можно программировать без последствий для измерения времени.


      1. Smileedition
        08.09.2021 12:41

        вам нужен таймер с выходом на ногу контроллера
        большой диапазон достигается за счет того что можно менять и регистры таймера и делитель частоты
        16-bit Timer/Counter1 with PWM вот этот раздел в reference manual


        1. zjor Автор
          08.09.2021 12:57

          спасибо! попробую в след. версии


  1. AaRoN_2021
    08.09.2021 11:59

    Интересно, а вот если увеличить масштам, обьем этого робота, то будет вопще супер. Кстати а именно только через Arduino Nano можно собрать или можно собрать из разных Arduino микрокотролеров? Нагрузка какая типо нужна ли подзарядка? потомучто этим роботам нужна подзардка, если конечно я неошибаюсь.


  1. Sterpa
    22.09.2021 13:28

    Прекрасная работа, @zjor!

    Обратил внимание, что практически все подобные работы с балансировкой движения начинаются с мат. модели, особенно для коптеров, где получается достаточно много сложных диф. уравнений. Но ведь в самих PID регуляторах эти уравнения не используются, или я не прав?

    Я сам сталкивался только с PID регуляторами температуры, когда по датчику температуры или фотоэлементу определяется цвет расплава, а управляющий сигнал от PID повышает или понижает расход газа в печи. Но там нигде сама физика процессов не используется, т.к. PID-регулятору совершенно все равно чем управлять и в каких единицах.

    Мне казалось, что подобным образом PID регуляторы контролируют углы эйлера в полете. Но для этого вроде тоже никакие уравнения не нужны, углы мы получаем уже с гироскопа...

    Буду очень признателен, если кто в двух словах пояснит, где используются уравнения движения в связке с PID, или отправит в направлении источника знаний, с примерами))


    1. zjor Автор
      22.09.2021 16:22

      спасибо,

      это верно, PID-регулятору все равно чем управлять, но подгонять коэффициенты сразу на устройстве может быть очень дорого и долго, более того, не при всех коэффициентах система стабилизируется, а реальное устройство может сломаться. Поэтому все отлаживается на модели, а для этого нужны уравнения. Для подбора коэффициентов достаточно линеаризованной модели, тогда уравнения существенно упрощаются (sinx ~ x, cosx ~ 1, и т.д.), но я люблю посмотреть на картину в целом, поэтому моделирую полную систему. Могу посоветовать вот эти 2 канала: https://www.youtube.com/watch?v=Pi7l8mMjYVE&list=PLMrJAkhIeNNR20Mz-VpzgfQs5zrYi085m, https://www.youtube.com/user/ControlLectures/playlists