Тахометр — это устройство для подсчёта скорости вращения вала двигателя или любого другого вращающегося объекта. Скорость вращения обычно измеряют в оборотах в минуту (об/мин) или по-английски revolution per minute (rpm).
Тахометр можно увидеть на приборной панели большинства автомобилей, его используют для контроля оборотов коленвала двигателя. Но в действительности тахометр имеется в системе практически каждого серьёзного двигателя: в самолете, в автомобиле, в станке, в турбине электростанции.
Для наших целей тахометр тоже пригодится. Зная скорость вращения колес робота, мы сможем вычислить скорость его линейного передвижения. А еще, попутным продуктом при вычислении скорости будет количество оборотов, что поможет нам рассчитать пройденный роботом путь (это называется одометрией). Другое применение — определение угла поворота манипулятора, который тоже можно рассчитать, зная количество совершенных оборотов мотора в суставе.
Как нам узнать скорость вращения вала двигателя? Очевидно, что нужно каким-то образом фиксировать каждый полный оборот вала вокруг своей оси и при этом засекать время, за которое этот самый полный оборот совершается. Нужен таймер и счётчик оборотов.
Детектировать оборот колеса можно по-разному. Два самых распространённых способа: оптический и магнитный. Более подробно про это мы поговорим на другом уроке, а для нашей текущей задачи выберем оптический способ — тахометр на основе фотопрерывателя.
На этом уроке мы:
- соберем стенд для измерения скорости вращения мотора;
- напишем программу для подсчёта оборотов;
- напишем программу для вычисления скорости вращения.
Список необходимых компонентов
Для выполнения всех экспериментов в этом уроке, кроме самого модуля джойстика, потребуется контроллер Arduino Uno или любой его аналог, модуль фотопрерывателя с компаратором LM393, моторчик и немного проводов вилка-розетка.
Необходимые компоненты можно добавить в корзину прямо здесь, и затем оформить заказ в нашем интернет-магазине.
Сборка испытательного стенда
Итак, в этом уроке будем использовать модуль фотопрерывателя с компаратором. Например, такой.
Фотопрерыватель — это прибор, который может детектировать прерывание луча каким-либо предметом. Обычно он состоит из инфракрасного светодиода с одной стороны и фотодиода (или фототранзистора) с противоположной.
Светодиод излучает свет, который проходит через зазор и достигает фотодиода. Если на пути этого луча появляется преграда, фотодиод перестает получать достаточно света и датчик начинает выдавать сигнал на соответствующем выводе. Сигнал при этом может быть высоким, а может и и низким, в случае инвертированной логики (у нас как раз последний случай).
Подключаем фотопрерыватель к Ардуино по следующей схеме:
Arduino Uno R3 | Gnd | 5V | 2 |
Фотопрерыватель | Gnd | Vcc | DO |
Обычно, у такого датчика ещё есть выход 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.
Загрузим программу и откроем плоттер для изображения наших данных в виде графика. Если мотор подключен к лабораторному источнику питания, можно менять напряжение и смотреть как меняется скорость вращения.
Также на графике виден шум — это колебания скорости вращения. К сожалению, коллекторный двигатель постоянного тока — машина не совершенная и его скорость имеет свойство «плавать». Но это тема совсем другого разбирательства.
Здравствуйте, спасибо за статью. Можете рассказать поподробнее: почему скорость вращения якоря колеблеться?