Руководство · Средний · 25 min

Управление относительно поля: «вперёд» значит «вперёд»

Одна матрица поворота и IMU делают управление роботом с омни-приводом интуитивным. Разбираем математику, дрейф и кнопку сброса, необходимую каждой конструкции.

Проблема, которая возникнет через десять секунд

Соберите робота с приводом mecanum, возьмите пульт и толкните стик вперёд. Робот уезжает от вас. Хорошо.

Теперь поверните его на 180° и снова толкните стик вперёд. Робот едет на вас, потому что «вперёд» означает «вперёд для робота», а робот теперь обращён к вам. Оператор автоматически мысленно поворачивает команду зеркально, ошибается, и робот разбивается.

На роботе с дифференциальным приводом это уже достаточно плохо, хотя робот всегда движется вдоль собственного курса. На роботе с омни-приводом ещё хуже: робот может быть направлен в одну сторону, а двигаться в другую, и не видно, в какую сторону направлено боковое движение. После десяти секунд вращения никто в комнате не сможет им управлять.

Исправление — одна матрица поворота.

Две системы координат, одно преобразование

Стик можно интерпретировать двумя способами:

  • В системе координат робота. Стик — команда в собственной системе робота, base_link, если говорить на языке ROS. Толкните вперёд — робот движется вдоль своего курса.
  • В системе координат поля. Стик — команда в системе координат пола. Толкните вперёд — робот движется на север, куда бы ни смотрел его нос.

Привод понимает только систему робота — кинематика mecanum записана именно в ней. Поэтому управление относительно поля означает поворот команды оператора в систему робота до того, как её увидит кинематика.

Если курс робота равен θ (измеряется против часовой стрелки от оси x поля), поверните команду на −θ:

vx_robot = vx_field · cos(θ) + vy_field · sin(θ)
vy_robot = −vx_field · sin(θ) + vy_field · cos(θ)

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

Вращательная составляющая команды не преобразуется. ω означает одно и то же в обеих системах — вращение остаётся вращением, — поэтому значение передаётся напрямую.

Всё решение в коде

#include <math.h>

// stickX: forward on the stick, positive = away from the driver (field +x)
// stickY: left on the stick,    positive = to the driver's left (field +y)
// stickW: twist, positive = counter-clockwise
void driveFieldOriented(float stickX, float stickY, float stickW) {
  float theta = imuYawRadians() - headingOffset;   // see "the reset" below

  float c = cosf(theta);
  float s = sinf(theta);
  float vx =  stickX * c + stickY * s;
  float vy = -stickX * s + stickY * c;

  driveMecanum(vx, vy, stickW);   // the inverse kinematics, unchanged
}

Шесть строк, а это разница между роботом, которым можно управлять, и роботом, которым нельзя. Обратите внимание, что driveMecanum() ничего об этом не узнаёт: ориентация относительно поля — это преобразование команды, а не изменение привода.

Как получить θ

Нужен угол рыскания, и есть три способа получить его — от самого быстро устаревающего к самому устойчивому.

Источник Дрейф Стоимость Вердикт
Только одометрия колёс Быстро — каждое проскальзывание становится ошибкой курса, а ролики mecanum скользят по конструкции Бесплатно Приемлемо только для короткой поездки
Гироскоп MPU6050, интегрирование Обычно 1–3° в минуту после калибровки ~£2 Подходит для двухминутного матча, не для часа
9-осевой DoF IMU со слиянием магнитометра (BNO055, ICM-20948) Ограниченный, но уязвимый к магнитным помехам в помещении ~£20 Подходит для долгой поездки

Рыскание от гироскопа получается интегрированием, поэтому смещение превращается в линейный дрейф:

// Integrate yaw rate, with the bias you measured while it sat still.
float rate = gyroZ() - gyroBiasZ;             // rad/s
if (fabsf(rate) < 0.004f) rate = 0.0f;        // deadband: kill the last of the creep
yaw += rate * dt;

