egy mobil robot építésének története

Robotkocsi

Robotkocsi

Szenzorkezelés (1. rész)

mellékesen: mire jó a függvénypointer

2018. szeptember 26. - dralisz82

A Freedom Boardon van 6 db analóg bemenet, az akkumulátor monitorozását mindenképp terveztem, így adta magát, hogy feszültségmonitorozó legyen az első szenzor.

A legegyszerűbb szenzor egy analóg vagy digitális bemenet állapotának lekérdezése, azonban a szenzorkezelést nem érdemes ad-hoc módon megoldani. Mivel maga a szenzor egyszerű, a szenzorkezelő keretrendszer kialakítására fektettem nagyobb hangsúlyt.

Hardver

A Freedom board 3.3 V-os rendszerfeszültséggel működik, ami azt jelenti, hogy az analóg bemenetei a 0 és 3.3 V közötti feszültségtartományt tudják mérni. Ha ennél nagyobb feszültséget szeretnénk monitorozni, akkor azt ebbe a tartományba kell skáláznunk, amit egy egyszerű feszültségosztóval megtehetünk:

2 db egyforma értékű ellenállással felezzük a feszültséget, így pl. egy 5 V-os tápvonal mérhetővé válik, mivel 0 - 2.5 V tartományba fog esni a mérendő feszültség.

Az akkumulátor 12 V körüli feszültségét pedig különböző méretű ellenállásokkal tudjuk a 2 V körüli tartományba hozni, az Umért = Umérendő / (R1 + R2) * R2 képlet szerint.

Fontos, hogy az ellenállásoknak ne csak az arányát, de a méretét is helyesen válasszuk meg:

  • Ha túl kicsi ellenállásokat választunk, akkor nagyon nagy lesz a feszültségosztónkon eső áramerősség, fölöslegesen terheljük az áramforrásunkat, hamar lemerítjük az akkumulátorunkat.
  • Ha ellenben túl nagy (pl. MΩ) nagyságrendű ellenállásokat választunk, túl pici lesz az áramerősség, ami az analóg-digitális átalakító (ADC) sample and hold kondenzátorát tölteni fogja, az onnan szükségszerűen elszivárgó áram pedig pontatlanná, sőt értékelhetetlenné teszi a mérést.
  • Jó tehát, ha tudjuk az ADC-nk bemeneti impedanciáját (10 kΩ körüli érték az esetünkben) és ehhez igazítjuk a feszültségosztó ellenállásainak értékét.

Az akku feszültségének méréséhez egy 100 kΩ és egy 15 kΩ ellenállásból készítettem feszültségosztót, ami nem disszipál el túl nagy teljesítményt (P = U² / R), ugyanakkor elegendő áramot szolgáltat a méréshez.

robotkocsi_077_feszultsegoszto.png

A mérés stabilabbá tételéhez egy 100 nF értékű kondenzátort is elhelyeztem az "alsó" ellenállással párhuzamosan kötve, amire azért is szükség volt, mert egyelőre a breadboardos kialakítás miatt csak egy nemkívánatosan hosszú vezetékkel tudtam az ADC bemeneti csatlakozóját bekötni. A kondenzátor megléte ebben az esetben szemmel láthatóan stabilabbá tette a méréseket, de az igazi majd egy megfelelően kialakított forrasztott megoldás lesz. Ezzel a trükkel akár 1 MΩ körüli ellenállásokkal is stabil és pontos mérési eredményekhez jutunk, feltéve, ha a mérések között van elég ideje a kondenzátornak a feltöltődésre.

Keretrendszer

Szoftveres oldalról nézve minden szenzornak van:

  • neve, azonosítója
  • egy mérést végző algoritmusa
  • egy mért értéke
  • a mért értéknek mértékegysége

A tervem az, hogy egy központi objektumtól lehessen lekérdezni az elérhető szenzorok listáját, valamint hozzáférést kapni az egyes szenzorok paramétereihez.

A fenti listában szereplő 4 tulajdonság köré egy Sensor osztályt építettem:

