Измерение скорости движущегося транспортного средства всегда было интересной задачей для любителей электроники. Сейчас, в эпоху почти тотального перехода на цифровую технику, наиболее просто сделать цифровой спидометр и подобный спидометр для велосипеда на основе платы Arduino мы уже рассматривали на нашем сайте. Но для многих людей визуально более удобен аналоговый спидометр, поэтому в данной статье мы рассмотрим создание аналогового спидометра на основе платы Arduino и инфракрасного датчика. В данном проекте инфракрасный датчик будет использоваться для измерения скорости. Во многих других проектах для измерения скорости используется датчик Холла, но в этом проекте мы применим инфракрасный датчик – его достаточно легко купить и его можно использовать практически в любом типе транспортного средства.
В рассматриваемом проекте мы будем показывать скорость как в аналоговой, так и в цифровой форме. Также в данной статье мы можем улучшить свои познания в области шаговых двигателей и использования прерываний и таймеров в Arduino. В результате реализации данного проекта мы сможем измерять скорость любого вращающегося объекта, отображать ее в цифровой форме на экране ЖК дисплея 16x2 и в аналоговой форме на соответствующем указателе.
Необходимые компоненты
- Плата Arduino Uno (купить на AliExpress).
- Биполярный (двухполюсный) шаговый двигатель (4 провода) (bipolar stepper motor).
- Драйвер шагового двигателя L298n (Stepper motor driver) (купить на AliExpress).
- Модуль инфракрасного датчика (IR sensor module) (купить на AliExpress).
- ЖК дисплей 16х2 (16*2 LCD display) (купить на AliExpress).
- Резистор 2,2 кОм (купить на AliExpress).
- Соединительные провода.
- Макетная плата.
- Источник питания.
- Напечатанная на принтере картинка спидометра.
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Расчет скорости и ее отображение на аналоговом спидометре
Инфракрасный (ИК) датчик представляет собой устройство которое может обнаруживать присутствие объекта перед собой. Для тестирования работы проекта мы использовали двухлопастной вентилятор, который поместили перед инфракрасным датчиком, поэтому всегда когда лопасть вентилятора будет проходить над датчиком ИК датчик будет обнаруживать это. Для расчета времени одного оборота вентилятора мы задействуем таймеры и прерывания платы Arduino. В определенной степени данная часть проекта похожа на тахометр на основе платы Arduino, ранее рассматривавшийся на нашем сайте.
В этом проекте мы будем использовать прерывание самого высокого приоритета для определения числа оборотов вентилятора в минуту (rpm - revolutions per minute). Мы будем применять это прерывание в нарастающем режиме. То есть всегда когда выход датчика будет изменять свое состояние с LOW на High будет вызываться на выполнение функция RPMCount(). А поскольку в проекте мы использовали двухлопастной вентилятор это значит что данная функция будет вызываться 4 раза за один оборот.
Когда мы определим время одного оборота мы можем рассчитать по ниже приведенной формуле число оборотов в минуту (RPM). В этой формуле 1000/time позволит определить нам число оборотов в секунду (RPS - revolution per second), а умножив полученное значение на 60 мы получим число оборотов в минуту.
1 |
rpm = (60/2)*(1000/(millis() - time))*REV/bladesInFan; |
После расчета числа оборотов в минуту (RPM) скорость можно определить по следующей формуле:
1 |
Speed = rpm * (2 * Pi * radius) / 1000 |
Поскольку число пи нам известно (Pi = 3.14), а радиус в нашем случае составляет величину 4.7 дюйма, то сначала конвертируем радиус из дюймов в метры:
1 2 |
radius = ((radius * 2.54)/100.0) meters Speed= rpm * 60.0 * (2.0 * 3.14 * radius)/ 1000.0) // в километрах в час |
В представленной формуле мы умножаем rpm на 60 чтобы конвертировать rpm в rph (revolution per hour – число оборотов в час) и делим на 1000 чтобы преобразовать м/ч (метров в час) в км/ч.
После получения скорости в км/ч мы можем непосредственно показать ее на экране ЖК дисплея в цифровой форме, однако чтобы показать ее в аналоговой форме нам необходимо произвести дополнительные преобразования, в частности, мы должны определить число шагов, которое должен сделать наш шаговый двигатель.
В нашем проекте мы используем 4-проводный биполярный шаговый двигатель, который совершает 200 шагов за один оборот, то есть за один шаг он поворачивается на 1.8 градуса.
К примеру, нам необходимо показать скорость 280 км/ч на спидометре – для этого шаговый двигатель должен повернуться на 280 градусов. То есть максимальная скорость у нас будет равна maxSpeed = 280, а максимальное число шагов (maxSteps) будет равно:
1 |
maxSteps = 280/1.8 = 155 steps |
Для преобразования скорости в число шагов мы будем использовать функцию Arduino под названием map:
1 |
Steps = map(speed,0,maxSpeed,0,maxSteps); |
Итого, получим:
1 |
steps=map(speed,0,280,0,155); |
После расчета необходимого числа шагов (steps) мы можем непосредственно их использовать в функции управления шаговым двигателем. Но перед этим нам необходимо учесть текущее число шагов (текущий угол), на которое повернут шаговый двигатель. Для этого мы будем использовать следующие преобразования:
1 2 3 |
currSteps=Steps steps= currSteps-preSteps preSteps=currSteps |
где currSteps – текущее число шагов, полученное в результате предыдущего вычисления скорости, а preSteps – последнее выполненное число шагов.
Работа схемы
Схема аналогового спидометра на основе платы Arduino представлена на следующем рисунке.
В схеме мы будем использовать ЖК дисплей 16x2 для отображения скорости в цифровой форме и шаговый мотор, с помощью вращения которого будет показываться скорость в аналоговой форме.
ЖК дисплей подключен к следующим контактам платы Arduino:
RS - A5
RW - GND
EN - A4
D4 - A3
D5 - A2
D6 - A1
D7 - A0
Резистор 2,2 кОм используется для установки яркости ЖК дисплея. Модуль инфракрасного датчика (IR sensor module), который используется для определения числа оборотов лопастей вентилятора, подключен к контакту D2 платы Arduino, который в данном случае используется как вход внешнего прерывания 0 (interrupt 0).
В качестве драйвера мотора мы использовали модуль L293N. Контакты IN1, IN2, IN3 и IN4 драйвера шагового двигателя непосредственно подключены к контактам D8, D9, D10 и D11 платы Arduino.
Объяснение программы для Arduino
Полный код программы приведен в конце статьи, здесь же мы рассмотрим его основные фрагменты.
В программе первым делом мы должны подключить все используемые библиотеки – для работы с шаговым двигателем и для работы с ЖК дисплеем, а также инициализировать контакты Arduino, к которым эти устройства подключены.
1 2 3 4 5 |
#include<LiquidCrystal.h> LiquidCrystal lcd(A5,A4,A3,A2,A1,A0); #include <Stepper.h> const int stepsPerRevolution = 200; // число шагов за один оборот, измените это число для используемого вами шагового двигателя Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11); |
После этого нам необходимо объявить в программе используемые переменные.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
volatile byte REV; unsigned long int rpm,RPM; unsigned long st=0; unsigned long time; int ledPin = 13; int led = 0,RPMlen , prevRPM; int flag = 0; int flag1=1; #define bladesInFan 2 float radius=4.7; // inch int preSteps=0; float stepAngle= 360.0/(float)stepsPerRevolution; float minSpeed=0; float maxSpeed=280.0; float minSteps=0; float maxSteps=maxSpeed/stepAngle; |
После этого в функции setup мы инициализируем ЖК дисплей, последовательный порт, прерывание и шаговый двигатель.
1 2 3 4 5 6 7 8 9 10 |
void setup() { myStepper.setSpeed(60); Serial.begin(9600); pinMode(ledPin, OUTPUT); lcd.begin(16,2); lcd.print("Speedometer"); delay(2000); attachInterrupt(0, RPMCount, RISING); } |
После этого в функции loop мы будем считывать значение rpm (число оборотов в минуту) и производить необходимые вычисления для расчета скорости и преобразования значения скорости в необходимое число шагов для шагового двигателя чтобы отображать скорость в аналоговой форме.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
void loop() { readRPM(); radius=((radius * 2.54)/100.0); // преобразуем в метры int Speed= ((float)RPM * 60.0 * (2.0 * 3.14 * radius)/1000.0); // RPM in 60 minute, diameter of tyre (2pi r) r is radius, 1000 to convert in km int Steps=map(Speed, minSpeed,maxSpeed,minSteps,maxSteps); if(flag1) { Serial.print(Speed); Serial.println("Kmh"); lcd.setCursor(0,0); lcd.print("RPM: "); lcd.print(RPM); lcd.print(" "); lcd.setCursor(0,1); lcd.print("Speed: "); lcd.print(Speed); lcd.print(" Km/h "); flag1=0; } int currSteps=Steps; int steps= currSteps-preSteps; preSteps=currSteps; myStepper.step(steps); } |
Также в программе мы должны запрограммировать функцию readRPM() для расчета числа оборотов в минуту.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
int readRPM() { if(REV >= 10 or millis()>=st+1000) // данные будут обновляться каждые 10 считываний или через 1 секунду в неиспользуемом состоянии { if(flag==0) flag=1; rpm = (60/2)*(1000/(millis() - time))*REV/bladesInFan; time = millis(); REV = 0; int x= rpm; while(x!=0) { x = x/10; RPMlen++; } Serial.println(rpm,DEC); RPM=rpm; delay(500); st=millis(); flag1=1; } } |
И, наконец, нам будет необходима программа обработки прерываний, которая будет измерять количество оборотов объекта (в нашем случае лопастей вентилятора).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void RPMCount() { REV++; if (led == LOW) { led = HIGH; } else { led = LOW; } digitalWrite(ledPin, led); } |
Для дальнейшего усовершенствования проекта можно применить датчик Холла и выводить измеряемую скорость на приложение в смартфоне как это сделано в проекте спидометра для велосипеда.
Исходный код программы (скетча)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
#include<LiquidCrystal.h> LiquidCrystal lcd(A5,A4,A3,A2,A1,A0); #include <Stepper.h> const int stepsPerRevolution = 200; // число шагов на один оборот шагового двигателя, измените это число для своего двигателя Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11); volatile byte REV; unsigned long int rpm,RPM; unsigned long st=0; unsigned long time; int ledPin = 13; int led = 0,RPMlen , prevRPM; int flag = 0; int flag1=1; #define bladesInFan 2 float radius=4.7; // в дюймах int preSteps=0; float stepAngle= 360.0/(float)stepsPerRevolution; float minSpeed=0; float maxSpeed=280.0; float minSteps=0; float maxSteps=maxSpeed/stepAngle; void setup() { myStepper.setSpeed(60); Serial.begin(9600); pinMode(ledPin, OUTPUT); lcd.begin(16,2); lcd.print("Speedometer"); delay(2000); attachInterrupt(0, RPMCount, RISING); } void loop() { readRPM(); radius=((radius * 2.54)/100.0); // преобразуем в метры int Speed= ((float)RPM * 60.0 * (2.0 * 3.14 * radius)/1000.0); // RPM умножаем на 60 чтобы перевести минуты в часы, диаметр шины - 2pi*r, r - радиус, деление на 1000 чтобы перевести скорость в км/ч int Steps=map(Speed, minSpeed,maxSpeed,minSteps,maxSteps); if(flag1) { Serial.print(Speed); Serial.println("Kmh"); lcd.setCursor(0,0); lcd.print("RPM: "); lcd.print(RPM); lcd.print(" "); lcd.setCursor(0,1); lcd.print("Speed: "); lcd.print(Speed); lcd.print(" Km/h "); flag1=0; } int currSteps=Steps; int steps= currSteps-preSteps; preSteps=currSteps; myStepper.step(steps); } int readRPM() { if(REV >= 10 or millis()>=st+1000) // данные будут обновляться каждые 10 считываний или через 1 секунду в неиспользуемом состоянии { if(flag==0) flag=1; rpm = (60/2)*(1000/(millis() - time))*REV/bladesInFan; time = millis(); REV = 0; int x= rpm; while(x!=0) { x = x/10; RPMlen++; } Serial.println(rpm,DEC); RPM=rpm; delay(500); st=millis(); flag1=1; } } void RPMCount() { REV++; if (led == LOW) { led = HIGH; } else { led = LOW; } digitalWrite(ledPin, led); } |
Там что, надо перед каждым включением стрелку на нуль руками выставлять? Может, какой датчик абсолютного положения приделать?
Почему руками? Ведь направление вращения шагового двигателя можно изменять. На представленном видео видно же что стрелка поворачивается как по часовой, так и против часовой стрелки
Шляпа какая то, стрелка ходит как стрелка часов. Вы когда то видели спидометры в машине, как там все плавно? Не пытались побороть проблему рывков?
Петр, ну поставьте более дорогой и качественный шаговый двигатель и тогда, я думаю, проблему этих небольших рывков (на мой взгляд, они не так критичны) можно будет побороть без труда
Здравствуйте, в инете много схем для создания спидометра на ардуино на датчике. GPS, но у всех проектов вывод показаний скорости реализуется на экранчик, возможно ли скорость вывести на аналоговый спидометр? В данный момент на плате стоит биполярный двигатель (4 контакта). Спасибо.
Здравствуйте, а чем вас этот проект не устраивает? В нем как раз вывод показаний скорости происходит на аналоговый спидометр. Реализовано это с помощью шагового двигателя. С помощью биполярного двигателя это тоже можно сделать, но это будет уже посложнее. А если вам нужно получать показания скорости от GPS датчика, то в приведенной в данном проекте схеме просто замените инфракрасный датчик на модуль GPS
Так а подключение модуля куда и как, программу менять нужно. Проект мне нужен на gps для работы спидометра моего автомобиля, на нем нет ни одного датчика, ни на АКПП, ни на АБС.
Могу ли я вас попросить осуществить это? Оплату обсудим! И на счёт моторчика я не совсем уверен что он биполярный, но идёт на 4 контакта , 2 катушки .
Спасибо что ответили.
GPS-модуль подключается к последовательному порту платы Ардуино. У нас на сайте уже есть похожий проект - GPS спидометр на Arduino и OLED дисплее. Вам в него нужно просто вместо OLED дисплея добавить двигатель, который будет вращать стрелку аналогового спидометра.
Помочь с проектом не могу, извините, временно пока нет доступа к оборудованию. Но могу ответить на ваши вопросы, которые вы будете задавать в комментариях на моем сайте.
а возможно скейч под А4988
В этой статье есть скетч для управления шаговым двигателем с помощью драйвера А4988. Совместить его с программой из данного проекта, надеюсь, будет несложно
к сожалению для мня это новшество в написании скейча
Ну многое в нашей жизни происходит в первый раз ))