Две детали важнее выбора датчика:

  • Измеряйте смещение при каждой загрузке, пока робот неподвижен. Усредните 500 отсчётов за секунду-две до начала движения. Сырой MPU6050 без удаления смещения дрейфует на десятки градусов в минуту; с ним — на единицы.
  • Мёртвая зона должна быть на скорости, а не на угле. Мёртвая зона на угле теряет медленные настоящие повороты. Мёртвая зона на скорости отбрасывает только шумовой пол, который как раз и интегрируется в дрейф.

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

Сброс, который обязателен

Ручной ноль необходим по двум причинам:

  1. Дрейф. Через несколько минут представление робота о севере и представление оператора расходятся, и исправление становится проблемой.
  2. Начальная ориентация. Ноль IMU находится там, куда робот смотрел при включении, а это редко совпадает с положением оператора.

Поэтому храните смещение и кнопку:

float headingOffset = 0.0f;

void resetFieldHeading() {          // bind to a button the driver can hit blind
  headingOffset = imuYawRadians();  // "whatever you are pointing at is now forward"
}

Соглашение, к которому приходят все: направьте робота от оператора, нажмите кнопку и поезжайте. Это занимает полсекунды и одновременно устраняет обе проблемы. У каждого серьёзного телеуправляемого робота с омни-приводом есть такая кнопка, а каждая команда разработчиков, которая её пропустила, добавила кнопку после первого матча.

Ориентация относительно поля и для автономности

Это не только помощь при вождении. Любое автономное поведение, команда которого естественно выражена в системе координат поля, требует того же преобразования:

  • «Переместиться на 300 mm к цели» — цель задана в координатах поля, значит, команда тоже.
  • «Ехать боком, удерживая камеру в центре цели при её облёте» — облёт задан в системе поля, вращение — в системе робота, а управление относительно поля позволяет записать оба действия в одной строке.
  • Всё, что находится после планировщика маршрута, который планирует по карте, а значит, в системе поля.

В ROS это делает преобразование odom → base_link, поэтому существует TF2 и поэтому cmd_vel явно определён в base_link. Управление относительно поля — самостоятельная реализация преобразования, которое иначе запросили бы у TF2.

Как это увидеть

В симуляторе привода mecanum есть один манёвр, который передаёт смысл без слов: удерживайте стик вперёд, продолжайте вращаться и переключите систему координат.

Система Что рисует робот
Ориентированная на робота Розетку. Команда вращается вместе с корпусом, поэтому робот закручивается вокруг себя и никуда конкретно не едет.
Ориентированная на поле Прямую линию, пока корпус всё время вращается вдоль неё.

Один и тот же стик, колёса и кинематика. Разница только в шести строках тригонометрии.

Диагностика

Симптом Причина Исправление
При 0° правильно, при 180° точно неверно Вращение на +θ вместо −θ Измените знак; слагаемые с синусом поменяются местами
Робот едет под 90° к стику x и y переставлены или IMU установлен с поворотом Проверьте обозначение осей IMU относительно курса робота
Минуту всё хорошо, потом медленно становится неверно Дрейф гироскопа Калибруйте смещение при загрузке, задайте мёртвую зону скорости и кнопку сброса
Возле одной части комнаты происходит резкий скачок Магнитометр рядом с двигателем, динамиком или сталью Переместите IMU или откажитесь от магнитометра и примите дрейф гироскопа
Кнопка сброса ничего не делает Смещение применено к неправильной переменной или прочитано до готовности IMU Печатайте θ и смещение вместе; сразу после сброса они должны быть равны
Робот ползёт боком при центральном стике Это не проблема системы координат — это скорость колёс Проверьте, что каждое колесо действительно останавливается

Далее

Ориентация относительно поля делает команду правильной. Замкнутое управление скоростью колёс заставляет колёса действительно её обеспечивать: на роботе с омни-приводом это единая система, потому что неодинаковое падение момента двигателей отклоняет робота от курса ещё до того, как IMU сможет вмешаться.

Исследуйте граф

Входит в эти сборки

Проекты и учебные пути, в которые входит это руководство.

Дополнительные материалы

Источники