Bónusz program: Miért nem egyenletesen mászik a fény?

Ok, ok, szépen elhalványul a fenti led, és világosodik az alsó led, de mintha nem teljesen egyenletesen történne mindez. Mintha középállásnál kicsit sokat időzne, szinte megáll a "homok" egy pár pillanatra.

Pedig tutira mindent jól csinálunk! Pontosan egyeséven növekszik és csökken a fényerő! Akkor mi a bibi?

Bár a fény egyenletesen változik, de a szemünk nem egyenletesen érzékel! Igaziból szinte egyik érzékszervünk sem egyenletes. Lássuk csak ezt közelebbről!

Lineáris érzékelés

A lineáris azt jelenti, hogy amit érzünk és ahogy érezzük, aközött lineáris összefüggés van. Nem kell megijedni, ez a lineáris szó csak azt jelenti, hogyha egy grafikonon ábrázolnánk, akkor egy egyenest kapnánk.

Lineáris összefügglés

Például, a Dongó készletben a potméter elcsavarásával arányos volt a kimeneti feszültség. Negyed-állásban a kimeneti feszültség 5V negyedrésze volt, fél állásban a fele, stb. Szóval, a kimenet mindig egyszerűen arányos a bemenettel.

Nem-lineáris érzékelés

Minden más, ami nem ilyen, az nem-lineáris. A füleddel simán meg tudod különböztetni a suttogást és a beszédet, pedig 10 000-szer hangosabb a beszéd a suttogásnál.

Egy repülőgép hangereje és egy teljes 75 fős nagyzenekar hangereje egyformán hangosnak tűnik (bár a zenekart jobban szeretjük). Valójában a repülőgép 10 000-szer hangosabb, mint a nagyzenekar. Csak nem így érzi a fülünk.

Nyilván az evolúció tehet az egészről. Az ősembereknek fontos volt, hogy az erdőben meghallják a legapróbb neszeket, és jól különbséget tudjanak tenni az őzike és a mamut között, ezért a halk hangok tartományát sokkal érzékenyebben halljuk. De a nagyon hangos dolgokat nem tudjuk megkülönböztetni.

Óvatosan a brutális koncertekkel! Mivel nem érezzük a nagyon hangos és a piszok hangos és a veszélyesen hangos közt a különbséget, ezért a hangszórók előtt veszélyes lehet!

A dimmer

A dimmer az angol dim (elhalványít) szóból származik, és arra használják TV stúdiókban, szíházakban, sőt, otthon is, hogy a lámpákat ne csak be-ki lehessen kapcsolni, hanem fényerejüket finoman lehessen változtatni.

Okos emberek lemérték, hogy egy lámpába berakott villany nagysága és az emberi szem által érzékelt fény nagysága között mi az összefüggés. Csúnya eredményre jutottak, ez bizony közel sem lineáris!

A Wiki cikkében a Dimming curves bekezdésben olvashatsz erről részletesen, de amit a színházban használnak, az olyan, mint egy S-betű alakú görbe!

Dimmer görbék

No, ezt nehéz kimatekozni, de egy ronda exponenciális képlettel ezt lehet közelíteni. Ha 0..255 között van a fényerő, akkor a képlet

amitBeállítunk=1/(1+EXP(((amitÉrzünk/21)-6)*-1))*255

Persze ezt nem fogjuk zsebszámológépezni, Excelbe vele!

Az S-görbe

Hogyan is kell ezt értelmezni? Először is, ne feledjük, hogy a fényerősség nálunk 0..255 között van, 255 a teljes fény.

Ahhoz, hogy fél fényt (kb. 120) érezzünk, nem 120-at, hanem 109-et kell használni az analogWrite-ba! A negyed fényhez (kb. 60) nem 60-at, hanem csak 10-et kell használni.

Negyed fényhez (60) tartozó helyes érték kiszámítása: 

1/(1+EXP(((60/21)-6)*-1))*255 = 10

Hú, 60 helyett 10, ez azért durván nagy különbség! Nem csoda, hogy szemmel észrevettük, hogy valami hibádzik!

A táblázat

Azt állítottam korábban, hogy az A-starban a 32u4 mikrovezérlő egy számítógép, ezért úgy vélnénk, tud számolni. Ezt a fenti aranyos kis képletet is akár ki tudná számolni... de inkább ne fárasszuk szegényt, mert szegénynek nagyon megerőltető törtszámokkal számolni.

Mi lenne, ha egyszerűen a számolás helyett használnánk egy táblázatot, ahol előre ki vannak számolva az értékek.

Régen a bolygók helyzetét előre kiszámolták az év minden napjára, és nagy táblázatos könyvben, az Almanacban adták ki. A legelső komoly mechanikus számítógépet, a Difference Engine-t is pont arra szánták, hogy ezeket számolgassa ki. A 90-es években, amikor még nem voltak elterjedve a zsebszámológépek, a szögfüggvények értékeit négy tizedes jegyig papírra nyomtatva, könyv formájában lehetett megkapni, ennek a neve Négyjegyű függvénytáblázat volt.

Tulajdonképp annyit kell csak tenni, hogy sorban minden lehetséges elvárt érzett fényességhez kiszámoljuk, hogy pontosan mit is kell használni az analogWrite-ba. Exelre fel!

Dimmelő görbe táblázat

A táblázat nagyon egyszerű:

A kész programkódot kimásoltam a C oszlopból, picit összébb formáztam, hogy ne 256 sor hosszú legyen, és ezt kaptam:

