Ардуино: тахометр на прерываниях

Тахометр — это устройство для подсчёта скорости вращения вала двигателя или любого другого вращающегося объекта. Скорость вращения обычно измеряют в оборотах в минуту (об/мин) или по-английски revolution per minute (rpm).

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

Тахометр автомобиля

Для наших целей тахометр тоже пригодится. Зная скорость вращения колес робота, мы сможем вычислить скорость его линейного передвижения. А еще, попутным продуктом при вычислении скорости будет количество оборотов, что поможет нам рассчитать пройденный роботом путь (это называется одометрией). Другое применение — определение угла поворота манипулятора, который тоже можно рассчитать, зная количество совершенных оборотов мотора в суставе.

Как нам узнать скорость вращения вала двигателя? Очевидно, что нужно каким-то образом фиксировать каждый полный оборот вала вокруг своей оси и при этом засекать время, за которое этот самый полный оборот совершается. Нужен таймер и счётчик оборотов.

Детектировать оборот колеса можно по-разному. Два самых распространённых способа: оптический и магнитный. Более подробно про это мы поговорим на другом уроке, а для нашей текущей задачи выберем оптический способ — тахометр на основе фотопрерывателя.

На этом уроке мы:

  1. соберем стенд для измерения скорости вращения мотора;
  2. напишем программу для подсчёта оборотов;
  3. напишем программу для вычисления скорости вращения.

Список необходимых компонентов

Для выполнения всех экспериментов в этом уроке, кроме самого модуля джойстика, потребуется контроллер Arduino Uno или любой его аналог, модуль фотопрерывателя с компаратором LM393, моторчик и немного проводов вилка-розетка.

Необходимые компоненты можно добавить в корзину прямо здесь, и затем оформить заказ в нашем интернет-магазине.

В корзину
В корзину
В корзину
В корзину

Сборка испытательного стенда

Итак, в этом уроке будем использовать модуль фотопрерывателя с компаратором. Например, такой.

Фотопрерыватель — это прибор, который может детектировать прерывание луча каким-либо предметом. Обычно он состоит из инфракрасного светодиода с одной стороны и фотодиода (или фототранзистора) с противоположной.

Светодиод излучает свет, который проходит через зазор и достигает фотодиода. Если на пути этого луча появляется преграда, фотодиод перестает получать достаточно света и датчик начинает выдавать сигнал на соответствующем выводе. Сигнал при этом может быть высоким, а может и и низким, в случае инвертированной логики (у нас как раз последний случай).

Подключаем фотопрерыватель к Ардуино по следующей схеме:

Arduino Uno R3Gnd5V2
ФотопрерывательGndVccDO

Обычно, у такого датчика ещё есть выход A0, но в данном случае он нам не пригодится. Также на плате модуля есть светодиод, соединенный с DO. Он гаснет каждый раз, когда луч датчика прерывается.

Диск с прорезью

Теперь займёмся мотором. Сделаем диск с прорезью и наденем его на вал мотора. Можно использовать для этих целей 3D-принтер, а можно вырезать из картона.

Затем, поместим диск в зазор фотопрерывателя таким образом, чтобы на каждом обороте диска щель совпадала с лучом инфракрасного света и давала ему свободно пройти к фотодатчику.

Также рекомендуется прочно закрепить датчик относительно мотора, как на видео. Это позволит избежать ложных срабатываний и пропусков датчика.

Перейдем к программированию прерываний на Ардуино и к вычислению скорости вращения.

Программа

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

...
int rot = 0; // переменная для хранения количества оборотов
void loop(){
    if( digitalRead(2) ){ // если датчик сработал
        rot++; // прибавляем единичку к счетчику
        Serial.println(rot);
    }
}

Эта программа будет сносно считать количество оборотов и выводить их в последовательный порт. Но у такого решения есть большой недостаток. Если кроме подсчета оборотов в суперцикле loop будут другие операции, и не дай бог вызовы функции delay, то мы можем легко пропустить очередное срабатывание датчика! То есть в момент, когда щель на диске будет очередной раз пролетать мимо луча, контроллер будет занят какими-то другими делами и пропустит срабатывание.

