11 февраля 2016 г.

Внешнее питание для сервопривода. Большая игра.

Тут задался вопросом - как управлять сервоприводом с Arduino? Все вроде просто, подключаешь питание, землю, плату и все! Но что, если сервопривод рассчитан на питание в 9 вольт? Поскольку Arduino дает только 5V, то для такого сервопивода нужен внешний источник питания. Не долго рылся в интернете, что бы найти схему, скорее дольше понимал принцип ее работы (это от недостатка знаний). Итак, опишу проектик.

Цели

Давайте будем управлять сервоприводом. Но не просто управлять, а управлять его скоростью. Так же было бы не плохо добавить участие человека в этом управлении. Пусть у привода будет 5 скоростей и каждое нажатие переключает ее на следующий уровень, а последнее нажатие возвращает нас на первую скорость. Все это будет грустно, если мы не будем знать, уровень скорости нашего привода. Для этого сделаем ответ из пяти разноцветных диодов. И для полноты картины и емкости знаний проекта будем использвать внешний источник питания для нашего сервопривода.

Итак, у нас есть Arduino, которая управляет сервоприводом, кнопка, нажатие которой меняет скорость работы серво и пять светодиодов, отображающих уровень скорости.

Ингридиенты

В этом проекте нам понадобится:
  • Плата Arduino
  • Кнопка
  • Инвертирующий триггер Шмитта
  • 5 резисторов на  100 Ом
  • 5 светодиодов (синий, зеленый, желтый, ораньжевый и красный)
  • Сервопривод с углом поворота на 180 градусов
  • Батарейка на 9V
  • Макетка

Прерывания


В этом проекте мы не будем считывать значение кнопки каждый раз в бесконечном цикле. Вместо этого мы воспользуемся прерываниями в Arduino. Прерывания обрабатываются в любое время бесконечного цикла не зависимо от выполняемого оператора. При возникновении прерывания процессор остановит выполнение бесконечного цикла программы, выполнит команды прерывания и продолжит выполнять бесконечный цикл с того места, где остановился.
У Arduino UNO есть только два пина, которые могут вызвать прерывание (D2 и D3) которым соответствуют значения 1 и 2 в функции прерывания. На практике же оказалось, что достаточно запомнить, что используются пины 2 и 3, а при установке прерывания воспользоваться функцией преобразования digitalPinToInterrupt.
В прерываниях можно что-то делать, например включать или выключать диод. Но нам нужно изменить переменную, которая отвечает за коэффициент скорости. Для того, что бы переменные изменялись во время прерывания, их необходимо описать как volatile.
Прерывание можно привязать к нескольким вариантам сигналов:

  • LOW - вызывается при сигнале пина LOW
  • CHANGE - вызывается при изменении сигнала на пине
  • RISING - вызывается, когда значение сигнала пина переходит от LOW к HIGH
  • FALLING - вызывается, когда сигнал пина меняется от HIGH к LOW
  • HIGH - вызывается, когда значение сигнала пина HIGH. Но не все Arduino поддерживают это событие.
Подробнее про прерывания написано здесь.

Инвертирующий триггер Шмитта

Его главная цель - убрать шумы. При нажатии на кнопку, сигнал на пин приходит HIGH, но из-за шумов он приходит не один раз за однократное нажатие. Триггер Шмитта потушит шумы. Более того, он инвертирует сигнал, который пришел к нему, т.е. LOW станет HIGH, а HIGH станет LOW. Мы хотим, что бы наша скорость менялась в момент, когда мы отпускаем кнопку. В этот момент сигнал пойдет на спад, значит нас устроит прерывание на событии FALLING. Все бы хорошо, но у нас используется инвертирующий триггер Шмитта, а значит наш сигнал будет инвертирован. В таком случае, мы должны использовать событие RISING.

Внешнее питание

Последний момент, который хотелось описать - это внешнее питание. Здесь все просто, к батарейке на 9V мы подключим только сервопривод, причем только положительный заряд. Землю мы все так же оставим подключенной к земле Arduino. Единственный нюанс, который стоит отметить - это земля батарейки. Ее нужно так же подключить к земле Arduino, что бы соблюсти замкнутость цепи.

Скеч

Далее последует сам скеч программы для Arduino и картинка со схемой соединения. Сам скеч я посарался прокомментировать достаточно подробно. Рабочую версию сземы можно посмотреть тут.

#include <Servo.h>
 
int buttonPin = 2;   // Пин кнопки
int ledBluePin = 7;   // Пин голубого диода
int ledGreenPin = 6;  // Пин зленого диода
int ledYellowPin = 5;  // Пин желтого диода
int ledOrangePin = 4;  // Пин оранжевого диода
int ledRedPin = 3;   // Пин красного диода
// Для простоты объявим массив наших диодов
int ledPinList[] = {ledBluePin, ledGreenPin, ledYellowPin, ledOrangePin, ledRedPin};
volatile int speedVal = 1; // Уровень скорости
int maxSpeedVal = 5;  // Максимальный уровень скорости
int minSpeedVal = 1;  // Минимальный уровень скорости
int servoPin = 9;   // Пин сервопривода
int servoDelay = 15;  // Задержка для сервопривода
Servo servo;    // Переменная управления сервоприводом
 
