Домой

Управление 16 сервомашинками


Реализаций управления сервомашинками при помощи "народной" AVR ATMega полным полно в интернете. Вот ещё одна реализация, основанная на таймерах и регистрах. Можно сказать что такая методика является "полуаппаратной" так как интервалы управления каждой машинки довольно жёстко задаются аппаратными таймерами, но изменение состояния выводов осуществляется программно в прерываниях таймера, поэтому будет наблюдаться небольшой "джиттер" в те моменты когда текущее прерывание накладывается на другое, происходящее в близкие моменты времени, или прерывания отключены на некоторое время. В данном небольшом проекте это возможно в двух местах - во время атомарного обновления ячейки позиции сервопривода или в случае если значения двух "соседних" серв в двух "строках" близки друг к другу и происходит перекрытие двух прерываний по совпадению. Можно было развесить все сервоприводы по ножкам всего контроллера но для экономии я воспользовался двумя сдвиговыми регистрами типа 595 и аппаратный SPI порт в режиме мастера. Можно воспользоваться и программной реализацией SPI для записи данных но тогда увеличится нагрузка на процессор, время для обновления состояний выводов увеличится в несколько раз и джиттер еще больше возрастёт.

Схема Плюсы предложенного решения:
1. Хорошее аппаратное разрешение для установки угла сервопривода, примерно 0.1 градуса, причем легко может быть увеличено в 8 раз за счет отказа от предделителя таймера1, но тогда возрастет и джиттер.
2. Задействовано всего 4 ножки микроконтроллера, причем две из них это аппаратный SPI порт, который может быть использован и для других приемников SPI.
3. Очень небольшой объём кода который управляет всем этим хозяйством, только Си, можно не ухищряться со встроенным ассемблером.
4. Подсистема работает на аппаратных таймерах и прерываниях, позволяет не отвлекаться на обработку в главном цикле - просто установил новые значения положений в табличке и забыл (не забываем про атомарность).
5. Позволяет расширить алгоритм введением скоростей перемещения в прерывании по переполнению и прочие "плюшки".

Недостатки (кудаж без них):
1. SPI порт довольно прилично занят, и, хотя, его можно использовать и в других целях, следует уделить внимание разделению времени, больше важна не загрузка порта а изохрнность слотов передачи для уменьшения джиттера.
2. Хороший во всех отношениях 16-битный Таймер1 с двумя регистрами сравнения полностью занят и считает в "обратном" режиме, переустанавливая вперед своё текущее значение в прерывании по переполнению. Единственная радость - период срабатывания таймера фиксированный и может использоваться ещё для чего-нибудь полезного. Прерывание TIMER1_CAPT_vect по захвату использовать можно но с плясками и бубном.
3. Исходя из принципа работы невозможно легко и просто расширить количество управляемых серв в рамках подсистемы.

Итак, как же это всё устроено. Подробно останавливаться на устройстве модельных серв и форме управляющего сигнала я не буду, это можно прочитать в [2] или [3], однако следует упомянуть о том что стадартный фрейм радиоуправления содержит сигналы для 8-ми машинок по очереди, таким образом сигнальный период каждой укладывается в 2.5 миллисекунды а пакет сигналов для 8-ми длится 20 миллисекунд. Раз так то мы можем считать интервалы для 8-ми машинок по очереди, у нас есть два регистра сравнения A и B, таким образом мы спокойно считаем интервалы для двух линеек машинок по 8 - итого 16. В переполнении таймера (каждые 2.5мс) мы устанавливаем фронт управляющего импульса для текущей пары машинок и взвзодим соответствующий регистр сравнения. А на сигнале сравнения сбрасываем уровень в ноль, вообще-то обнуляем мы все выводы в текущей "строке" машинок, но все выводы кроме одной и так нули.
Тут маленькое отступление: если задействовать еще один вывод контроллера на входы сброса регистров то можно обойтись без SPI передачи в перываниях по совпадению, просто сбрасывать соответствующий регистр в ноль через сигнал /MR. Не забываем всё равно дёрнуть ST_CP. А если вспомнить что установка и сброс этих регистров не влияет на другие то можно немного съэкономить на фрейме стека и определить прерывание по сравнению как ISR_NAKED.
Стоит ли такая оптимизация целой ножки контроллера за счет времени ожидания готовности SPI передачи и нескольких тактов на стек - решать вам.
На основе методики можно усложнять подсистему дополнительными элементами вроде групповой установки положений, установки крайних точек, среднего положения, различные передаточные характеристики, скорости перемещения и даже сценарии. Предварительные расчеты можно делать в функции установки параметров а периодические расчёты можно выполнять в прерывании переполнения, только уже после взведения текущих сигналов, передачи данных в регистры и перенастройке регистров сравнения. Следует только помнить что времени до первого срабатывания прерывания по сравнению не так много - в худшем случае не больше 1 миллисекунды, впрочем это не так и мало.

В проекте-примере я не стал вводить управление кнопками, потенциометрами или через, скажем, последовательный порт, при желании можно эти вещи добавить без особого труда согласно ваших предпочтений или требований, наоборот, пример автономно крутит сервами по синусоидальному закону со сдвигом фазы каждого привода, как это сделано в [2] у гуру DiHalt-а. Заодно получился неплохой пример расчета целочисленного синуса по табличке в четверть периода. Данный демонстрационный проект я не стал реализовывать в железе однако симуляция показывает что идея вполне себе жизнеспособна. Она и на самом деле работает :-)

Схема и исходники проекта можно взять тут.

Конструктивные замечания и предложения будут благоприятно восприняты по электронной почте тут


В работе над статьёй использовались следующие ресурсы:
1. OWL ROBOT User Manual
2. Управление множеством сервомашинок
3. Управление сервоприводом (сервомашинкой) с помощью микроконтроллера ATMega.

Еремеев Алексей