Даже если в loop не будет ничего кроме digitalRead, мы всё равно рискуем пропустить срабатывание датчика при измерении скорости быстрых двигателей. Процедура digitalRead медленная. Что же делать?

Прерывания

Прерывания — это специальная аппаратная функция микроконтроллеров, которая позволяет прерывать выполнение основной программы по сигналу на определенных входах. Например, у Ардуино Уно есть два прерывания №0 и №1 на соответствующих выводах D2 и D3 (обычные цифровые ноги 2 и 3). 0 и 1 — это номера самих прерываний! Не путать с нумерацией ног Ардуино.

Если прерывание активировано, то при появлении на соответствующем контакте высокого уровня, программа мгновенно останавливается, и запускается так называемый обработчик прерывания. После выполнения кода обработчика, управление передается основной программе ровно в том же месте, где она была прервана.

Важное замечание. Код обработчика не должен выполняться слишком долго, иначе есть риск нарушить работу других прерываний и основной программы. А еще прерывание не должно вызываться слишком часто, иначе микроконтроллер только и будет, что висеть непрерывно в функции обработчика. В общем при работе с прерываниями есть много тонкостей, но мы не будем в них сильно углубляться на этом уроке.

Напишем программу для подсчета количества оборотов при помощи прерывания №0.

const byte interruptPin = 2; // контакт к которому подключен датчик
long int rot = 0; // переменная для хранения количества оборотов

// функция-обработчик, которая вызывается во время прерывания
void detect() {
    rot++;  
}

void setup() {
    Serial.begin(9600);
  
    // настроим контакт D2 на вход, да ещё с подтяжкой к питанию
    pinMode(interruptPin, INPUT_PULLUP);
    // активируем прерывание и свяжем его с функцией detect
    attachInterrupt(digitalPinToInterrupt(interruptPin), detect, RISING);
}

void loop() {
    Serial.println(rot);
    delay(100);
}

Функция digitalPinToInterrupt преобразует номер контакта Ардуино в номер прерывания. Вызов digitalPinToInterrupt(2) вернёт 0. Можно было явно написать:

attachInterrupt(0, detect, RISING);

Загрузим эту программу на Ардуино и откроем монитор последовательного порта.

Увидим вереницу чисел — это и есть количество оборотов. Каждые 100мс в порт вываливается текущее число оборотов, которое пока для нас бесполезно. Вот если бы у нас вращалось колесо робота, то умножив количество оборотов на длину окружности колеса мы бы получили пройденное расстояние! Обязательно попробуем это сделать в уроке про контроль движения робота.

А пока перейдем к скорости вращения.

Расчёт скорости

Изменим программу. Каждые 100мс будем считать скорость по формуле:

V = rot/dt

где rot — количество оборотов, dt — время, пройденное с последнего расчёта.

const byte interruptPin = 2;
unsigned int rot = 0;
unsigned long int tm;
unsigned long int spd = 0;
unsigned int dt = 0;

void detect() {
    rot++; // прибавляем единичку к счётчику обротов
    dt = millis() - tm; // вычисляем время с последнего расчёта
    if( dt >= 100 ){ // если прошло 100мс или более, то начинаем расчёт
        spd = rot*60000/dt;
        rot = 0; // обнуляем счётчик
        tm = millis(); // запоминаем время расчёта
    }
}

void setup() {
    Serial.begin(9600);
  
    pinMode(interruptPin, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(interruptPin), detect, RISING);

    tm = millis();
}

void loop() {
    Serial.println(spd);
    delay(100);
}

Откуда взялось 60000? Дело в том, что формула V = rot/dt даст нам скорость в единицах об/мс. Ведь dt у нас в миллисекундах. Чтобы превратить миллисекунды в секунды нужно dt поделить на 1000. А чтобы секунды в минуты — еще поделить на 60. Вот и получается: V = rot * 60000/dt.

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

Тахометр на Ардуино график

Также на графике виден шум — это колебания скорости вращения. К сожалению, коллекторный двигатель постоянного тока — машина не совершенная и его скорость имеет свойство «плавать». Но это тема совсем другого разбирательства.


Изменено:

Ардуино: тахометр на прерываниях: Один комментарий

  1. Здравствуйте, спасибо за статью. Можете рассказать поподробнее: почему скорость вращения якоря колеблеться?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.