void setup()
{
  pinMode(buttonPin, INPUT);  // Пин кнопки ставим как INPUT, поскольку мы будем считывать ее состояние
  pinMode(ledBluePin, OUTPUT);  // Пин голубого диода ставим на вывод
  pinMode(ledGreenPin, OUTPUT);  // Пин зеленого диода ставим на вывод
  pinMode(ledYellowPin, OUTPUT); // Пин желтого диода ставим на вывод
  pinMode(ledOrangePin, OUTPUT); // Пин оранжевого диода ставим на вывод
  pinMode(ledRedPin, OUTPUT);  // Пин красного диода ставим на вывод
  pinMode(servoPin, OUTPUT);  // Пин сервопривода ставим на вывод
 
  Serial.begin(9600);    // Сериал монитор просто для вывода информации
 
  // Добавляем прерывание для кнопки
  // При возниковении прерывания будет вызвана функция changeSpeed
  // прерывание отработает на восходящем сигнале
  attachInterrupt(digitalPinToInterrupt(buttonPin), changeSpeed, RISING);
 
  servo.attach(servoPin);   // Говорим, к какому пину подключен сервопривод
 
  // Приветствие модели. Поморгают диоды и подвигается сервопривод. 
  // Так же это поможет убедиться, что все работает
  sayHello();
 
  // Включаем диоды согласно уровню скорости
  turnOnNLeds(speedVal);
}
 
// Функция изменения уровня скорости
void changeSpeed(){
  speedVal++;      // Увеличиваем значение уровня скорости
  if(speedVal > maxSpeedVal)  // Проверим, что он не превышает максимум
    speedVal = minSpeedVal;   // Если превышает, тогда устанавливаем минимальный уровень
  turnOnNLeds(speedVal);   // Включаем соответствующие диоды
}
 
// Функция изменения состояния всех диодов
void setLidsState(int state){
  for(int i = 0; i < sizeof(ledPinList); i++){  // Цикл по всем диодам
    digitalWrite(ledPinList[i], state);   // Устанавливаем состояние
  }
}
 
// Включение соответствующего уровня скорости
void turnOnNLeds(int count){
  for(int i = 0; i < sizeof(ledPinList); i++){ // Цикл по всем диодам
    if(i < count)        // Если диод меньше уровня скорости
     digitalWrite(ledPinList[i], HIGH);  // Включаем его
    else          // Иначе
     digitalWrite(ledPinList[i], LOW);  // Выключаем
  }
}
 
// Функция приветствия
void sayHello(){
  int helloDelay = 200;       // Переменная задержки 0,2 сек
  setLidsState(LOW);       // Выключаем все диоды
  for(int i = 0; i < sizeof(ledPinList); i++){ // Цикл по всем диодам
    digitalWrite(ledPinList[i], HIGH);   // Включаем текущий диод
    delay(helloDelay);       // Ждем
    digitalWrite(ledPinList[i], LOW);   // Выключаем текущий диод
  }
  delay(helloDelay);       // Снова ждем
  for(int i = 0; i < 3; i++){     // Цикл на 3 итерации. Моргнем три раза всеми диодами
    setLidsState(HIGH);       // Включаем все диоды
    delay(helloDelay);       // Ждем
    setLidsState(LOW);       // Выключаем все диоды
    delay(helloDelay);       // Снова ждем
  }
}
 
// Бесконечный цикл
void loop()
{
  // Цикл на 180 градусов с шагом уровня скорости
  for(int i = 0; i < 180; i = i + speedVal){
    if(i >= 180) break;  // Если текущее положение превышает 180 градусов, то прерываем цикл
    servo.write(i);   // Команда сервоприводу повернуться на градус
    delay(servoDelay);  // Ждем выполнения
  }
  // Тот же цикл, но в обратную сторону
  for(int i = 179; i >= 0; i = i - speedVal){
    if(i < 0) break;
    servo.write(i);
    delay(servoDelay);
  }
}
 

Заключение

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

3 комментария:

  1. Алексей, из статьи не совсем понятно, о какой скорости идёт речь. Ведь сервопривод предназначен для поворота центрального шпинделя на определённый градус. Данный вид "моторчиков" не обладает скоростными характеристиками его основная задача, преодолеть сопротивление при повороте через редуктор.Таким образом, команда servo.write(i); приведёт к повороту центрального шпинделя на градус равный переменной i. Возможно вы имели ввиду привод постоянного вращения.

    ОтветитьУдалить
    Ответы
    1. Александр, статья относилась именно к сервомоторчикам. Я соглашусь с Вами относительно скоростных характеристик. Наверное будет правильнее назвать это мнимой скоростью, учитывая приведенный факт. На сколько я понимаю, на скорость вращения можно повлиять двумя способами в данной ситуации: сократить расстояние поворота или увеличить ток. Второй вариант я не могу попробовать физически. Первый вариант приведет к ускорению за счет того, что поворот будет не полный.

      Удалить
    2. ...понятно о какой скорости...) шагающие роботы...

      Удалить