Електроника и Електротехника | Electronics and Electrical Engineering > Цифрово / дигитално управление | Digital Command Control

Измервателен вагон

<< < (3/8) > >>

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] Списък на темите

[#] Следваща страница

[*] Предходна страница

Премини на пълна версия