Skip to content
База на глиссере

База на глиссере

База управления на глиссере

Цель занятия: обучающиеся реализуют приём команд и микшер на наземной технике, проверяют поведение при потере связи и переносят эту логику на летающий аппарат.

Глиссер даёт ту же цепочку управления, что и дрон — приём команд, микширование, воздействие на движители, поведение при потере связи, — но отлаживается на земле. Ошибка в коде здесь означает, что аппарат остановился или поехал не туда, а не что он упал с высоты.

Зачем начинать не с дрона. У квадрокоптера отладка кода и отладка пилотирования происходят одновременно, и при аварии невозможно понять, что виновато: код, настройки или руки. На наземной технике эти причины разделены — аппарат стоит на столе, код виден в консоли, руки не при чём. Разделять переменные при отладке — базовый инженерный приём, и здесь он встроен в саму конструкцию занятия.

Что общего у глиссера и дрона

ЗвеноГлиссерКвадрокоптер
Приём командCRSF от ELRS-приёмникаТо же самое
Разбор протоколаТот же конечный автомат, тот же CRCТо же самое
ARM-тумблерРазрешение движенияРазрешение вращения винтов
МикшерКаналы → мощность двух движителейКаналы → обороты четырёх моторов
FailsafeСтоп при потере связиСнятие газа / возврат домой
ВыходШИМ на драйверШИМ или DShot на ESC

Отличается только микшер и последствия ошибки. Всё остальное переносится буквально, вплоть до строк кода.

Микшер: от каналов к движителям

Микшер — функция, превращающая команды пилота в мощности отдельных движителей. Для двух движителей (танковая схема, skid-steer):

Pлев=газ+руль,Pправ=газруль P_{\text{лев}} = \text{газ} + \text{руль}, \qquad P_{\text{прав}} = \text{газ} - \text{руль}

Логика простая: едем прямо — обоим одинаково; поворачиваем — одному добавляем, другому убавляем.

// Каналы приходят в диапазоне 1000..2000, центр 1500
int thr  = rx.getChannel(CH_THROTTLE);   // 1000..2000
int yaw  = rx.getChannel(CH_YAW);        // 1000..2000

// Переводим в знаковый диапазон -255..255
int drive = map(thr, 1000, 2000, -255, 255);
int turn  = map(yaw, 1000, 2000, -255, 255);

int left  = constrain(drive + turn, -255, 255);
int right = constrain(drive - turn, -255, 255);

motors.set(left, right);
constrain здесь не украшение. При полном газе и полном руле сумма даёт 510 — вдвое больше максимума. Без ограничения значение переполнится или уедет в драйвер как мусор. Приём тот же, что в регуляторе линии у робота: выход контура всегда ограничивается диапазоном исполнительного устройства.

Мёртвая зона

Стики почти никогда не возвращаются ровно в 1500. Без мёртвой зоны глиссер будет медленно ползти при отпущенных стиках.

const int DEADZONE = 30;   // микросекунд вокруг центра

int applyDeadzone(int value, int center = 1500, int dz = DEADZONE) {
    if (abs(value - center) < dz) return center;
    return value;
}

Тот же приём понадобится на дроне: там «ползёт» превращается в «уводит».

Микшер квадрокоптера — для сравнения

Чтобы связь была наглядной, вот тот же принцип для четырёх моторов:

Mпер.лев=газтангаж+крен+рысканиеMпер.прав=газтангажкренрысканиеMзад.лев=газ+тангаж+кренрысканиеMзад.прав=газ+тангажкрен+рыскание \begin{aligned} M_{\text{пер.лев}} &= \text{газ} - \text{тангаж} + \text{крен} + \text{рыскание} \\ M_{\text{пер.прав}} &= \text{газ} - \text{тангаж} - \text{крен} - \text{рыскание} \\ M_{\text{зад.лев}} &= \text{газ} + \text{тангаж} + \text{крен} - \text{рыскание} \\ M_{\text{зад.прав}} &= \text{газ} + \text{тангаж} - \text{крен} + \text{рыскание} \end{aligned}

Та же идея: общая составляющая (газ) плюс разностные (наклоны и разворот). Знаки при рыскании чередуются по диагонали — потому что разворот создаётся разбалансом реактивных моментов пар винтов, вращающихся в разные стороны.

Понял микшер глиссера — понял микшер дрона. Разница только в числе строк. Именно поэтому глиссер идёт первым: главная идея усваивается там, где её можно проверить, покрутив колесо рукой.

ARM: движение только по разрешению

const int ARM_THRESHOLD_US = 1700;

bool armed = rx.getChannel(CH_ARM) > ARM_THRESHOLD_US;
motors.setArmed(armed);

if (!armed) {
    motors.set(0, 0);     // не armed — движители обесточены, что бы ни было на стиках
    return;
}

Порог 1700 (а не 1500) выбран так, чтобы случайное дрожание около центра не включало моторы: тумблер должен быть уверенно в верхнем положении.

Проверка ARM — первое, что делается в цикле управления. Не после микшера, не «где-нибудь рядом», а до любых вычислений мощности. Логика простая: если разрешения нет, то никакие вычисления не должны иметь возможности что-то включить.

Failsafe и двухуровневая защита

В ERLS_Rover реализованы два независимых уровня:

  1. Тумблер ARM — осознанное решение оператора. Работает мгновенно.
  2. Таймаут связи — автоматика. Нет пакетов 500 мс → каналы в безопасные значения, газ в минимум, движение прекращается.

Уровни независимы намеренно: отказ одного не отменяет другой. Оператор может выключить ARM при живой связи; автоматика остановит аппарат, даже если оператор ничего не успел сделать.

Практика занятия

Собрать цепочку и увидеть каналы

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

Написать микшер

Реализуем drive/turn → left/right с constrain и мёртвой зоной. Проверяем без движителей: выводим рассчитанные мощности в консоль и двигаем стики.

Подключить движители и проверить направления

Частая ошибка — движитель крутится не в ту сторону. Лечится либо перестановкой проводов, либо знаком в коде. Записываем, что именно сделали.

Проверить ARM

Тумблер вниз — стики не действуют вообще. Тумблер вверх — управление работает. Проверяется многократно, это ключевая защита.

Проверить failsafe

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

Порядок проверок не переставляется. Сначала консоль, потом движители. Сначала ARM, потом failsafe. Каждая следующая проверка опирается на то, что предыдущая пройдена, — иначе при отказе непонятно, что именно сломалось.

Диагностика

СимптомПричинаЧто делать
Ползёт при отпущенных стикахНет мёртвой зоны или сбит центрДобавить deadzone, откалибровать стики
Поворачивает не в ту сторонуПерепутаны движители или знакПоменять местами в микшере
При полном газе руль не работаетНасыщение: drive уже 255Ограничить газ или масштабировать сумму
Дёргается на полном ходуПросадка питания под нагрузкойПроверить аккумулятор и сечение проводов
Не останавливается при выключении пультаFailsafe не реализован или не проверяется таймаутВернуться к таймауту 500 мс

Приёмка занятия

  • Микшер написан самостоятельно, ограничение диапазона объяснено.
  • ARM работает: при выключенном тумблере движители не реагируют ни на что.
  • Failsafe проверен выключением пульта при работающих движителях.
  • Обучающийся объясняет, какие строки перенесутся на квадрокоптер без изменений, а какие придётся заменить.