class Sensor {
public:
    Sensor(char *sId, char *name, char *metric);
    ~Sensor();
    ...

    void setFunction(float (*function)(void) = 0);
    char *getId();
    char *getName();
    char * getMetric();
    float readValue();

private:
    char sId[10];
    char name[30];
    char metric[4]; // max 3 characters + terminating 0
    float (*function)(void);
};

Mivel C++ környezetben vagyunk, lehetne ez egy ősosztály, amiből származtatnám a konkrét szenzorokat implementáló osztályokat, felüldefiniálva a readValue() függvényt és a többi paramétert, de aktuálisan más utat választottam.

Mivel a mérést végző függvényt leszámítva nagy különbség (egyelőre) nem lesz a szenzorok között és nem akartam, hogy nagyon terjedelmes legyen a kód, ellenben kíváncsi voltam, hogy hogyan működnek a függvénypointerek a mbed OS környezetben, ebből az egy osztályból példányosítottam az összes szenzoromat, majd állítottam a függvénypointerüket a megfelelő függvényekre:

float readVBatt() {
    float factor = 3.3 * 8.25; // Adjusted value of theoretical: 3.3V * 115k / 15k
    return sensors->getAnalogIn(0)->read()*factor;
}

void Sensors::createVBatt() {
    Sensor *s = &sensArr[sensNum++];
    s->setId("vBatt");
    s->setName("battery voltage");
    s->setMetric("V");
    s->setFunction(readVBatt);
}

Ebből a kódrészletből már az is látható, hogy van egy Sensors osztály (amiből egy példányosított objektum létezhet az egész programon belül), ami nyilvántartja a szenzorainkat, valamint tartalmazza azokat az erőforrásokat (pl. AnalogIn objektumok), amiket a szenzor objektumok használhatnak.

class Sensors {
public:
    Sensors();
    ~Sensors();
    Sensor* getSensor(char *sId);
    AnalogIn* getAnalogIn(int aiId);

private:
    void createVBatt();
    ...
   
    Sensor sensArr[MAX_NUM_SENS];
    int sensNum;
   
    AnalogIn* analogInputs[6];
};

Sensors::Sensors() {
    // create peripheral objects
    analogInputs[0] = new AnalogIn(PTB2);
    ...
    sensNum = 0;

    // create sensor objects
    createVBatt();
    ...
}

Sensor* Sensors::getSensor(char *sId) {
    if(!strcmp(sId, "vBatt"))
        return &sensArr[SENS_VBATT];
    ...
}

Az így megtervezett keretrendszer szépen és jól működik, de visszatekintve rá úgy néz ki, mintha az objektumorientáltság hőskorából származna, amikor class-ok híján struct-okba próbálták összefogni a fejlesztők az összetartozó adatokat, függvényeket. Egyszer valószínűleg korszerűbbre fogom tervezni, bár ez csupán esztétikai kérdés, hiszen a háttérben mindkét megoldás körülbelül ugyanarra a gépi kódra fordul le.

Szenzor olvasása

A szenzorok olvasására kibővítettem a Bluetooth-on keresztül várt parancsok listáját egy readSensor paranccsal:

void execCommand(char *cmd, int argc, simplestr *args) {
    ...
    else if(!strcmp(cmd, "readSensor")) {
        Sensor *s = sensors->getSensor(args[0]);
        if(s != NULL) {
            BT.printf("%s: %f %s\n", s->getName(), s->readValue(), s->getMetric());
        }
    }
    ...
}

Így az autó irányítására is használt Bluetooth Serial Controller programból lekérdezhetővé váltak a szenzorok:

robotkocsi_078_readsensor.png

Forráskód

Korábban az os.mbed.com-on keresztül már megosztottam a kódot, mostantól azonban a kényelmesebb hozzáférés, olvasás érdekében a GitHubon is elérhetővé tettem: https://github.com/dralisz82/robotkocsi_OS

 

A bejegyzés trackback címe:

https://robotkocsi.blog.hu/api/trackback/id/tr9514237955

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.
süti beállítások módosítása