Тахометр на Arduino
Тахометр – это полезный инструмент для подсчета RPM (оборотов в минуту) колеса или всего, что крутится. Самый простой способ сделать тахометр – это использовать ИК передатчик и приемник. Когда связь между ними прерывается, вы знаете, что что-то вращается и можете применять код для вычисления RPM, ориентируясь на частоту прерывания связи.
В этой статье мы рассмотрим, как использовать ИК-передатчик и приемник для изготовления тахометра с применением Arduino. Результат отображается на ЖК-дисплее 16х2.
Целью данного проекта является создание системы с одним входом и одним выходом. На входе устройства присутствует сигнал, изменяющийся с высокого (+5В) на низкий (+0В) уровень при нарушении связи.
Согласно этому сигналу, Arduino будет увеличивать значение внутреннего счетчика.
Потом проводится дополнительная обработка и расчет, и по прерыванию триггера на ЖК-дисплей будет выводиться рассчитанное RPM.
Для связи мы будем использовать ИК-луч от ИК-светодиода, включенного через низкоомный резистор так, чтобы светиться ярко. В качестве приёмника мы будем использовать фототранзистор, который при отсутствии света ИК-светодиода “закрывается”.
Компьютерный вентилятор будет размешен между ИК-передатчиком и приёмником и включен. ИК-приёмник включенный через транзисторную схему, будет генерировать прерывания.
Для вывода результата будет использоваться Arduino LCD интерфейс, поэтому мы можем вывести окончательное значение RPM на ЖК-дисплей.
Элементы: Arduino UNO 16×2 LCD Макетная плата Подстроечный резистор 5 кОм Перемычки SIP разъёмы 2x 2N2222 NPN транзистор Инфракрасный светодиод Фототранзистор Резистор 10 Ом Резистор 100 кОм Резистор 15 кОм или 16 кОм
Компьютерный вентилятор
Подробный список элементов
Все элементы используемые в проекте указаны выше, но я более подробно опишу функции основных элементов.
Arduino UNO
Это плата Arduino, которую мы будем использовать для обработки импульсов от прерывания ИК-луча, которые сообщают о нахождении лопасти компьютерного вентилятора между приемником и датчиком. Arduino будет использовать эти импульсы наряду с таймером, чтобы вычислить RPM вентилятора.
ЖК-дисплей 16×2
После того, как Arduino вычислило RPM, эта значение будет отображаться на дисплее в понятном для пользователя виде.
Подстроечный резистор 5 кОм
Этот подстроечный резистор будет использоваться для регулировки контрастности ЖК-дисплея 16×2. Он дает аналоговое напряжение в диапазоне от 0 до +5В, позволяя настроить яркость ЖК-дисплея.
Инфракрасный светодиод и Фототранзистор
Фототранзистор открывается, когда мощный ИК-свет падает на него. Поэтому, когда ИК-светодиод горит, он держит фототранзистор открытым, но если ИК-светодиод закрывается например, лопастью вентилятора, то фототранзистор закрывается.
2N3904 и 2N3906
Эти транзисторы используются для преобразования уровня сигнала, с целью обеспечения выходных импульсов с фототранзистора для Arduino, в которых нет никаких напряжений кроме +0 и +5В.
Принципиальная схема
В схеме, интерфейс связи с ЖК-дисплеем упрощен и имеет только 2 линии управления и 4 линии передачи данных.
Особенности схемы
Интерфейс ЖК-дисплея 16×2
2 управляющих контакта и 4 для передачи данных подключены от Arduino к ЖК-дисплею. Это то, что указывает ЖК-дисплею, что и когда делать.
Схема обрыва ИК-луча
Сигнал обрыва ИК-луча идет на 2-ой цифровой контакт Arduino. Это прерывает Arduino, что позволяет ему засчитать импульс и позволяет тахометру получать данные.
Arduino LCD библиотека
Для этого проекта мы будем использовать Arduino LCD библиотеку. В основном мы будем просто обновлять значение RPM на второй строке на новое.
В качестве подготовки, посмотрите на код приведенный ниже, в котором при помощи этой библиотеки на ЖК-дисплей выводиться “Hello, World!” В тахометре мы будем использовать похожий код, особенно: “lcd.print(millis()/1000);”.
Разберитесь в функциях этой ЖК-библиотеки как можно подробнее, прежде чем двигаться дальше. Она не слишком сложна и хорошо документирована на сайте Arduino.
Подсчет RPM при помощи Arduino
Так как мы собираемся подсчитать RPM компьютерного вентилятора, мы должны понимать, что для подсчета мы используем прерывание ИК-луча. Это очень удобно, но мы должны учитывать, что у компьютерного вентилятора 7 лопастей. Это значит, 7 прерываний равно 1 обороту.
Если мы будем отслеживать прерывания, мы должны знать, что каждое седьмое прерывание означает, что только что произошел 1 полный оборот. Если мы отследим время, необходимое для полного оборота, то мы легко вычислим RPM.
Время 1-го оборота = P * (µS/оборот)
RPM = кол-во оборотов/мин = 60 000 000 * (µS/мин) * (1/P) = (60 000 000 / P) * (кол-во оборотов/мин)
Для расчета RPM мы будем использовать формулу приведенную выше. Формула точная, и точность зависит от того, насколько хорошо Arduino сможет отслеживать время между прерываниями и посчитывать количество полных оборотов.
Сборка схемы
На фотографии ниже вы можете увидеть все необходимые детали и перемычки как на схеме.
Для начала подключается +5В и линии данных/управления ЖК-дисплея. Затем ЖК-дисплей, потенциометр контрастности и светодиод питания.
Схема обрыва ИК-луча собрана. Старайтесь, чтобы между ИК-светодиодом и фототранзистором было расстояние. На этой фотографии видно расстояние между ИК-светодиодом и фототранзистором, где я размещу компьютерный вентилятор.
Хватит разговоров о аппаратной части! Давайте начнем делать прошивку/программу, чтобы увидеть работу устройства!
Программная часть
Есть две основных части кода, которые показаны и подробно описаны ниже: -Основной цикл обновления ЖК-дисплея
-Обновление времени прерываний
В основном цикле считаются обороты и обновления ЖК-дисплея. Поскольку основной цикл это гигантский while(1) цикл, то он будет работать всегда, RPM считаться, а ЖК-дисплей обновляться несколько раз в секунду. Функция в прерывании подсчитывает время между прерываниями ИК, поэтому считать RPM можно в основном цикле.
Помните, что компьютерный вентилятор имеет 7 лопастей, так что это тахометр предназначен для работы только с такими вентиляторами. Если ваш вентилятор или другое устройство дает только 4 импульса за оборот, измените в коде “(time*4)”.
Два вентилятора работают на примерно 3000 оборотов в минуту и 2600 оборотов в минуту, с погрешностью около + / -100 оборотов в минуту.
Обзор тахометра на Arduino
Вентилятор генерирует импульсы прерывания, а на выходе мы видим RPM. Хотя точность не 100%, а примерно 95%, при стоимости элементов 10$ есть смысл построить этот тахометр на Arduino.
Что теперь делать?
Системы на основе обрыва луча полезны не только при измерении RPM, но и в качестве других датчиков. Например, вы хотите знать, открыта дверь или закрыта. Возможно, вы хотите знать, не проходило-ли что то под роботом. Есть много применений обрыва луча, а схема используемая тут настолько проста, что есть много путей для улучшения и сборки других удивительных устройств.
Заключение
В целом, я считаю этот проект успешным… Но дело во времени и опыте.. Так или иначе, система работает как задумывалось и достаточно надежно, а мы получили ожидаемый результат. Надеюсь, вам понравилось прочитать эту статью и узнать как сделать свой собственный тахометр на Arduino!
Скачать список элементов (PDF)
Оригинал статьи
Прикрепленные файлы:
- lcd_tachometer.rar (1 Кб)
Источник: http://cxem.net/arduino/arduino66.php
Тахометр или спидометр: Поток мыслей про измерение частоты в Arduino
Если дома есть Arduino, в гараже машина или мотоцикл, а то и хоть мотособака, в голове туманные представления о программировании — возникает желание измерить скорость движения или обороты двигателя, посчитать пробег и моточасы.
В данной статье я хочу поделиться своим опытом по изготовлению подобных поделок.
// Сразу скажу, что код, указанный в статье не для копипаста, а для иллюстраций. // Я конкретно эти примеры не компилировал. У меня код ещё по проекту размазан.
Немного физики
Для измерения частоты вращения нам понадобится датчик положения колеса/вала/круга/итп. Датчик ставится как правило один. Возможно, что он будет срабатывать не один раз на каждый оборот. Например, у вас датчик Холла и 4 магнита на колесе. Таким образом, для правильного вычисления частоты нужно знать:
- количество срабатываний датчика на один оборот К;
- минимальная ожидаемая частота Мин.
- максимальная ожидаемая частота Макс.
Вычисленная = ВычисляемЧастоту() / К;
Если (Частота < Мин) Частота = 0
Иначе Если (Частота < Макс) Частота = Вычисленная
То есть, если частота меньше разумного минимума, то считаем, что она равна нулю, если больше максимума — игнорируем показания.
С количеством срабатываний понятно, но зачем ещё эти мины и максы? Давайте рассмотрим сначала варианты расчёта частоты.
Со скоростью всё проще, достаточно знать число π, диаметр колеса, а частоту вращения мы уже знаем.
Болванка для кода
Так как мы имеем дело с такими нежными величинами как время и пространство, то лучше сразу освоить прерывания.
const byte fqPin = 2; // Для ATMega32 только 2 или 3. volatile unsigned long counter = 0; // Функция для обработки прерывания.
void ISR() { // Здесь код прерывания counter++; // Например
} void setup() { Serial.begin(115200); // Подключаем функцию ISR на прерывание по появлению сигнала на ноге fqPin. attachInterrupt(digitalPinToInterrupt(fqPin), ISR, RISING);
} void loop() { // Копируем данные. noInterrupts(); unsigned long cnt = counter; interrupts(); // Здесь делаем что-то с полученными данными. // … Serial.println(cnt); delay(1000);
}
Обратите внимание на модификатор volatile у переменной counter. Все переменные, которые будут изменяться в обработчике прерывания (ISR) должны быть volatile. Это слово говорит компилятору, что переменная может изменяться неожиданно и доступ к ней нельзя оптимизировать.
Функция ISR() вызывается каждый раз, когда появляется единица на ноге fqPin. Мы эту функцию не вызываем, это делает сам контроллер. Он это делает, даже когда основная программа стоит в ступоре на функции delay().
Считайте, что ISR() обслуживает событие, от вас не зависящее и данное вам свыше как setup() и loop(). Контроллер прерывает выполнение вашей программы, выполняет ISR() и возвращается обратно в ту же точку, где прерывал.
Обратите внимание, что в функции loop() мы отключаем прерывания вообще любые для того, чтобы прочитать переменную counter и сохранить её во временную переменную cnt. Потом, конечно же, включаем снова.
Так мы можем потерять один вызов, конечно же, но с другой стороны, переменная unsigned long имеет 32 бита, а процессор ATMega32 8-битный, вряд ли он скопирует данные за один такт, а ведь в процессе копирования может случиться прерывание и часть данных изменится.
По этой же причине мы копируем значение counter локально так как значение этой переменной при использовании в разных местах программы может быть разным опять же из-за изменения её в прерывании.
Тело функции ISR() должно быть максимально коротким, точнее, сама функция должна выполняться максимально быстро. Это важно, так как прерывается выполнение вашего кода, который может оказаться чувствительным к непредвиденным задержкам. Некоторые библиотеки отключают прерывания для выполнения чувствительных с задержкам операций, например для управления светодиодной лентой WS2812.
Считаем обороты за единицу времени
Первое, что приходит в голову, это взять интервал времени и посчитать количество измерений.
Частота = ( Счётчик / Время ) / К
const byte fqPin = 2; // Для ATMega32 только 2 или 3.
const unsigned long interval = 1000000UL; // Интервал подсчёта в микросекундах
const int K = 1; unsigned long oldMks = 0; // предыдущий момент времени volatile unsigned long counter = 0; // Функция для обработки прерывания.
void ISR() { // Здесь код прерывания counter++; // Например
} void setup() { Serial.begin(115200); // Подключаем функцию ISR на прерывание по появлению сигнала на ноге fqPin. attachInterrupt(digitalPinToInterrupt(fqPin), ISR, RISING);
} void loop() { // вычисляем текущий момент времени unsigned long mks=microseconds(); // Получаем данные. noInterrupts(); unsigned long cnt = counter; counter = 0; // Сразу сбросим счётчик interrupts(); // Выводим частоту в оборотах в секунду Serial.println( 1000000f * (float)cnt / (float)(mks-oldMks) / (float)K ); // 1000000 микросекунд в секунде // далее по формуле выше. // mks-oldMks лучше, чем interval потому, что это реальное время от последнего // опроса счётчика, а interval — предполагаемое. // Все целые переменные приводим в вещественные oldMks=mks; // Сохраняем время вычисления. // Спим пока копятся отсчёты до следующего вычисления delayMicroseconds(interval);
}
Как и у многих простых решений, у этого есть неочевидные минусы. Для повышения точности измерений вам необходим довольно большой интервал времени. Принцип тот же, что и у Шума квантования. При времени оборота колеса сравнимом с временем подсчёта, существенные изменения скорости вращения не будут замечены. Показания такого частотомера будут различаться до двух раз на каждый отсчёт.
Для повышени точности на малой скорости можно увеличить число К, как это сделано, скажем, в автомобильной технике для датчика ABS. Можно увеличить время подсчёта.
Делая и то и другое мы подходим ко второй проблеме — переполнению счётчика.
Да, переполнение легко лечится увеличением количества бит, но арифметика процессора Arduino не умеет считать 64-битные числа столь быстро, как хотелось бы и как она это делает с 16-разрядными.
Увеличение времени расчёта тоже не очень хорошо тк нам надо знать частоту прямо сейчас, вот при нажатии на газ, а не через пару секунд. Да и через пару секунд мы получим скорее некое среднее значение. За это время можно несколько раз сделать врумм-врумм.
Есть другой метод. Он лишён вышеописанных недостатков, но, как водится, имеет свои.
Считаем интервал между отсчётами
Частота = 1 / ( Интевал * К )
Мы можем засечь время одного отсчёта и другого, вычислить разницу. Величина, обратная вычисленному интервалу и есть частота. Круто! Но есть минусы.
const byte fqPin = 2; // Для ATMega32 только 2 или 3.
const int K = 1; volatile unsigned long interval; // Функция для обработки прерывания.
void ISR() { // Здесь код прерывания static unsigned long oldTime; // Сохраняем предыдущее значение. unsigned long Time=microseconds(); interval=Time-OldTime(); oldTime=Time;
} void setup() { Serial.begin(115200); // Подключаем функцию ISR на прерывание по появлению сигнала на ноге fqPin. attachInterrupt(digitalPinToInterrupt(fqPin), ISR, RISING);
} void loop() { // Получаем данные. noInterrupts(); unsigned long cnt = interval; interrupts(); // Выводим частоту в оборотах в секунду Serial.println( 1000000f / ( (float)K * (float)(cnt) ); // 1000000 микросекунд в секунде // далее по формуле выше. // Все целые переменные приводим в вещественные // Спим, чтобы не заливать экран потоком данных // Четверть секунд — хорошее время. delay(250);
}
Что делать, если наше колесо крутится еле-еле и измеренный интервал превышает разумные пределы? Выше я предложил считать частоты ниже разумного минимума за ноль.
Определённым недостатком метода можно считать шумы квантования на высоких частотах, когда целочисленный интервал снижается до нескольких двоичных разрядов.
Так же хотелось бы некую статистику подсчётов для улучшения показаний, а мы берём лишь последнее значение.
Методом проб и ошибок я подобрал интервал отображения данных на дисплее в 250мс как оптимальный. Если чаще, то цифры размазываются, если реже — бесит тормознутость.
Комбинированный метод
Можно попробовать объединить достоинства обоих методов.
Частота = Счётчик / ИнтервалИзмерения / К
То есть, мы засекаем время не просто между отсчётами, а время между проверками данных и делим на количество отсчётов за это время. Получается усреднённый интервал между отсчётами, обратная величина от которого есть частота. Предоставим компилятору оптимизировать вычисления.
const byte fqPin = 2; // Для ATMega32 только 2 или 3.
const int K = 1; volatile unsigned long counter; // Количество отсчётов.
volatile unsigned long mks; // Время последнего отсчёта. unsigned long oldTime; // Время последнего отсчёта в предыдущем вычислении. // Функция для обработки прерывания.
void ISR() { // Здесь код прерывания mks=microseconds(); // Момент последнего отсчёта counter++; // Количество отсчётов
} void setup() { Serial.begin(115200); // Подключаем функцию ISR на прерывание по появлению сигнала на ноге fqPin. attachInterrupt(digitalPinToInterrupt(fqPin), ISR, RISING);
} void loop() { unsigned long rpm; // Получаем данные. noInterrupts(); unsigned long cnt = counter; counter = 0; unsigned long tmr = mks; interrupts(); // Выводим частоту в оборотах в секунду if (cnt > 0) { rpm = 1000000UL / ((tmr – oldTime) / cnt) / K; oldTime = tmr; } else { rpm = 0; } Serial.println( rpm ); delay(250);
}
Обратите внимание, что за интервал считается не время опроса, как в первом примере, а время от последнего отсчёта до предыдущего последнего отсчёта в прошлом опросе. Это заметно поднимает точность вычисления.
Таким образом, мы можем получать вполне достоверные данные как на низких так и на высоких частотах.
Если использовать кооперативную многозадачнось, то можно сделать подсчёт, скажем раз 100мс, а вывод на дисплей раз в 250мс. Очень короткий интервал опроса снизит чувствительность к низким частотам.
Как говорят в рекламе, “но это ещё не всё”.
Ошибки дребезга
Для устрашения вас предположу, что измеряем частоту вращения двигателя от индуктивного датчика зажигания. То есть, грубо говоря, на высоковольтный провод намотан кусок кабеля и мы измеряем индукцию в нём. Это довольно распространённый метод, не правда ли? Что же здесь сложного может быть? Самая главная проблема — современные системы зажигания, они дают не один импульс, а сразу пачку.
Примерно так:
Но даже обычная система зажигания даёт переходные процессы:
Старинные же кулачковые контактные вообще показывают замечательные картинки.
Как с этим бороться? Частота вращения не может вырасти мгновенно, не даст инерция. Кроме того, в начале статьи я предложил ограничить частоту сверху разумными рамками. Отсчёты, что происходят слишком часто можно просто игнорировать.
МинимальныйИнтервал = ( 1 / ( K * МаксимальнаяРазумнаяЧастота) )
const byte fqPin = 2; // Для ATMega32 только 2 или 3.
const int K = 1;
const unsigned long maxFq = 20000; // rpm (оборотов в минуту)
const unsigned long minInterval = 1000000UL / ( K * maxFq ); // минимальный интервал в мкс volatile unsigned long counter; // Количество отсчётов.
volatile unsigned long mks; // Время последнего отсчёта. unsigned long oldTime; // Время последнего отсчёта в предыдущем вычислении. // Функция для обработки прерывания.
void ISR() { // Здесь код прерывания static unsigned long oldTmr; // сохраняем старый таймер unsigned long tmr=microseconds(); if (tmr – oldTmr > minImterval) { mks=microseconds(); counter++; oldTmr=tmr; }
} void setup() { Serial.begin(115200); // Подключаем функцию ISR на прерывание по появлению сигнала на ноге fqPin. attachInterrupt(digitalPinToInterrupt(fqPin), ISR, RISING);
} void loop() { unsigned long rpm; // Получаем данные. noInterrupts(); unsigned long cnt = counter; counter = 0; unsigned long tmr = mks; interrupts(); // Выводим частоту в оборотах в секунду if (cnt > 0) { rpm = K * 1000000UL / ((tmr – oldTime) / cnt); oldTime = tmr; } else { rpm = 0; } Serial.println( rpm ); delay(250);
}
Другой вид помех — это пропадание отсчётов. Из-за той же инерции у вас не может измениться частота в два раза за одну миллисекунду. Понятно, что это зависит от того, что вы собственно измеряете. Частота биения крыльев комара может, вероятно и за миллисекунду упасть до нуля.
Статистическая обработка в данном случае становится уже достаточно сложной для маленькой функции обработки прерывания и я готов обсудить варианты в комментариях.
Особенности измерения скорости движения и скорости вращения
При измерении скорости вращения бензинового двигателя надо обязательно учесть величину К, которая совсем не очевидна. Например, вы намотали провод на кабель свечи и ожидаете, что там будет одна искра на один оборот. Это совсем не так.
Во-первых, у 4-тактного двигателя вспышка происходит один раз на два оборота, у 2-тактного один раз на оборот коленвала. Во-вторых, для упрощения системы зажигания коммутатор подаёт искру на неработающие в данный момент цилиндры, типа на выпуске.
Для получения правильного К надо почитать документацию на двигатель или подсмотреть показания эталонного тахометра.
При измерении скорости движения частота обновления дисплея не имеет большого значения, особенно, если вы рисуете цифры, а не двигаете стрелку. Даже обновление информации раз в секунду не вызовет отторжения. С оборотами двигателя всё наоборот, индикатор должен откликаться гораздо быстрее на изменение оборотов.
Типичная обида начинающего разработчика автомобильной и мотоциклетной электроники “стрелки дёргаются, цифры нечитабельны” лечится простым способом — надо обманывать клиента. Вы что думаете, автомобильный тахометр всегда показывает вам правду? Конечно же нет! Хотя вам этот обман нравится и вы хотите, чтобы ваш прибор дурил голову так же.
Стрелки
Если включить зажигание на новом модном автомобиле или мотоцикле, стрелки приборов сделают красивый вжух до максимума и медленнее опадут до нуля. Вот! Вот это нам и надо сделать. Надо, чтобы при показе максимальной величины стрелка не метнулась к ней мгновенно и не упала как акции лохотрона в ноль.
Итак, нам надо учитывать максимальную скорость стрелки на увеличение и максимальную на уменьшение показаний. Совсем хорошо сделать эти скорости нелинейными, чтобы стрелка сначала двигалась быстрее, а потом чуть помедленнее приближалась к заданному значению.
Вот пример с нелинейным выводом показаний:
dispRPM(unsigned int rpm) { static unsigned int lastRpm; if (rpm > lastRpm) { // Увеличивается unsigned int disp = rpm – (lastRpm-rpm)/5; // быстро вверх outputRPM(disp); // Поворот стрелки lastRpm=disp; } else { // Уменьшается unsigned int disp = rpm – (lastRpm-rpm)/2; // медленно вниз outputRPM(disp); // Поворот стрелки lastRpm=disp; }
}
Вы можете поиграть с коэффициентами. Этот же принцип используется при выводе громкости сигнала, например, у любого аналогового индикатора: стрелки, полоски, яркость, цвет, размер итп. Приведённый пример самый простой, но и не самый красивый. Предлагайте ваши варианты в комментариях.
Цифры
С цифрами всё намного сложнее. Быстрые изменения показаний приводят к тому, что несколько порядков сливаются в мутное пятно. Для скорости, как и писал выше, можно задать интервал раз в секунду и глаз успеет прочитать три цифры.
В мототехнике не зря делают аналоговые индикаторы оборотов, точные цифры не нужны, важна относительная близость к оборотам максимального крутящего момента, к максимальным вообще и холостые.
Я предлагаю менять частоту вывода информации на дисплей в зависимости от степени изменения величины. Если обороты меняются, скажем, на 5% от последнего подсчёта, а не показа — можно затупить и показывать раз в 300-500мс. Если на 20%, то показывать раз в 100мс.
Можно огрубить шкалу и показывать только две значащие цифры
С учётом мототематики, можно довольно точно показывать обороты холостого хода как описано чуть выше и огрублять вывод на оборотах от двух холостых. На высоких оборотах для гонщиков важнее делать блинкеры типа “передачу вниз”, “передачу вверх” и “ты спалишь движок”.
То есть держать двигатель около максимального крутящего момента и не дать ему крутиться выше максимальных разрешённых оборотов.
Блинкеры замечательно делаются с помощью SmartDelay когда можно унаследовать от этого класса свой с заданной ногой контроллера и частотой мигания, там есть методы для переопределения и они вызываются раз в заданное время.
Идеи по отображению цифр тоже приветствуются в комментариях.
Вывод
Если наступить на все грабли, можно стать опытным разработчиком.
Источник: https://habr.com/post/346126/
Код программы к уроку 12. arduino и электродвигатель
/* * * Набор для экспериментов ArduinoKit * Код программы для опыта №12: sketch 12 * * Крутись мотор * * Написано для сайта http://arduinokit.ru * * * Помощь сообщества Arduino. * Посетите сайт http://www.arduino.cc * * * * КРУТИСЬ МОТОР. ARDUINO И ЭЛЕКТРОДВИГАТЕЛЬ. * * Использование транзистора для управления скоростью мотора.
* Мы также покажем вам, как вводить данные через последовательный порт * (см функцию serialSpeed() ниже). * * Двигатели одна из многочисленных вещей из нашей повседневной жизни, * и Arduino может ими управлять. Мы будем использовать Широтно * Импульсную Модуляцию (PWM) для управления скоростью двигателя.
* * Порты Arduino способны выдержать работу нескольких светодиодов * (до 40 мА), но они не достаточно мощны, чтобы справиться с нагрузкой * от двигателя и других прожорливых потребителей энергии. Двигатель * идущий в наборе потребляет приблизительно от 50 до 100 mA, а это * значительно больше чем может дать Arduino.
Поэтому мы будем * использовать транзистор, который выполнит главную работу. * Транзистор будет выполнять роль «твердотельного выключателя», мы * «дадим» ему ток маленькой величины, а будет коммутировать, гораздо * больший ток. Транзистор 2N2222 может коммутировать ток до 200 мА.
* * Вы можете управлять транзистором с помощью функции digitalWrite() * («включать» и «выключать»), а с помощью функцию analogWrite() * изменять скорость вращения двигателя, для этого Arduino использует * Широтно Импульсную Модуляцию (PWM), подавая импульсы напряжения * изменяя их ширину от 0% до 100%.
* * Имейте в виду, для уменьшения скорости, вы уменьшаете ее с помощью * ШИМ (делая паузы «СТОП» длиннее). Если в начале, длительность паузы * будет 50% и более, двигатель, просто не сможет раскрутиться, * поэтому при старте необходимо немного добавить скорости. * * Подсоединяем оборудование: * * Транзистор: * * У транзистора имеются три вывода.
Если повернуть его скошенной * стороной (с надписями) к себе, а выводами вниз, то назначения * выводов будут следующими (слева на пр.): КОЛЛЕКТОР, БАЗА, ЭМИТЕР. * * Подсоедините минусовой вывод мотора к КОЛЛЕКТОРУ транзистора. * Подсоедините БАЗУ через резистор 330 Ом к цифровому порту 9. *Подсоедините ЭМИТЕР к GND (минусовой шине).
* * Мотор: * * Вы уже должны были подсоединить минусовой вывод мотора к *КОЛЛЕКТОРУ транзистора.
* * В данном опыте не имеет большого значения как подсоединять плюс * или минус двигателя, если их перепутать двигатель просто будет * крутиться в обратном направлении, это будет иметь значение если * двигатель установлен в машинке, и вместо того, чтобы ехать вперед, * она поедет назад. * * Оставшийся вывод мотора подсоедините к +5 Вольт.
* * Полупроводниковый диод: * * Полупроводниковый диод пропускает электрический ток только в * одном направлении и блокирует его прохождение в другом. * * Когда двигатель вращается, и резко отключается, магнитное поле * внутри него падает, в результате создается всплеск напряжения. * Это может привести к повреждению транзистора.
Чтобы этого не * случилось, мы и будем использовать диод, который не пропустит * этот всплеск через себя. * * На импортных диодах, почти всегда, КАТОД, отмечен полоской — * кольцом, расположенным, как раз у этого вывода. * * Подключите один вывод диода (КАТОД) к +5 Вольт, а другой * вывод (АНОД) к минусовому контакту на двигателе. * * В данном опыте не имеет большого значения плюс или минус * двигателя, если их перепутать двигатель просто будет крутиться в * обратном направлении, это будет иметь значение если двигатель * установлен в машинке, и вместо того, чтобы ехать вперед, она * поедет назад. * * * Комментарий к программе написан * 23 ноября 2014
* специально для http://arduinokit.ru
*
*/
// Будем управлять двигателем используя цифровой порт 9 (pin 9).
// Это должен быть любой ШИМ порт Arduino
const int motorPin = 9; void setup() {
// Установим порт мотора как выходной:
pinMode(motorPin, OUTPUT);
// Активируем «Монитор порта»:
Serial.begin(9600); } void loop() { // Здесь мы использовали комментарии для отключения некоторых // примеров. Чтобы испробовать другой пример, раскомментируйте // одну из следующих строк и закомментируйте другие. См функции,
// для того чтобы узнать что они делают и как работают.
// motorOnThenOff(); // motorOnThenOffWithSpeed(); // motorAcceleration(); serialSpeed();
}
// Попробуйте разные значения.
void motorOnThenOff() { int onTime = 3000; // миллисекунд для вращения мотора
int offTime = 3000; // миллисекунд для простаивания мотора
digitalWrite(motorPin, HIGH); // включить мотор — максимальная скорость delay(onTime); // задержка, для продолжения вращения digitalWrite(motorPin, LOW); // выключить мотор delay(offTime); // задержка, для простаивания мотора
}
// Функция «motorOnThenOffWithSpeed» переключает работу мотора между
// двумя скоростями. Пробуйте разные значения, если интересно.
void motorOnThenOffWithSpeed() { int Speed1 = 200; // скорость «Speed1» 0 (остановка), 255 (полный ход)
int Time1 = 3000; // время «Time1» в миллисекундах
int Speed2 = 50; // скорость «Speed2» 0 (остановка), 255 (полный ход)
int Time2 = 3000; // время «Time2» в миллисекундах
analogWrite(motorPin, Speed1); // включаем мотор на скорости «Speed1» delay(Time1); // продолжаем вращение заданное время analogWrite(motorPin, Speed2); // включаем мотор на скорость «Speed2» delay(Time2); // продолжаем, заданное время «Time2» } // Функция «motorAcceleration» раскручивает двигатель от нуля до
// максимума, и обратно до полной остановки.
void motorAcceleration() { int speed;
int delayTime = 20; // пауза в миллисекундах
// будем раскручивать мотор, увеличивая скорости от 0 до 255 с паузой в
// 20 миллисекунд меду каждым шагом (1, пауза, 2, пауза, 3, пауза и.т.д)
for(speed = 0; speed = 0; speed—) { analogWrite(motorPin,speed); // установка новой скорости delay(delayTime); // пауза «delayTime», т.е 20 миллисекунд } } // Следующая функция позволит вам изменять скорость прямо в окне // «Монитора порта».
Для этого откройте Монитор порта, используя // значок увеличительного стекла в Arduino IDE, в правом верхнем // углу окна.
Затем введите желаемую скорость в специальном месте // для ввода текста «Type a speed (0-255) into the box above,», в // верхней части окна, и нажмите кнопку «Send» (отправить) или // «return» (возврат). Двигатель будет работать на заданной вами
// скорости. Допустимый диапазон от 0 до 255.
void serialSpeed() {
int speed;
Serial.println(«Type a speed (0-255) into the box above,»); // Т.к. с русским языком в «мониторе порта» существуют некоторые // сложности, надписи будут на английском. Serial.println(«then click [send] or press [return]»);
Serial.println(); // Распечатать пустую строку
// In order to type out the above message only once, // we’ll run the rest of this function in an infinite loop: // Для того, чтобы вывести сообщение (выше) лишь один раз, // Мы будем запускать остальную часть этой функции в // бесконечном цикле: // Вывод запроса данных осуществляется лишь раз, после этого // Функция будет проверять правильность ввода данных по кругу, пока
// данные не изменятся.
while(true) {
// Сначала мы проверяем, доступны ли входные данные:
while (Serial.available() > 0) {
// Если данные есть, выполняем parseInt() для считывания цифр:
speed = Serial.parseInt();
// Поскольку analogWrite() работает с числами от 0 до 255, // мы обязательно должны быть уверенны, что число входит в // заданный диапазон. Для этого воспользуемся функцией «constrain».
// об этой функции мы говорили в опыте №6 «Arduino и Фоторезистор»:
speed = constrain(speed, 0, 255);
// Напечатать сообщение для того, чтобы вы знали что число
// было получено:
Serial.print(«Setting speed to «);
Serial.println(speed);
// И в конце зададим скорость двигателя
analogWrite(motorPin, speed); } }
}
Источник: http://arduinokit.ru/arduino/lessons-arduino/sketch-lesson-12-arduino-motor.html
Тахометр на базе Arduino
Тахометр представляет собой устройство, которое используется для измерения количества оборотов объекта в заданном интервале времени. Обычно значение выражается в оборотах в минуту или об/мин.
Ранее тахометры были чисто механическими устройствами, в которых вращение передавалось в тахометр через механическое соединение (трос или вал), количество оборотов в минуту определялось с помощью зубчатой передачи и отображалось на круговой шкале.
После прихода современной электроники тахометры очень сильно изменились. Данная статья описывает бесконтактный цифровой тахометр на базе Arduino. Скорость двигателя также может контролироваться с помощью аналогичной схемы.
Количество оборотов в минуту и другая информация отображается на жидкокристаллическом дисплее размером 16×2. Электрическая схема цифрового тахометра на базе Arduino показана ниже.
Электрическая схема
Датчик оборотов в минуту
Инфракрасный фототранзистор и инфракрасный светодиод образуют датчик. Инфракрасный фототранзистор – это тип фототранзистора, который реагирует только на инфракрасные волны. Использование инфракрасного фототранзистора позволяет избежать влияния других интерференций света из окружающей среды. Фототранзистор и инфракрасный светодиод расположены параллельно.
Резистор R2 ограничивает ток через инфракрасный диод. Отражательная направляющая лента приклеена на вращающийся объект (вал, диск или вентилятор) на одной линии с датчиком. Я использовал охлаждающий вентилятор с напряжением питания 9В/100мА. Зазор между датчиком и отражательной направляющей лентой должен не превышать 1см.
Когда отражательная направляющая лента проходит перед датчиком, инфракрасные волны отражаются назад к фототранзистору. Фототранзистор проводит больше в данный момент и в результате напряжение через R3(68K резистор) стремительно поднимается. Результатом будет сигнал, форма которого показана ниже на эмиттере фототранзистора.
Количество оборотов в минуту может быть определено путем вычисления количества восходящих импульсов в заданный интервал времени.
Вычисление количества оборотов в минуту
Arduino используется для вычисления величины оборотов в минуту и отображения этой величины на жидкокристаллическом дисплее. Эмиттер фототранзистора соединен с выводом Interrupt 0 (цифровой вывод 2) Arduino. Прерывание Arduino конфигурируется по инициируемому нарастающему фронту. В результате обрабатывается прерывание для каждого восходящего импульса в форме сигнала эмиттера. Количество полученных прерываний в заданное время вычисляется по приращению переменной, посредством программы обслуживания прерываний. Время, прошедшее в течение вычислительного цикла, определяется с помощью функции millis(). Функция millis() возвращает количество мили секунд, прошедших после включения платы Arduino. Вызов функции millis() до и после вычислительного цикла и вычисление их разницы дает время, прошедшее в течение вычислительного цикла. Величина (количество прерываний/раз в миллисекунду)*60000 определит количество оборотов в минуту (об/мин).
Контроль скорости двигателя
Устройство для контроля скорости двигателя с помощью потенциометра также включено в схему. Транзистор Q1 используется для управления двигателем. Его база подсоединена к ШИМ выводу 9 Arduino через токоограничивающий резистор R1. Движок потенциометра контроля скорости R4 подсоединен к аналоговому выводу A0 Arduino.
Напряжение на этом выводе преобразуется в значение между 0 и 1023 посредством функции anlogRead. Затем это значение делится на четыре, чтобы попасть в диапазон от 0 до 255. После этого данное значение записывается в ШИМ вывод 9 с помощью функции anlogWrite.
В результате на выводе 9 будет прямоугольная волна, чей коэффициент заполнения пропорционален величине, записанной с помощью функции analogWrite. Например, если величина равна 255, коэффициент заполнения будет 100%, а если величина равна 127, коэффициент заполнения будет около 50%.
D1 – это обратный диод, а C1 – это шумоподавляющий конденсатор (декаплер). Количество оборотов в минуту и коэффициент заполнения отображаются на экране жидкокристаллического дисплея с помощью стандартной библиотеки LiquidCrystal. Прочтите вот эту статью: Интерфейсный жидкокристаллический дисплей для Arduino.
Полный программный код для цифрового тахометра на базе Arduino показан ниже.
Программный код
#include LiquidCrystal lcd(12,11,6,5,4,3); int pwm=9; int pot=A0; float value=0; int percent; float rev=0; int rpm; int oldtime=0; int time; void isr() //interrupt service routine { rev++; } void setup() { lcd.begin(16,2); //initialize LCD attachInterrupt(0,isr,RISING); //attaching the interrupt } void loop() { delay(1000); detachInterrupt(0); //detaches the interrupt time=millis()-oldtime; //finds the time rpm=(rev/time)*60000; //calculates rpm oldtime=millis(); //saves the current time rev=0; value=analogRead(pot); //reads the speed control POT value=value/4; analogWrite(pwm,value); //sets the desired speed percent=(value/255)*100; //finds the duty cycle % lcd.clear(); lcd.setCursor(0,0); lcd.print(“___TACHOMETER___”); lcd.setCursor(0,1); lcd.print(rpm); lcd.print(” RPM”); lcd.print(” “); lcd.print(percent); lcd.print(“%”); attachInterrupt(0,isr,RISING); }
Примечания • На плату Arduino можно подать напряжение питания 9В через внешнее гнездо питания. • Напряжение 5В, необходимое для некоторых компонентов схемы, может быть подано от 5В источника на плате Arduino. • Используемый вентилятор использует напряжение 9В/100мА. Транзистор 2N2222 может выдержать ток только до 800мА. Помните об этом при выборе нагрузки. • Используемый жидкокристаллический дисплей — JHD162A. • Потенциометр R5 может использоваться для регулировки контрастности жидкокристаллического дисплея. При его подсоединении на дисплее не будет ничего отображаться. Выполните регулировку R5, пока на дисплее не появится изображение. Оптимальное напряжение на движке потенциометра R5 находится в пределах от 0.4 до 1В. • Инфракрасный фототранзистор и инфракрасный диод были вынуты из фото прерывающего модуля LTH-1550. • Боковую поверхность фототранзистора необходимо закрыть с помощью изоленты. • Положение датчика показано на рисунке ниже.Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.
Источник: http://electronics-lab.ru/blog/4012.html
Arduino и PWM. Широтно-импульсная модуляция (ШИМ)
Давайте вспомним предыдущую статью о том, как сделать гирлянду на Arduino и попробуем выполнить новую задачу. Думаю, что все видели новогодние витринные гирлянды, в которых плавно мигают светодиоды. Допустим, что мы хотим сделать нечто подобное.
Мы уже рассматривали функцию digitalWrite() и знаем, что значение, которое она записывает, может быть двух вариантов – высокий или низкий уровень. В данном случае нам поможет функция analogWrite(). “Формулировки” функций различаются только начальными приставками, поэтому их легко запомнить.
Функция analogWrite(), так же как и digitalWrite(), содержит в скобках два аргумента и работает по тому же словесному принципу: “куда, что”. Главным различием является возможность записи широкого диапазона значений вместо привычного LOW или HIGH. Это и позволит нам регулировать яркость светодиода.
Главное замечание, которое необходимо учитывать, это то, что данная функция работает только на определенных контактах. Эти контакты обозначены символом “~”. Этот символ означает, что это PWM-контакт. PWM (pulse-width modulation) звучит по-русски как ШИМ (широтно-импульсная модуляция).
Принцип работы основан на изменении длительности импульса. Графически это можно изобразить так:
Давайте попробуем разобраться как это работает, рассмотрев простой пример. Для этого необходимо подключить светодиод к PWM-контакту через резистор номиналом 150 Ом и “зашить” в Arduino простенькую программу. Схема подключения и код скетча представлены ниже:
Думаю, что в целом код понятен, но необходимо уделить немного внимания циклу for(). Существует такое понятие как разрешение. Поскольку мы работаем с 8-битным разрешением (это будет рассмотрено несколько позднее), то минимальному значению будет соответствовать 0, а максимальному – 255. В конце каждой итерации мы установили временную задержку в 10мс.
Давайте вернемся к схеме из предыдущего урока и попробуем сделать аналогичную гирлянду с использованием функции analogWrite().
Визуально скетч стал несколько сложнее. На самом деле здесь все просто и давайте в этом разберемся. Нам необходимо идентифицировать все подключенные светодиоды, но вместо привычного int led мы используем массив, каждый элемент которого является PWM-контактом на Arduino. В теле функции void setup() мы тоже поступили хитрым образом. “Перечислять” все контакты мы доверили циклу for(), с каждой итерацией которого производится конфигурация соответствующего контакта на OUTPUT. Переходим к функции void loop(). Функция debounce() и начальное условие if() остается без изменений. У нас по-прежнему идет проверка уровней двух переменных: предыдущее значение (изначально LOW) и текущее состояние кнопки. При выполнении этих условий значение переменной enable инвертируется. Учитывая это, мы добавили еще два простых условия if(). Если enable = true, то гирлянда включается, плавностью “перетекания” которой управляет цикл for(). Если же enable = false, то все светодиоды выключены. По окончанию условий переменная lastButton принимает текущее состояние кнопки. Тестируя нашу программу, мы заметили, что все работает не должным образом. Помните, в прошлом уроке мы сделали поправку, что при большом значении временной задержки кнопка срабатывает по её истечению? В прошлом примере, при включенной гирлянде, суммарная задержка в теле функции void loop() составляла 85мс. Это давало нам возможность успеть “попасть” в определенной отрезок времени. В данном скетче, при том же условии, задержка отличается в несколько раз. Возможно, при желании выключить гирлянду напрашивается слово “прервать”. Это и будет являться решением данной задачи!
Надеюсь, что эта статья была для Вас полезной. В следующем уроке мы рассмотрим прерывания в Arduino и добьемся должного результата.
Источник: http://arduinokit.blogspot.com/2013/05/arduino-pwm.html
Урок 1 -Подключает servo-привод к arduino. Сервопривод + кнопка
Сервопривод – это привод, вал которого может встать в заданное положение или поддерживать заданную скорость вращения. Другими словами, валом сервопривода можно управлять, например, задавая ему положение в градусах или определенную частоту вращения.
Сервоприводы используются в самых разных областях, например, в робототехнике они помогают моделировать различные движения роботов. Сервоприводы – эффективное решение для перемещения механизмов в пространстве.
В этом уроке мы научимся управлять сервоприводом.
Для урока нам понадобиться:
Подключение к Arduino
Для достижения самых разных целей робототехники к программируемому контроллеру Arduino может быть подключен сервопривод. Подключение осуществляется через кабели, которые выходят из сервопривода. Обычно это три кабеля: красный; коричневый или черный; желтый, оранжевый или белый.
Подключение сервопривода к плате Arduino производится через ШИМ-выводы. Что Такое PWM (ШИМ) мы уже рассматривали в уроке: Плавное включение светодиода на Arduino с помощью ШИМ (PWM)
За основу возьмем урок Подключение кнопки и светодиода плате Arduino к схеме добавим сервопривод и вот что у нас должно получиться.
Изменим код:
#include // подключаем библиотеку для работы с сервоприводом Servo servo; // объявляем переменную servo типа “servo” int led_pin=3; // пин подключения int button_pin = 4; // пин кнопки // переменные int buttonState = 0; // переменная для хранения состояния кнопки void setup() { pinMode(led_pin, OUTPUT); // Инициализируем цифровой вход/выход в режиме выхода. pinMode(button_pin, INPUT); // Инициализируем цифровой вход/выход в режиме входа. servo.attach(5); // привязываем сервопривод к аналоговому выходу 10 } void loop() { buttonState = digitalRead(button_pin);// считываем значения с входа кнопки if (buttonState == HIGH) { digitalWrite(led_pin, HIGH);// зажигаем светодиод servo.write(0); //ставим вал на 180 delay (1000); // задержка в 1 секунду } else { digitalWrite(led_pin, LOW);// выключаем светодиод servo.write(180); //ставим вал на 0 delay (1000); // задержка в 1 секунду } } #include // подключаем библиотеку для работы с сервоприводом
Мы еще не работали с библиотеками. Библиотека это класс, содержащий функции которые мы можем использовать в нашей программе. Библиотека позволяет сократить объем написанного кода и скорость разработки приложения.
Ка вы поняли строка выше подключает нашу библиотеку Servo.h, после чего мы можем использовать все функции данной библиотеки.
Servo servo; // объявляем переменную servo типа “servo”
Объявлением переменную, она нам понадобиться для работы с библиотекой.
servo.attach(5); // привязываем сервопривод к аналоговому выходу 5
Функция библиотеки Servo.
servo.write(180); //ставим вал на 180
С помощью данной функции мы можем повернуть сервопривод на заданный угол.
Следующий урок: IR Пульт. Включение выключение светодиода.
Если у вас чего то нет для выполнения данного урока, Вы можете посмотреть в каталоге. Там собранные комплектующими от проверенных продавцов по самым низким ценам.
Источник: https://portal-pk.ru/news/53-urok-1–podklyuchaet-servo-privod-k-arduino-servoprivod-%2B.html
Как контролировать скорость серводвигателя с помощью arduino Mega
Если все они имеют одинаковую степень, попробуйте этот код ниже.
На самом верху (не между любыми “{}” s) :
#include Servo S1;
Servo S2;
Servo S3;
Servo S4;
Servo S5;
Servo S6;
Servo S7;
Servo S8;
Servo S9;
Servo S10;
Servo S11;
Servo S12;
Поместите это в Setup :
S1.attach(1);
S2.attach(2);
S3.attach(3);
S4.attach(4);
S5.attach(5);
S6.attach(6);
S7.attach(7);
S8.attach(8);
S9.attach(9);
S10.attach(10);
S11.attach(11);
S12.attach(12);
Вам нужно изменить номера контактов.
Просто поставьте это где угодно (не между любыми “{}” s) :
void TurnServos(int toDegree){ servosAt = S1.read; if(servosAt == toDegree){ } if(servosAt > toDegree){ while(S1.read > toDegree){ int currentToDegree = S1.read – 1; S1.write(currentToDegree); S2.write(currentToDegree); S3.write(currentToDegree); S4.write(currentToDegree); S5.write(currentToDegree); S6.write(currentToDegree); S7.write(currentToDegree); S8.write(currentToDegree); S9.write(currentToDegree); S10.write(currentToDegree); S11.write(currentToDegree); S12.write(currentToDegree); delay(10); //Adjust this to make it faster or slower. } } if(servosAt < toDegree){ while(S1.read < toDegree){ int currentToDegree = S1.read + 1; S1.write(currentToDegree); S2.write(currentToDegree); S3.write(currentToDegree); S4.write(currentToDegree); S5.write(currentToDegree); S6.write(currentToDegree); S7.write(currentToDegree); S8.write(currentToDegree); S9.write(currentToDegree); S10.write(currentToDegree); S11.write(currentToDegree); S12.write(currentToDegree); delay(10); //Adjust this to make it faster or slower. } } } void ClearServos(){ int startDegree = 90; //Change this number to anything you want. S1.write(startDegree); S2.write(startDegree); S3.write(startDegree); S4.write(startDegree); S5.write(startDegree); S6.write(startDegree); S7.write(startDegree); S8.write(startDegree); S9.write(startDegree); S10.write(startDegree); S11.write(startDegree); S12.write(startDegree); }
Как использовать это: в setup перед тем, как делать что-либо с сервомоторами, но после того, как я сказал вам установить настройки, используйте ClearServos(); для подготовки сервоприводов, которые будут использоваться.
(Это, вероятно, не обязательно, но я не знаю, что произойдет, когда вы используете S1.read без его изменения, и если сервоприводы находятся на разных позициях, это устранит проблемы. Его можно избежать, если это не вызовет проблем, но я думаю, вы должны использовать его, если сможете.) Все они повернутся на 90 градусов.
(90 градусов можно изменить с помощью переменной startDegree в void ClearServos.)
Чтобы включить их, используйте TurnServos(90); , 90 – это степень, к которой вы хотите обратиться.
Не проверял это, потому что у меня нет Mega или 12 сервомашин. Прошу прокомментировать, если вы заметили какие-либо ошибки, так как это огромно. Я потратил много времени на это, поэтому надеюсь, что помог. 🙂
Источник: http://qaru.site/questions/6410328/how-to-control-speed-of-a-servo-motor-using-arduino-mega
Спидометр для велосипеда на Arduino
Хотите отследить скорость на велосипедной прогулке? Тогда эта инструкция для вас!
В проекте используется магнитный выключатель (геркон) для измерения скорости вращения колеса велосипеда. Arduino, в свою очередь, рассчитывает скорость перемещения в милях/час и передает эту информацию на LCD дисплей. Установить данную систему вы можете на любой велосипед/колесо. Для этого достаточно указать радиус колеса для правильного расчета.
Необходимые элементы
- 1 плата Arduino
- 1 геркон
- 1 резистор на 10 кОм, 1/4 ватта
- 1 Батарея на 9 вольт
- 1 Провод
- 1 Макетная плата для распайки
- 1 LCD дисплей
- 2 Переключателя
- Дополнительные материалы:
- Фанера, винты и т.п.
- Программа для Arduino Arduino IDE
Электросхема проекта приведена ниже.
Она состоит из трех переключателей:
1. Один подключен к питанию 9 вольт
2. Второй переключатель – к LCD экрану для его включения/выключения
3. Магнитный выключателя (геркон), который замыкает цепь каждый раз, когда колесо совершает полный оборот.
LCD монитор Parallax, который используется в проекте, подключается к Arduino по трем пинам. Один идет к 5 В, один к земле, третий – к серийному выходу (TX) на плате Arduino на цифровом пине 1.
Резисторы на 10 кОм подключены к переключателям и подсветке монитора, чтобы избежать превышения допустимой силы тока между 5 В и землей (ни в коем случае не подключайте 5 В и землю напрямую к Arduino).
Распайка шилда спидометра
Установите три ряда коннекторов на макетной плате таким образом, чтобы они сели на плату, как это показано ниже.
Геркон
Геркон состоит из двух частей, выключателя и магнита. С самого выключателя (собственно, там и расположен геркон), выходит два провода. В момент, когда магнит располагается неподалеку, небольшой механический элемента внутри геркона перемещается и замыкает цепь.
Установите токоограничивающий резистор на 10 кОм между пином A0 и землей на вашей макетной плате. Концы провода подключите к пину A0 и 5V. Этот провод вы протянете в дальнейшем вдоль всего велосипеда к переключателям.
Установка геркона на велосипед
Для установки геркона и магнита на колесо велосипеда, используйте изоленту. На рисунке сверху показано, что магнит устанавливается на одну их спиц, а геркон – на раму велосипеда.
Таким образом, магнит проходит мимо геркона после каждого полного оборота колеса.
Подключите провода от геркона к кабелям с распаянной вами платы (как именно подключать – неважно, так как это просто переключатель).
Для проверки работоспособности вашего переключателя, используйте код, приведенный ниже. В момент, когда магнит проходит мимо геркона, Arduino должна выдать ~ 1023, в ином случае будет отображаться 0.
Откройте серийный монитор (Tools – Serial Monitor) в оболочке Arduino IDE и запустите проверку. Если магнит не генерирует сигнал на герконе, измените его положение или используете более сильный магнит.
//arduino спидометр для велосипеда
#define reed A0//пин, который подключен к геркону
//переменная для хранения данных
int reedVal;
void setup(){
Serial.begin(9600);
}
void loop(){
reedVal = analogRead(reed);//получаем значение с A0
Serial.println(reedVal);
delay(10);
}
Проверка работоспособности
Загрузите код, приведенный ниже на плату Arduino. Активируйте серийный монитор. У вас должно отбражаться число 0.00. Начните крутить колесо велосипеда. Каждую секунду долгы отображаться данные текущей скорости в милях/час.
// расчеты
// радиус колеса ~ 13.5 дюймов
// расстояние = pi*2*r =~85 дюймов
// максимальная скорость 35 миль/час =~ 616 дюймов/сек
// максимальная угловая скорость =~7.25
#define reed A0// пин, который подключен к геркону
//переменные
int reedVal;
long timer;// время между одним полным оборотом (в мс)
float mph;
float radius = 13.5;// радиус колеса (в дюймах)
float circumference;
int maxReedCounter = 100;// минимальное время (в мс) одного оборота
int reedCounter;
void setup(){
reedCounter = maxReedCounter;
circumference = 2*3.14*radius;
pinMode(reed, INPUT);
// НАСТРОЙКА ТАЙМЕРА – таймер позволяет точно отслеживать время между сигналами геркона
cli();// остановка прерываний
// устанавливаем прерывания timer1 с частотой 1кГц
TCCR1A = 0;// устанавливаем внутренний TCCR1A регистр на 0
TCCR1B = 0;// то же самое для TCCR1B
TCNT1 = 0;
// устанавливаем инкремент счетчика времени на 1 кГц
OCR1A = 1999;// = (1/1000) / ((1/(16*10^6))*8) – 1
// активируем режим CTC
TCCR1B |= (1 2000){
mph = 0;// если новые с геркона не поступают новые импульсы, значит колесо не вращется, значит скорость равна 0 м/час
}
else{
timer += 1;// инкремент таймера
}
}
void displayMPH(){
Serial.println(mph);
}
void loop(){
// отображаем мили в час раз в секунду
displayMPH();
delay(1000);
}
LCD дисплей
Для установки дисплея вам понадобится дополнительный шилд. Припаяйте рельсу с контактами мама на выходе на protoshield. Три контакта будут использлваться для для подключения жидкокристаллического дисплея. LCD экран должен плотно установиться на рельсах.
Установка LCD
Подключите Arduino 5V, Ground, и TX (Arduino цифровой пин 1) к LCD сокету. Не забудьте проверить правильность установки экрана на основании меток на плате дисплея.
На задней части экрана Parallax LCD есть два переключателя и потенциометр. Потенциометр используется для ручной регулировки контраста дисплея. Переключатели надо установить в положения, которые приведены на фото ниже.
Проверка LCD для спидометра
Проверьте код, который приведен ниже. Лично у меня при первом запуске на экране появились совершенно невразумительные, хаотичные символы. Пришлось снять монитор, перезалить скетч и установить экран заново. Со второго раза все заработало. Возможно, проблема была в некорректной прошивке Arduino.
На LCD экране должна отобразиться надпись “Hello World”.
//Проверка Parallax 2×16 lcd
//Результат выполнения данного скетча – надпись “Hello World” на вашем LCD экране. Свитч подсветки должен быть подключен к цифровому пину 2
//Serial.write(13);// новая строка
void setup() {
Serial.begin(9600);
pinMode(1,OUTPUT);// tx
Serial.write(12);// очищаем
Serial.write(“Hello World”);
}
void loop() {
}
Тумблер подсветки спидометра
Тумблер подсветки
Подключите тумблер как это показано на рисунке ниже. Не забудьте соединить резистор на 10 кОм с черным и зеленым проводами. Потом эти провода подключаются к одному из контактов переключателя. Ко второму контакту подключаем красный провод.
Красный провод подключаем к Arduino 5V, вторую сторону резистора к земле, зеленый провод – к D2.
Окончательная программа для спидометра
Загрузите приведенный код на Arduino. Проверьте работу переключателя подсветки и насколько корректно отображается скорость.
Уточните радиус вашего коле в дюймах и вставьте это значение в строку: float radius = ''''';
В этой части кода я использовал прерывания, чтобы переменная “timer” увеличивала свое значение с частотой 1 кГц.
//Спидометр для велосипеда с использованием геркона
//скорость велосипеда отображается на LCD экране
//расчеты
//радиус колеса ~ 13.5 дюймов
//расстояние = pi*2*r =~85 дюймов
//максимальная скорость 35 миль/час =~ 616 дюймов/секунду
//максимальная угловая скорость =~7.25
#define reed A0// пин, к которому подключен геркон
// переменные
float radius = 13.5;// радиус колеса (в дюймах)- измените это для своем велосипеде
int reedVal;
long timer = 0;// время одного полного оборота (в милисекундах)
float mph = 0.00;
float circumference;
boolean backlight;
int maxReedCounter = 100;// минимальное время (в милисекундах) одного оборота
int reedCounter;
void setup(){
reedCounter = maxReedCounter;
circumference = 2*3.14*radius;
pinMode(1,OUTPUT);// tx
pinMode(2,OUTPUT);// свич подсветки
pinMode(reed, INPUT);
checkBacklight();
Serial.write(12);// очищение
cli();// остановка прерываний
// устанавливаем прерывание timer1 на частоте 1 кГц
TCCR1A = 0;// устанавливаем внутренний регистр TCCR1A в 0
TCCR1B = 0;// то же самое для TCCR1B
TCNT1 = 0;
// устанавливаем инкремент для счетчика 1 кГц
OCR1A = 1999;// = (1/1000) / ((1/(16*10^6))*8) – 1
// активируем режим CTC
TCCR1B |= (1 2000){
mph = 0;// если не поступают импульсы от геркона, значит скорость равна 0
}
else{
timer += 1;// инкремент таймера
}
}
void displayMPH(){
Serial.write(12);// очищаем
Serial.write(“Speed =”);
Serial.write(13);// начинаем новую строку
Serial.print(mph);
Serial.write(” MPH “);
//Serial.write(“0.00 MPH “);
}
void loop(){
// отображаем mph раз в секунду
displayMPH();
delay(1000);
checkBacklight();
}
Питание
Подключите последовательно коннектор для батареи и переключать как это показано на первом рисунке ниже. Красный провод от переключателя подключите к контакту Vin на Arduino, а черный контакт от коннектора для батареи – к земле на Arduino.
Корпус для спидометра на Arduino
Бокс для спидометра был вырезан из фанеры толщиной 1/4″. Использовалась лазерная резка мощностью 120 Ватт. Размеры бокса – 3.5″x4″x2″. Бокс был спроектирован в AutoCAD.
Для генерации файлов для лазерной резки использовался софт Autodesk 123D Make. Потом были добавлены два отверстия для переключателей и прямоугольное отверстие для LCD экрана.
Кроме того, были добавлены отверстия на нижней части бокса, чтобы проще осуществить крепеж к велосипеду.
Стенки бокса крепятся между собой на клей. Углы надо зачистить наждачкой. Можно использовать какое-то покрытие для фанеры, чтобы придать боксу надлежащий вид и защитить от влаги.
Скачать необходимые детали для бокса можно по ссылкам ниже:
enclosure.stl
enclosure.dwg
enclosure.cdr
Установка Arduino и обвязки в бокс
Переключатели фиксируются в корпусе с помощью гаек. LCD экран садится на клей или с фиксируется с помощью винтов на передней панели бокса. Arduino и Protoboard устанавливаются рядом с бетарейкой. Опять-таки, можно использовать клей для фиксации или предусмотреть крепеж на винтах.
Устанавливаем спидометр на велосипед
Бокс со спидометром на Arduino устанавливаем на руль велосипеда. Можно использовать пластиковые стяжки и sugru для фиксации. Провода, которые идут от платы к геркону надо пустить таким образом, чтобы они не мешали вам при поездке и при этом была возможность поворачивать руль.
Велосипед со спидометром на дороге!
Не забывайте про правила поведения велосипедистов на дороге! Несмотря на ваш прекрасный Arduino спидометр, следите за транспортом и людьми!
Оставляйте Ваши комментарии, вопросы и делитесь личным опытом ниже. В дискуссии часто рождаются новые идеи и проекты!
Источник: http://arduino-diy.com/arduino-spidometr-dlya-velosipeda