Rýchlomer, digitálny potenciometer


Projekt rýchlomera kombinuje použitie fotoelektrického snímača a digitálneho potenciometra. Arduino bude na základe počtu otáčok kolesa zachytenými fotoelektrickým snímačom elektricky nastavovať digitálny pontenciometer. Potenciometer je pripojený na vyšší systém, ktorý je pripojený k rýchlomeru a vizualizuje na analógovom displeji rýchlosť lokomotívy. V našom prípade využijeme 8 bodov pripevnených na koleso elektrickej lokomotívy, aby výstup pre rýchlomer nebol skokovitý. Na jednu otáčku kolesa tak bude prislúchať 8 prechodov, ktoré zaznamená fotoelektrický snímač RobotDYN. V konkrétny časový interval sa počet prechodov spočíta a odošlú sa ako počet krokov do digitálneho potenciometra, ktorý sa nastaví na určitý odpor, ktorý je linárne odstupňovaný.

Body pripevnené na koleso rušňa

Technické informácie o vozidle (elektrický rušeň triedy 362 "ESO") - Železnice 600 Vracov:

  • vmax = 20 km/h / 3,6 = 5,55 m/s, (maximálna rýchlosť rušňa)
  • d = 0,45 m (priemer kolesa na podvozku rušňa)
  • obvod = pi*d = pi*0,45 m ≐ 1,413 m, --> vzdialenosť, ktorú koleso prejde na jedno otáčku
  • n = vmax/obvod, teda n = 3.93-krát sa otočí koleso za 1 sekundu pri maximálnej rýchlosti 20 km/h
  • T.j. 3,93*8 pulzov ≐ to predstavuje 31 pulzov na sekundu pri maximálnej rýchlosti 20 km/h
  • Medzi prichádzajúcimi pulzmi bude pri maximálnej rýchlosti rušňa pauza cca 32.25 ms. Tento interval je možné použiť pre rozlíšenie dvoch po sebe idúcich signálov bez započítania zákmitu, ktorý môže nastať na digitálnom vstupe.

    Železnice 600 Vracov - lokomotíva ESO 362

    Digitálny potenciometer X9C103S:

    Digitálny potenciometer X9C103S á rozsah nastavenia odporu 0 až 10 kohm, pričom je ho možné prenastaviť v 100 krokoch, ktoré sú identicky odstupňované po 100 ohm. Tento potenciometer má lineárnu charakteristiku. Prúdové zaťaženie potenciometra na výstupe je max 4.4 mA, preto sa nehodí do výkonových sústav, ale iba ako signalizačná súčiastka. V aktuálnej implementácii sa za jednotku času (napr. 1 sekunda) nastaví potenciometer na hodnotu počet pulzov * 100 ohm. Výstup potenciometra je pripojený priamo do počítača vyššieho systému, ktorý hodnotu vizualizuje na displej stanovišťa lokomotívy. Pre prepojenie digitálneho potenciometra X9C103S s Arduinom sa využívajú 3 dátové vodiče (CS, INC, U/D) + napájanie.

    Čítač impulzov (otáčok)

    Fotoelektrický snímač (RobotDYN) je založený na infračervenom vysielači a prijímači. Štandardne je prijímač schopný detegovať signál z vysielača, ktorý vysiela nepretržite. Tento výstup prijímača je priamo pripojený k DOUT (Digital Out) výstupu modulu. Teda v prípade prechodu bodu medzi vysielačom a prijímačom sa na výstupe DOUT objaví logická 0 - LOW. Senzor má dostupný aj analógový výstup, ktorý však momentálne nevyužijeme pre túto aplikáciu. Arduino je schopné tento digitálny signál načítavať v prerušení, pričom sa zaoberá zostupnou hranou signálu z HIGH to LOW. Tento jav so zostupnou hranou nazývame aj FALLING. Na typ prerušenia RISING (vzostupná hrana), LOW prerušenie nezareaguje. Nežiadúci jav, ktorý nastáva je zvlnenie signálu, ktoré môže byť zapríčinené rôznymi javmi, napríklad nestálosť signálu, slabá filtrácia, pomalý prechod bodu popred snímač, externé rušenie a iné... Vo výsledku to môže zapríčiniť, že jeden reálny prechod načítaný aj niekoľko-krát z dôvodu zákmitov. Existujú rôzne spôsoby, predovšetkým pre optimalizáciu takéhoto signálu hardvérovou formou napríklad využitím kondenzátora, ktorý daný zákmit dokáže eliminovať, predĺži častokrát aj jeho dĺžku dobehom napäťovej úrovne. Zákmit je veľmi krátky, trvá maximálne pár jednotiek milisekúnd. Riešením je aj softvérový debounce, kedy prerušenie FALLING zareaguje na prechod z HIGH do LOW úrovne, avšak využívame aj overenie času, či je medzi signálmi aspoň x milisekúnd. Nakoľko z predchádzajúceho prepočtu vieme, že medzi pulzami bude 32 milisekúnd pri maximálnej rýchlosti rušňa, môžeme zvoliť pokojne 15 až 30 ms debounce. To zaručí, že načítame až ďalší signál a nie zvlnenie existujúceho signálu so zákmitmi.

    Technické informácie k programovej implementácii

    Všetky premenné, ktoré sa využívajú v prerušení, musia byť typu volatile, aby ich prerušenie obslúžilo bez ohľadu nato, kde sa aktuálne program vykonáva. Prerušenie obslúži premenné typu volatile aj v prípade, že je program zastavený na funkcii delay(). V našom prípade máme volatile premenné pre počet pulzov (int) a čas (unsigned long) načítaný z funkcie millis(). Prerušenie (v prípade dosky Arduino Uno) je možné využiť iba pre vývody s podporou hardvérového prerušenia, t.j. D2, D3. V systéme sa využíva počítadlo millis(), ktoré raz za 1000 ms prerušenie odpojí. Následne Arduino zapíše hodnotu načítaných signálov ako počet krokov na digitály potenciometer, vynuluje počítadlo a následne opäť obnoví prerušenie. Čas 1000 ms pre vyhodnotenie je iba ukážkový a je v systéme plne konfigurovateľný prostredníctvom UART monitoru, kedy je možné zapísaním znakov +, respektíve - pripočítať a odpočítať 100 ms (pre testovacie účely a nájdenie optimálneho času refreshu). Nakoľko je možné na digitálny potenciometer X9C103S zapísať hodnoty 0 až 100, nesmieme presiahnuť 100 krokov. Optimálne je teda zaznamenávať pulzy max 3 sekundy (31 pulzov na sekundu pri maximálnej rýchlosti 20km/h), aby sme zaručili počet krokov pod 100, prípadne ich môžeme priemerovať / vydeliť počtom prechodov, čím získame počet otáčok kolesa ako takého, čo už môže však byť v riešení vyššieho systému, ktorý pracuje s výstup digitálneho potenciometra. Samotný prepočet už realizuje vo vyššom systéme C# aplikácia na počítači, ktorá určí aktuálnu rýchlosť vozidla a dokáže túto rýchlosť vizualizovať aj na monitore lokomotívy. Nakoľko update prebieha štandardne každých 1000 ms t.j, refresh rate je 1 Hz, zmena rýchlosti na monitore - analógovom vizualizéri (na štýl analógového ručičkového voltmetra) nie je skokovitá. Počítač je pripojený priamo k výstupu potenciometra X9C103S.

    Stanovište lokomotívy ESO

    Programová implementácia:

    Potenciometer X9C103S má určitú odchýlku na nastavenej hodnote odporu v rozmedzí 10 až 20%, reálne je cca do 12% s čím treba počítať a korekciu zapracovať do finálnej aplikácie. V programovej implementácii je možné cez Serial Monitor posielať znaky + / - pre predĺženie / skrátenie obnovovacej frekvencie výsledného nastavenia potenciometra. Knižnica FastX9CXXX dostupná na stiahnutie na Githube: https://github.com/GitMoDu/FastX9CXXX

    //Autor implementácie: Martin Chlebovec (martinius96)
    //Starting refresh rate: 1Hz
    //Podpor autora projektu kávou: https://paypal.me/chlebovec
    
    #include <avr\wdt.h>
    #include <FastX9CXXX.h>
    // pinout
    #define X9_CS  3
    #define X9_INC 4
    #define X9_UD  5
    
    
    #define ROBOTDYN_Pin 2 // ROBOTDYN modul pripojeny k D2 (podpora preprusenia)
    volatile unsigned long tipCount; // pocet pulzov, inkrementovane v interrupte
    volatile unsigned long ContactTime;// timer v interrupte - casovy debounce
    
    FastX9C103 x9; //objekt x9 pre triedu FastX9C103
    unsigned long timer = 0;
    unsigned long interval = 1000;
    void setup() {
      // zahájení komunikace po sériové lince
      Serial.begin(9600);
      pinMode(ROBOTDYN_Pin, INPUT);
      attachInterrupt(digitalPinToInterrupt(ROBOTDYN_Pin), rgisr, FALLING); //prerusenie na zostupnu hranu - LOW
      sei();// Enable Interrupts
      x9.Setup(X9_CS, X9_UD, X9_INC);
      wdt_enable(WDTO_8S); //watchdog
    }
    
    void loop() {
      wdt_reset(); //feed watchdog
      if (Serial.available())
      {
        char val = Serial.read();
        if (val == '+')
          interval += 100;
        else if (val == '-')
          interval -= 100;
      }
      if ((millis() - timer) >= interval) {
        Serial.print("Interval: ");
        Serial.println(interval);
        timer = millis();
        cli();//Disable interrupts
        x9.JumpToStep(tipCount);
        Serial.print("Pocet impulzov: ");
        Serial.println(tipCount); //1 pulz = 100 ohm
        tipCount = 0; //VYNULOVANIE PULZOV
        sei();//Enables interrupts
        Serial.print("Priblizna hodnota nastaveneho odporu: ");
        Serial.print(x9.GetEstimatedResistance(), DEC);
        Serial.println(" Ohm");
      }
    }
    
    void rgisr() {
      //AK JE MEDZI PULZAMI ASPON 15ms
      if ((millis() - ContactTime) > 15 ) { // debounce of sensor signal
        tipCount++; //PRIPOCITAJ +1
        ContactTime = millis(); //uloz cas pulzu
      }
    }