byte dim[]={
    0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,
    2,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5,
    6,6,6,6,7,7,8,8,8,9,9,10,10,11,11,12,
    12,13,13,14,15,15,16,17,18,18,19,20,21,22,23,24,
    25,26,27,29,30,31,33,34,35,37,38,40,42,43,45,47,
    49,51,53,55,57,59,61,63,66,68,70,73,75,78,81,83,
    86,89,92,94,97,100,103,106,109,112,115,118,121,124,127,130,
    133,136,139,142,145,148,151,154,157,160,162,165,168,171,173,176,
    179,181,184,186,188,191,193,195,197,199,201,203,205,207,209,211,
    212,214,216,217,219,220,221,223,224,225,227,228,229,230,231,232,
    233,234,235,236,236,237,238,239,239,240,241,241,242,242,243,243,
    244,244,245,245,246,246,246,247,247,248,248,248,248,249,249,249,
    249,250,250,250,250,251,251,251,251,251,251,251,252,252,252,252,
    252,252,252,252,253,253,253,253,253,253,253,253,253,253,253,253,
    253,253,253,254,254,254,254,254,254,254,254,254,254,254,254,255};

Mi az hogy tömb?

Valamiből jó nagy darab! Egy kőtömb az nagy kő, egy háztömb az egy nagy ház! A programozásban egy adattömb jó nagy adat, és nem jelent mást mint a fenti táblázatot!

Emlékszel a változókra? Hogy az A-starnak vannak kis zsebecskéi amibe számokat (és más dolgokat) lehet pakolni, aztán később előszedni őket és számolni velük? Nos a tömböt úgy kell elképzelni, mint egy sornyi egyforma zsebet, amiből mindegyik zsebnek van egy sorszáma.

A legelső zseb a 0-ás számú, utána van az 1-es, és így tovább. Két módon csinálhatunk tömböket. Az első, hogy nem adjuk meg, hogy mi legyen a zsebekben, csak hogy mennyi zseb legyen. A másik lehetőség, hogy egyszerűen felsoroljuk, hogy mi legyen a zsebekben, és ebből kitalálja a C nyelv, hogy mennyi zsebre van szükség.

// Tömb megadása kezdőértékek nélkül 
byte név[elemszám];

// Tömb megadása kezdőértékekkel 
byte név[]={elem0,elem1,elem2,...};

Nos, ez a második megadás pont az, ami nekünk kell, pont így csináltuk az excellel a táblázatot! A nulladik zsebbe tettük, hogy mit kell analogWrite-elni ha 0 fényerőt szeretnénk, és így tovább...

Hogyan használjuk a tömböt?

Egyszerű! A [ ] műveleti jellel bármelyik zsebhez hozzá tudunk férni. A dim[128] a 128-as zseb értékét veszi elő, és ott pont az a szám van, amit az analogWrite-al ki kell írni! Ahova olyat írunk, hogy dim[128], oda behelyettesíti az ebben a zsebben lévő értéket, pont, mintha ez egy változó lenne.

Természetesen a 128 helyett is írhatunk bármilyen képletet, például előszedhetjük, hogy ugye a sand tartalmazza, hogy mennyi homok van, akkor a dim[sand] megmondja, hogy az adott homokhoz mennyi fény kell.

Tehát:

// Korábban 
analogWrite(5, sand);
analogWrite(6, 255-sand);

// Most 
analogWrite(5, dim[sand]);
analogWrite(6, dim[255-sand]);

Na, ugye nem volt nehéz? Itt a teljes program:

byte sand;
byte dim[]={
    0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,
    2,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5,
    6,6,6,6,7,7,8,8,8,9,9,10,10,11,11,12,
    12,13,13,14,15,15,16,17,18,18,19,20,21,22,23,24,
    25,26,27,29,30,31,33,34,35,37,38,40,42,43,45,47,
    49,51,53,55,57,59,61,63,66,68,70,73,75,78,81,83,
    86,89,92,94,97,100,103,106,109,112,115,118,121,124,127,130,
    133,136,139,142,145,148,151,154,157,160,162,165,168,171,173,176,
    179,181,184,186,188,191,193,195,197,199,201,203,205,207,209,211,
    212,214,216,217,219,220,221,223,224,225,227,228,229,230,231,232,
    233,234,235,236,236,237,238,239,239,240,241,241,242,242,243,243,
    244,244,245,245,246,246,246,247,247,248,248,248,248,249,249,249,
    249,250,250,250,250,251,251,251,251,251,251,251,252,252,252,252,
    252,252,252,252,253,253,253,253,253,253,253,253,253,253,253,253,
    253,253,253,254,254,254,254,254,254,254,254,254,254,254,254,255}; 

void setup() {
    pinMode(5, OUTPUT);
    pinMode(6, OUTPUT);
    pinMode(0, INPUT_PULLUP);
    sand=0;
}

void loop() {
    if (digitalRead(0)==0) { 
        // lábak a padló felé néznek
        if (sand<255) {
            sand=sand+1;
        }
    }
    else {
        // lábak a mennyezet felé néznek
        if (sand>0) {
            sand=sand-1;
        }
    }

    analogWrite(5, dim[sand]);
    analogWrite(6, dim[255-sand]);
    delay(20);
}

Mit volt ebben a részben?

Tudunk egyszerű programokat írni az A-starra! Tudunk ledeket, és érzékelőket kezelni, tudjuk mi az a konstans, változó, tömb és feltétel. Még azt is tudjuk, hogy mi az az utasításblokk, és egy egészen tüchtig kis ledes homokórát rittyentettél!