Електроника и Електротехника | Electronics and Electrical Engineering > Цифрово / дигитално управление | Digital Command Control
Измервателен вагон
IvanC:
Моделите на кутийката за 3D принтер:
Основа
Капак
И двете ги печатам с лицето надолу, като на основата включвам печатането на подпори, за да се получат сравнително добри вътрешни повърхности.
Иван
IvanC:
Програмата на Ардуиното за индициране на скоростта и изминатия път:
--- Код: ---#define verNum "IC 2.0 " // sketch version number Номер на версията на програмата
#define verDate "07/04/21" // and date и дата на завършване
#include <LCD_I2C.h> // libraries used Използвани библиотеки
#include <Wire.h>
unsigned long const wheelDia = 480; // wheel running diameter in mm divided by Диаметър на колелото в mm разделен
// number of pulses per rotation (magnets) на броя импулси на оборот (на броя магнити)
// 480 for ROCO, 501 for PIKO
#define tarePin 3 // zeroing button pin Извод за бутона за нулиране на изминатия път
#define baudRate 115200 // serial baud rate Бодрейт на серийния интерфейс
#define serialTimeout 3200 // serial read timeout in ms Таймаут на серийния интерфейс в милисекунди
#define readStart ' ' // serial read start symbol Константа за нормалната работа на програмата
#define widthDelimiter ';' // pulse length delimiter Константа за нормалната работа на програмата
#define readTerminator '/' // serial read terminator symbol Константа за нормалната работа на програмата
#define LCD_address 0x27 // LCD i2c address Адрес на дисплея - използвай i2c_scanner за прочитане на адреса
#define LCD_columns 16 // LCD columns Колони на дисплея
#define LCD_rows 2 // LCD rows Редици на дисплея
#define heartbeat 13 // LED pin Извод на светодиода на Ардуиното
#define wheelConstKPH 11310UL * wheelDia // wheel constant for km/h Константа за нормалната работа на програмата
#define wheelConstMPH 7028UL * wheelDia // wheel constant for MPH Константа за нормалната работа на програмата
#define wheelConstKM 31831UL // wheel constant for km Константа за нормалната работа на програмата
#define wheelConstMI 51227UL // wheel constant for mile Константа за нормалната работа на програмата
#define wheelConstCM 277UL // wheel constant for cm Константа за нормалната работа на програмата
int heartbeatCounter = 0; // Променлива за нормалната работа на програмата
unsigned long kph = 0, mph = 0, pL = 0, t = 0; // Променливи за нормалната работа на програмата
unsigned long s, l, r, sign; // Променливи за нормалната работа на програмата
long nSk = 0, iSk = 0, nSm = 0, iSm = 0, vC = 0; // Променливи за нормалната работа на програмата
unsigned long rData[] = {0, 0, 0, 0, 0, 0, 0, 0}; // Променлива за нормалната работа на програмата
LCD_I2C lcd(LCD_address, LCD_columns, LCD_rows); // initialize display Дефиниране и инциализиране на дисплея
void setup() { // begin setup От тук до края е самият код на програмата
pinMode(heartbeat, OUTPUT); // set LED pin as output
pinMode(tarePin, INPUT_PULLUP); // set zero pin as input with internal pull-up
Serial.begin (baudRate); // initialize serial port
lcd.begin(); // initialize LCD
lcd.backlight(); // turn on backlight
lcd.clear(); // clear screen
lcd.print("Speedometer"); // display program name
lcd.setCursor(0, 1);
lcd.print(String(verNum) + String(verDate)); // display version and date
delay(1200);
} // end of setup
void loop() { // begin main cycle
int lF = 0, sTimedout;
do {
if (Serial.available()) { // read serial
t = millis(); // read current timestamp for serial timeout
char c = Serial.read();
if (c == readStart) {r = 0; vC = 0; sign = 1;}
else if (c == widthDelimiter) {rData[vC] = r * sign; r = 0; vC++; sign = 1;}
else if (c == '-') sign = -1;
else if (c != readTerminator) r = r * 10 + String(c).toInt();
else if (c == readTerminator) {
rData[vC] = r * sign; lF = true; s = rData[0]; l = rData[1];
} // if (c == readTerminator)
} // if (Serial.available())
sTimedout = ((millis() - t) > serialTimeout);
} while ((lF == 0) && (sTimedout == 0));
if ((lF) && (s)) { // data received
nSk = wheelConstKPH / s; // calculate new speed
iSk = nSk - kph; // calculate speed increment
if (nSk > 2) iSk /= 2; if (nSk > 8) iSk /= 2; // adjust speed increment
if (nSk > 30) iSk /= 2; if (nSk > 120) iSk /= 2; // based on new speed
if (nSk > 480) iSk /= 2;
if (abs(nSk - kph) < abs(iSk) * 3 / 2) kph = nSk; else kph += iSk;
nSm = wheelConstMPH / s; // do the same as above for mph
iSm = nSm - mph;
if (nSm > 2) iSm /= 2; if (nSm > 8) iSm /= 2;
if (nSm > 30) iSm /= 2; if (nSm > 120) iSm /= 2;
if (nSm > 480) iSm /= 2;
if (abs(nSm - mph) < abs(iSm) * 3 / 2) mph = nSm; else mph += iSm;
displaySpeed(0, 0, kph % 1000, " km/h "); // display speed in km/h
displaySpeed(0, 1, mph % 1000, " mph "); // display speed in mph
unsigned long km = ((l - pL) * wheelDia / wheelConstKM) % 10000UL; // calculate distance in km
unsigned long cm = ((l - pL) * wheelDia / wheelConstCM) % 1000000UL; // calculate distance in miles or cm
int i = 9; if ((km < 1000) && (cm < 100000)) i--; // figure out from where to display distance
displayDistance(i, 0, km, " km "); // display distance in km
displayDistancm(i - 1, 1, cm, " cm "); // display distance in cm
heartbeatCounter = (heartbeatCounter + 1) % 17; // heartbeat logic
digitalWrite(heartbeat, !heartbeatCounter); // flash heartbeat
} // end of calculating received data
if (!digitalRead(tarePin)) pL = l; // zero button pressed - get zero distance counter value
if (sTimedout) {lcd.clear();lcd.print(" NO SIGNAL!");} // serial timed out - display "NO SIGNAL!"
t = millis(); // read current timestamp for serial timeout
if (t % 16 == 0) {
if (abs(nSk - kph) < abs(iSk) * 3 / 2) kph = nSk; else kph += iSk;
if (abs(nSm - mph) < abs(iSm) * 3 / 2) mph = nSm; else mph += iSm;
}
} // end of main cycle
void displaySpeed( int c, int r, long n, String s) {
lcd.setCursor(c, r);
if (n < 100) lcd.print(" ");
if (n < 10) lcd.print(" ");
lcd.print(String(n) + s);
}
void displayDistance( int c, int r, long n, String s) {
lcd.setCursor(c, r);
if (n < 1000) lcd.print(" ");
if (n < 100) lcd.print(" ");
lcd.print(String(n / 10) + "." + String(n % 10) + s);
}
void displayDistancm( int c, int r, long n, String s) {
lcd.setCursor(c, r);
if (n < 100000) lcd.print(" ");
if (n < 10000) lcd.print(" ");
if (n < 1000) lcd.print(" ");
if (n < 100) lcd.print(" ");
if (n < 10) lcd.print(" ");
lcd.print(String(n) + s);
}
--- Край на кода ---
В наалото на кода има един ред, който задава константата на колелото и датчика на Хол:
unsigned long const wheelDia = 480; // Диаметър на колелото в mm разделен
// на броя импулси на оборот (на броя магнити)
// обикновено 480 за ROCO, 501 за PIKO
Тази константа е равна на диаметъра на колелото на оригинала в милиметри, разделен на броя магнити. Под "оригинала" имам предвид колелото на вагон в мащаб 1:1.
От опит установих, че диаметърът на колоосите на вагоните на Роко отговаря на диаметър на оригинала 960 мм, а на Пико на 1002 мм. Тъй като използвам два магнита на колело, съответната константа е 480 за колоос на Роко и 501 за Пико, което съм написал и в коментара на програмата.
Тази константа трябва да променим така, че да отговаря на диаметъра на използваната колоос.
Друга константа, която може да се наложи да променим е адресът на дисплея, зададен на реда
#define LCD_address 0x27 // Адрес на дисплея - използвай i2c_scanner за прочитане на адреса
Този адрес е или 0x27 или 0x3f, в зависимост от това кой I2C чип е монтиран на втората платка на дисплея (I2C адаптера). Ако чипът е PCF8574(T), адресът е 0x27, ако чипът е PCF8574А(Т), адресът е 0x3f.
Програмата използва две библиотеки. Едната е "Wire", която идва заедно с Ардуино средата, втората е "LCD_I2C". Втората може да е моя разработка, затова пускам препратка за изтегляне:
Библиотека LCD_I2C
В ZIP файла ма една папка, която трябва да се копира в папката "libraries" в работната папка на Ардуино средата - където са по подразбиране програмите за Ардуино.
Иван
IvanC:
При включване на захранването на скоростомера, на екрана за кратко се изписва информация за програмата:
Ако скоростомерът не намери измервателен вагон с парола/пин, отговарящ на неговия, на екрана се изписва, че няма сигнал от измервателен вагон:
При осъществена връзка с измервателния вагон, на екрана се изписват моментната скорост в км/ч (km/h) и мили в час (mph) и изминатият път на "оригинала" в километри (km) и на модела в сантиметри (cm). Скоростта е винаги на оригинала, т.е. мащабната скорост.
Константите в програмата са за HO, т.е. мащаб 1:87, поради което мащабната скорост и изминат път в километри са за този мащаб. Ако мащабът е различен от HO, някои от константите в програмата трябва да се променят.
По поръчка на Владо Цанков, програмата следи извод 3 на Ардуиното (tarePin). Между този извод и маса може да се свърже бутон. При натискането на бутона, показанието за изминатия път се нулира. Това нулиране е само в скоростомера. Вагонът продължава да изпраща броя регистрирани импулси от момента на подаване на захранването му. Ако изключим скоростомера и го включим отново, показанието за изминатия път ще е отново от включване на захранването на вагона. Разбира се може да нулираме показанието на индикацията по всяко време и повече от един път.
Пропуснах да спомена в предно мнение, че на платката на модула на индикацията има едно тримерче (врътка за отвертка - на снимките в две мнения преди това е синичко с бяла врътка) - с него се настройва контрастът на индикацията. Ако след включване на захранването, на екрана не се вижда нищо или се виждат само черните точки на матрицата, трябва да завъртим това тримерче в едната или другата посока, за да си нагласим желания контраст на текста.
Иван
IvanC:
Както писах в първото мнение в тази тема, вторият метод за индициране на данните от измервателния вагон е с Android устройство. Проложението иска сравнително бързо устройство иначе показва информацията с голямо закъснение. Това се получи след като добавих акселерометърът (ъгломерът) към вагона. Ако вагонът няма акселерометър, може да се използва и по-стар/бавен таблет или телефон.
Приложението може да се свали от тук:
Скоростомер плюс за Android устройство
Приложението не е в магазина на Гугъл по лично мои съображения. Поради това, за да се инсталира, трябва в телефона/таблета да е разрешено инсталиране на приложения, които не са в гугълския магазин. Това е доста специфично за всяко устройство, така че ако не знаете как да го разрешите, търсете някой познат, който е навътре с това. Иначе операционната система няма да позволи инсталирането на приложението и дори може да изтрие файла.
Приложението не иска никакви разрешения от операционната система и няма никакви реклами (една от причините да не го публикувам в магазина на Гугъл). Приложението не иска никакви активирания или заплащания (друга причина да не е в магазина).
При стартиране на приложението, на екрана се показва главният екран:
Всички съобщения са на английски. Не съм ги превеждал на български, защото всичко е елементарно за работа и се подразбира от мерните единици, които са показани.
Когато няма свързан измервателен вагон, приложението е в демонстрационен режим - както е показано по-горе. За да се свърже измервателен вагон, първо трябва да се направи "съешването" от Bluetooth настройките на телефона. Това е идентично с процеса с всяко друго Bluetooth устройство. Да припомня, че паролата/пинът е този който сме прочели или променили за HC-05 модула във вагона - няколко мнения по-горе. Тук е особено полезно ако сме променили името на модула с нещо "по-говорящо".
След като вагонът е вече свързан с телефона/таблета, трябва да се избере в приложението. Това става, като цъкнем на бутона "Bluetooth Devices" (Bluetooth устройства). Изписва се списък с всички свързани към телефона/таблета устройства:
Горната картинка е за моя телефон. Понеже съм правил експерименти с много HC-05 модули, списъкът е доста дълъг и пак понеже на повечето не съм променял имената (защото е само за тест), става голяма обърквация кой модул къде се намира. Та затова силно препоръчах (и все още препоръчвам) да се промени името на модула в измервателния вагон с нещо по-смислено.
И така, намираме измервателния вагон и цъкаме на името му. Ако захранването на вагона е включено, ще се покаже информацията от него, ако не, операционната система ще каже, че не намира избраното устройство и приложението ще се върне в демонстрационен режим.
Настройки на приложението
За да променим настройките на приложението, цъкаме на бутончето с трите хоризонтални чертички в горния десен ъгъл.
Настройките са:
1. Диаметър на колелото на вагона (Wheel Diameter) в милиметри. Това е диаметърът на колелото на оригинала, разделен на броя магнити - също, както в програмата за индикацията с Ардуино.
2. Мерна единица (Unit of Measure) - километри (km) или мили (mi) (сухоземни, а не морски/въздушни). Бутонът показва текущо активната мерна единица. Мерната единица се използва за изминат път (мащабен на "оригинала") и мащабна скорост, съответно в километри в час (km/h) или мили в час (mph).
3. Мащаб (Scale) в едно към - въвеждаме желания мащаб. Мащабът може да е произволен, но е все пак силно пожелателно да въведем мащаба на измервателния вагон, за да са верни показанията на мащабните скорост и път.
4. Вид на индикацията на скоростта (Display Type) - аналогова (Analog) или цифрова (Digital). Цъкаме на бутона за да превключим между двата типа. И тук, както при избор на мерна единица, бутонът показва текущо активния вид на индикацията. На следващите картинки е показана цифрова индикациа, а на първата в това мнение е показана аналоговата.
5. Обхват на индикацията на скоростта - максималната скорост на циферблата на аналоговата индикация. Не е активно при избрана цифрова индикация.
Като сме свършили с настройките, цъкаме на бутончето със стрелката в горния ляв ъгъл, за да се върнем на основния екран.
Ако приложението се е свързало с измервателен вагон, основният екран изглежда така:
Вижда се "цифровото" индициране на скоростта, за разлика от "аналоговото", което е поазано на първата картинка в мнението.
Ако скоростта е под 20 км/ч, тя се индицира с точност до една десета в "цифров" режим:
Искам да обърна внимание, че ако вагонът има акселерометър, на екрана се показват наклоните на вагона по надлъжната ос X и по напречната ос Y в едно на хиляда (промили) с точност до една десета. Показва се и бутон за калибриране на датчика. Ако вагонът няма акселерометър, даните за наклона не се показват.
И така, на основния екран се показват:
1. Мащабната скорост в км/ч или мили в час (mph)
2. Изминатият мащабен път в км или мили
3. Избраният мащаб
4. Изминатият моделен път в сантиметри (cm)
5. Наклонът на вагона по дължината му (X) и страничният му наклон (Y) в промили (едно на хиляда)
Бутонът "Reset" нулира показанията за изминатия път. Това става в приложението. Ако затворим приложението и го стартираме отново, то ще покаже изминатия път от вагона от включване на захранването му.
Приложението запомня последното Bluetooth устройство, с което е работило последно и при следващо стартиране автоматично го търси, за да се свърже с него. Ако не го открие (или ако Bluetooth на Андроид устройството е изключен), приложението автоматично минава в демонстрационен режим.
Калибриране на датчика за наклона (акселерометъра)
1. Поставяме вагона на релси, не на ребордите. Не е задължително повърхността, на която са релсите да е хоризонтална. Раздвижваме вагона леко напред-назад, за да улегнат колоосите в гнездата им (където лагеруват).
2. Изчакваме показанията на наклона да се успокоят.
3. Цъкаме на бутона "Calibrate". На екрана се появяват едни точки, които изчезват една по една:
а бутонът "Calibrate" става недостъпен. По време на тази стъпка е важно вагонът да не се разклаща.
4. Когато приложението завърши този етап от калибрирането, на екрана се изписва съобшение да завъртим вагона на 180° (Rotate Car 180°) и бутонът "Calibrate" отново става достъпен:
5. Вдигаме вагона от релсите, завъртаме го на 180° и го поставяме отново на релсите, на същото място. Отново раздвижваме вагона леко напред-назад.
6. Пак изчакваме показанията на наклона да се успокоят.
7. Пак цъкаме бутона "Calibrate". На екрана отново се показват точките, които постепенно изчезват, бутонът е недостъпен и пак внимаваме да не се разклати вагонът.
8. Когато завърши и вторият етап от калибрирането, приложението се връща в изходно положение.
Калибрирането на датчика за наклона (акселерометъра) става в приложението, а не във вагона. Затова е важно калибрирането да се направи за всяко използвано приложение (в различни Андроид устройства). Така направеното калибриране е също специфично за вагона, с който е направено. Ако трябва да използваме друг измервателен вагон с акселерометър, трябва наново да калибрираме и предишното калибриране се губи.
Иван
Ivo Nedkov:
:hi: Свалям ти шапка за този проект.
Много оригинална идея и реализация: вагон + скоростомер + мобилно приложение.
Благодаря за подробното описание и многото снимки.
За да реализираш подобен проект трябва да имаш доста познания в различни области:
моделиране, електроника, програмиране и др.
Поздравявам те за успешната работа!
Навигация
[0] Списък на темите
Премини на пълна версия