Главная > Hard > Простой способ управлением сервоприводом SG90

Простой способ управлением сервоприводом SG90

IDE для Arduino предлагает готовую библиотеку Servo для управления сервоприводами. Это хорошее решение, если надо управлять ими в простом проекте. При работе над более сложной задумкой приходится бороться за каждый байт кода и думать над нестандартными решениями.

В предыдущих статьях была описана работа с камерой OV7670 . Данный пример основан на одном из таймеров Arduino Uno, для которого была изменена частота и отключены прерывания. Из-за этого и неудачи при портировании библиотеки Servo в AtmelStudio от готового решения пришлось отказаться.

Ниже будет предложен альтернативный способ управления сервоприводом SG90 без библиотеки Servo.

Сервопривод SG90

Для начала стоит сказать, что сервопривод управляется импульсами определённой длительности и частоты. От длительности зависит угол поворота. 544 мкс — поворот в 0 градусов. 2400 мкс — поворот в 180 градусов. Импульсы для SG90 должны посылаться с частотой 50Гц. Это даёт интервал 20000 мкс между импульсами.

Как работает сервопривод SG90

Вся задача управления сводится к подаче нужного количества импульсов определенной длинны на сервопривод. Из-за невозможности вызвать функцию _delay_us с динамическим значением, приходится разбивать интервал от 544 до 2400 на 18 шагов с величиной 103, чтоб минимальный шаг сервопривода был 10 градусов.

В примере ниже управляющий провод подключается к порту D3 и сервопривод поворачивается от 0 до 180 градусов с шагом 10.

Подключение SG90

#define MIN_PULSE_WIDTH       544 
#define MAX_PULSE_WIDTH      2400
#define ANGLE_PULSE_WIDTH      103
#define PULSE_WIDTH         20000  

#define NUMBER_OF_TIMES 18
#define PORT      0x08 //Digital 3 (D3)
#define DELAY      100000

int main(void) {
  DDRD = PORT; //Set D3 as output
  while(1) {
    int i = 0;
    for (i = 0; i <= 18; i++) {
        angle(i);
    }

  }
}

void angle(int angle) {
    int i = 0;
    int j = 0;
    
    PORTD = 0x00;

    for (i = 0; i < NUMBER_OF_TIMES; i++) {
        PORTD = PORT;

        _delay_us(MIN_PULSE_WIDTH);
        for (j = 0; j < angle; j++) {
            _delay_us(ANGLE_PULSE_WIDTH);
        }

        PORTD = 0x00;

        _delay_us(PULSE_WIDTH - MAX_PULSE_WIDTH);
        int remaining = (MAX_PULSE_WIDTH - MIN_PULSE_WIDTH - angle*ANGLE_PULSE_WIDTH)/ANGLE_PULSE_WIDTH;
        for (j = 0; j < remaining; j++) {
            _delay_us(ANGLE_PULSE_WIDTH);
        }
    }
    _delay_us(DELAY);
}
Categories: Hard Tags: , ,
  1. Антон
    9 Февраль 2018 в 01:19 | #1

    Пробовал использовать приведенный пример в своей задаче:
    ардуина принимает ИК сигнал и в зависимости от этого меняет направление вращения сервы.
    У меня ничего не вышло (
    Полагаю это связанно с тем что используется напрямую обращение к ногам процессора?(так это называется?)
    Так же мне пришлось изменить int main(void) на void setup() т.к. в противном случае у меня ничего не компилилось.

    Если вызывать функцию angle передавая ей в качестве параметра число то все работает. Но как только я пробую передать туда переменную всё ломается (

    #define MIN_PULSE_WIDTH 1125
    #define MAX_PULSE_WIDTH 1925
    #define ANGLE_PULSE_WIDTH 100
    #define PULSE_WIDTH 20000

    #define PORT 0x08 //Digital 3 (D3)

    #include «IRremote.h»
    IRrecv irrecv(2); // указываем вывод, к которому подключен приемник
    decode_results results;

    void setup() {
    int angle_test=3;
    // pinMode(13, OUTPUT);
    irrecv.enableIRIn(); // запускаем прием
    DDRD = PORT; //Set D3 as output
    while(1){
    if ( irrecv.decode( &results )) { // если данные пришли
    switch ( results.value ) {
    case 0xFFA857:
    //digitalWrite( 13, HIGH );
    angle_test=1;
    break;
    case 0xFFE01F:
    //digitalWrite( 13, LOW );
    angle_test=7;
    break;
    }
    irrecv.resume(); // принимаем следующую команду
    }
    angle(angle_test); // если вызывать функцию с числом а не с переменной то всё ок
    // angle(3); // параметр функции задает скорость вращения, у меня серва 360
    }
    }

    void angle(int anglef) {

    PORTD = 0x00;
    PORTD = PORT;
    //_delay_us(MIN_PULSE_WIDTH);
    _delay_us(MIN_PULSE_WIDTH + ANGLE_PULSE_WIDTH * anglef);
    PORTD = 0x00;
    _delay_us(PULSE_WIDTH — MAX_PULSE_WIDTH);
    }


    Anton Belov




    0



    0
  2. Антон
    9 Февраль 2018 в 01:21 | #2

    Не мог понять почему не дает запостить комент.
    Ему оказывается ссылка не нравилась и он белый экран показывал.
    Это ссылка на библиотеку:
    гитхаб.ком/z3t0/Arduino-IRremote




    0



    0
  1. Пока что нет уведомлений.