CUSTOMELECTRONICS.RU
Информационно-учебный блог о разработке электроники
Эл. почта: info@customelectronics.ru

Управление несколькими сервоприводами с высокой точностью на микроконтроллере

В этой статье речь пойдет об алогоритмах формирования сигналов для одновременного управления несколькими сервоприводами.

Управляющий сигнал сервопривода

Как известно, для управления сервоприводом необходимо на его управляющий вход подавать импульсный сигнал с одинаковой частотой и разной длительностью импульса. Длительность импульса может быть от 0,7 до 2,3мс, она определяет положение привода.

Сигнал сервопривода

Управляющий сигнал сервопривода

Этот сигнал является стандартным, и применяется во многих других устройствах: драйверах двигателей, системах радиоуправления, телеметрии и т.д. Сформировать такой сигнал на микроконтроллере очень просто, например запустить генератор ШИМ-сигнала. Но что делать, если надо управлять несколькими сервомашинками одновременно?

Существующие алгоритмы

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

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

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

Наш алгоритм

Алгоритм, разработанный нами, был придуман в процессе работы над этим проектом.

Сигналы для управления сервоприводами формируются один за другим, что приводит к ограничению — на один таймер не более 8 приводов.

Сигналы сервоприводов

Сигналы для нескольких приводов

Принцип формирования следующий:

  1. Запускаем таймер задав какое-то начального значение для прерывания совпадения.
  2. Задаем и обнуляем некоторую переменную, которая будет считать такты. Для каждого сервопривода требуется два такта: фронт импульса и спад.
  3.  При первом попадании в прерывании (о чем узнаем по состоянию счетчика) выводим на пин единицу, записываем в регистр совпадения требуемую длительность импульса и увеличиваем счетчик .
  4. При втором срабатывании прерывания проверяем счетчик, выводим на пин 0, записываем в регистр сколько тиков осталось до начала импульса для второго сервопривода и так далее.

Мы реализовывали алгоритм на микроконтроллере Atmega16. У него на борту имеется 16-ти битный таймер. Тактовая частота в нашем проекте была 8МГц, поэтому таймер мы запустили с делителем 8. В нашем случае требовалось управлять четырьмя приводами, поэтому весь период мы разделили на части по 5000мкс. Углы задаются в основном цикле программы прямо в микросекундах от 700 до 2300.

Исходный код

#define CYCLE 5000

volatile int angle1 = 700;
volatile int angle2 = 700;
volatile int angle3 = 700;
volatile int angle4 = 700;
volatile int takt = 0;

void timer1_init() {
OCR1A = 20000;
TCCR1A = 0;
TCCR1B |= (1 << WGM12);}

void timer1_start() {
TCNT1 = 0;
TCCR1B |= (1<<CS11);
TIMSK |= (1 << OCIE1A);}

void timer1_stop() {
TCCR1B &= 0b11111000;
TIMSK &= !(1 << OCIE1A);}

void main () {
sei();
timer1_init();
timer1_start();
while (1){
//Основной цикл в котором меняются значения angle1, angle2, angle3, angle4
}}

ISR(TIMER1_COMPA_vect) {
if (takt == 0) {
SERVO_PORT |= (1<<SERVO_PIN1);
OCR1A = angle1;}
if (takt == 1) {
SERVO_PORT &= ~(1<<SEVO_PIN1);
OCR1A = CYCLE - angle1;}
if (takt == 2) {
SERVO_PORT |= (1<<SERVO_PIN2);
OCR1A = angle2;}
if (takt == 3) {
SERVO_PORT &= ~(1<<SEVO_PIN2);
OCR1A = CYCLE - angle2;}
if (takt == 4) {
SERVO_PORT |= (1<<SERVO_PIN3);
OCR1A = angle3;}
if (takt == 5) {
SERVO_PORT &= ~(1<<SEVO_PIN3);
OCR1A = CYCLE - angle3;}
if (takt == 6) {
SERVO_PORT |= (1<<SERVO_PIN4);
OCR1A = angle4;}
if (takt == 7) {
SERVO_PORT &= ~(1<<SEVO_PIN4);
OCR1A = CYCLE - angle4;}
takt = takt + 1;
if (takt == 9) takt = 0;};

Для работы с кодом остается объявить порты и инициализировать их, а также добавить алгоритм изменения углов в основной цикл. Значения углов можно принимать по UART или считывая состояние управляющего резистора с АЦП. В нашем проекте был написан цикл, который бесконечно повторялся пока нажата кнопка.

Итоги

Нам удалось устанавливать длительность сигнала с точностью до одной микросекунды. При этом сами двигатели меняют свое положение с точностью 3-5мкс. Это дало нам возможность реализовать максимально плавный ход двигателей. Вычислительные затраты минимальны, все формирование сигнала в коротком прерывании. Обратите внимание на машинку, которая находится в самом нижнем углу — ее перемещение практически не заметно для глаза!

Мы будем очень рады, если вы поддержите наш ресурс и посетите магазин наших товаров shop.customelectronics.ru.

Метки: , , Просмотров: 13340