int alap = 0; // Kicsit felesleges ezekhez a változókhoz értéket rendelni, mert az első előforduláskor automatikusan kapnak egy releváns értéket. int atlag = 0; int adag = 0; // Itt az első lehetséges galiba, ha a ciklusok számát felemeled mondjuk 100-ra (100-zal oszt átlagot, 100 mintavételből), akkor az int típusú változó 32767-nyi maximális értéke rohadt gyorsan túl fog csordulni. 10 mintavételnél ez nem akkora gond (1023×10=10230), így technikailag 32-ig mehet fel az átlagolás ciklusainak száma. Tesztelni kell, hogy milyen mértékű iterálás kell az elégségesen sima szóráshoz. Javasolt változótípus: unsigned long. (Ennek a maximális értéke uszkve 4,3 milliárd. A kető között csak a sima long [2,15 milliárd] és az unsigned int [65 ezer] van. Előbbi kettő bőven sok, utóbbi elég lehet, az unsigned int 64-szeres mintavételt elbír.) for (int i=1; i <= 10; i++) { alap = analogRead(pot1); constrain(alap, 1, 1023); // Ez ide tökéletesen felesleges, mert az analogRead() eleve nem mehet 0 alá és 1023 fölé (hacsak nincs rosszul deklarálva a változó, pl. byte-ként, mert ugye akkor 255-nél fordul). alap = map(alap, 1, 1023, 1, 60); // Változatlanul nem értem, hogy miért van szükség a map-re ebben a fázisban, tekintetbe véve, hogy a bemeneti analóg érték átlagolása (ezzel a szórásának tekintélyes csökkentése) a célunk, nem az, hogy kiderüljön, pontosan hova "esik" az analóg érték az 1-től 60-ig terjedő értelmezési tartományban. adag += alap; } atlag = adag / 10;
És van benne még egy galiba: az elemhívása elején az adag változó a korábbi értéket tartalmazza (hacsak a sketch más része felül nem írja), azért nem 0-ról, hanem az előző mérés eredményéről indul az összesítés (vagyis minden hívásnál szép lassan mászik fölfelé, amit csak a constrain() kompenzál a felső határnál).
Nálam ez így néz ki (csak az átlagolás rész, amit a beolvas() hív meg és csak globális változókkal dolgozik).
const int pot1 = A3; // 1. potméter A2-n int beolv; // a potméter aktuális értéke unsigned long beolvas; // az átlagoláshoz használt átmeneti változó ("gyűjtő") int atlagolas = 100; // hány lépésben átlagoljon. A magasabb érték lassabb, de stabilabb mintavételt ad. Maximális elvi értéke kb. 4,2 millió
void beolvasas() { beolvas = analogRead(pot1); for (int i = 0; i < (atlagolas-1); i++) { beolv = analogRead(pot1); beolvas = beolvas + beolv; // csak a könnyebb érthetőség kedvéért } beolvas = beolvas/atlagolas; beolvas = constrain(beolvas,0,1023); // a számítási hibából eredő túlcsordulást levágja }
constrain() csak a "tisztításhoz" van benne, map() egyáltalán nincs, mert a feladat nem az, hogy megatározzuk, hogy az 1-től 60-ig terjedő tartományban épp hova esik a potméter aktuális értéke, hanem az, hogy kiderítsük, a korábbi méréshez (referenciához) képest változott-e a potméter helyzete vagy sem. A kimeneti értéke a beolvas változóban van tárolva (ami ugye egy sima int), értéke 0 és 1023 között lehet.
Átlagolás módszertan (ez nekem is érdekes tapasztalás volt, de self-learning alatt ez belefér).
1. csinálsz egy külön rutint, mondjuk void atlag() {...}
2. ezen belül lesz egy
unsigned long osszeg
változó. Ezt másutt nem kell használni, így nem kell globális változóként deklarálni.
3. for .. ciklus akárhány elemmel (mondjuk 0-tól 39-ig az 40 elem). mérsz, az osszeg változóhoz hozzáadod a mért értéket, majd elölről, amíg a 40 kör le nem fut
4. elosztod az osszeg-et a mérések számával (40-nel), ez lesz a nyers adatod,
5. ezt megvágod constrain-nel (a végállások miatt fontos, 0 alá nem mehet, de tapasztalataim szerint a kerekítési hibák miatt képes 1023 fölé szaladni).
Mérések alapján kb. ezer tételes átlagolásnál kerül 0,5 mp közelébe a ciklus futása (ami egyrészt ésszerűtlen, másrészt még mindig rohadt gyors).
Igen, minden mérést átlagolj! Ha a fenti külön elemet legyártod, akkor azt bármikor hívhatod.
1. Az átlagolás még mindig nem jó. Azóta mondjuk én is rájöttem (ugye a diploma hiánya), hogy a sima "iskolás" módszer az értékek összeadásával, majd az értékek számosságának elosztásával jobb (stabilabb) eredményt ad. Ez sem ördöngősség, és mivel egyébként is át kell írni, ezt is érdemes átvarázsolni. A gond a változók kezelésével van elsősorban.
2. Ez is a tesztelés eredménye, hogy praktikus minden mérést átlagolni.
3. A void loop () nyitása mi? Egyből felülírod valami random számmal az előzőleg jól kiszámolt értéket?
4. if () alá nem kell return ide, mindenképp kiszáll belőle.
Teleírom a fórumot lassan... Egy mérésssel és egy változóval kevesebb! Működik. Egy hibája van mindössze - először minden esetben meghívja a kijelzést (mivel először az átlaghoz hasonlít).
// Carbo const int pot1 = 5; // 1. potenciometer A5-re kotve int alap1; int alap11; int adag1; int atlag1;
Már hogy a rákba ne tudnád? Van egy adagértéked, amely a poti aktuális állapotától függ. Vagyis ha tekerődik a poti, változik az adag, méghozzá pont oda, ahol a poti áll. Ha tudod az adagot, tudod, hogy milyen tartományban kell(ene) állnia a potinak. Ha nem ott áll (ez egy méréssel megoldható), akkor változtatni akarod a mennyiséget...
Szóval void(Carbo) meghívását mindenképpen a pot1 változásához kell kötni, ezt csk 2 méréssel tudom én megcsinálni (sajnos). Ha van ötlet erre, szívesen fogadom.
A egy 16x2-es lcd lévő általánops infók fognak megváltozni az adag11-re, ha változik az értéke.
Köszi az észrevételt és a javaslatot (lassan tanulgatom....)
Az ez akart lenni:
analogWrite(5, atlag1);
A két mérést hogy tudnám elkerülni? A változást az első lefutáskor tudom hasonlítani a setup-ban lévő átlaghoz, de utána nem, tehát ez nem jó. A második mérés eredménye számomra fontos - ez határozza az adagolandó mennyiséget (addig fog menni az adagoló motor sec-ben).
Örülök, hogy a múzsád lehettem és inspirálhattalak valami új megvalósítására :).
Az instrukciók alapján próbáltam javítgatni a hibákat. A serial monitor szerint azt csinálja, amit én szeretnék, de az még mindig 2x akkora mint a tiéd. Mi a titok?
A "logikai bukfenc"-nél úgy gondoltam, hogy az önmagát felülírandó változó csak a számítás végrehajtása után változik meg (egyébként számolt vele, de most lejavítottam). Eddig nem írtam vissza a ciklus végén kapott átlagértéket. Most beletettem azt is, gondolm a zavarszűrésnek ez lenne a lényege.
// Carbo const int pot1 = 5; // 1. potenciometer A5-re kotve int alap1; int alap11; int adag1; int adag11; int atlag1;
Két okból. Egyrészt nincs rotary encoderem (többek között azért sem, mert hosszú távon iszonyú megbízhatatlan). Másrészt, és ez a fő ok, hogy ez abszolút pozicionált, vagyis ahol hagyom, ott indul az újraindítás után. A rotary encoder, ha nincs mellette valamilyen optikai vagy fizikai érzékelő, ezt nem tudja, vagyis minden alkalommal vagy tárolni kell az utolsó állapotot, vagy mindig ugyanonnan kell kezdeni pl. a menüt.
Noszóval, a remek mai időre való tekintettel teszteltem egy kicsit (plusz az ötleted inspirált nekem is egy ötletet, ami később hasznos lesz, gondoltam, megírom).
Tapasztalások:
1. Az analóg bemenet zavarszűrése különösen a végállások környékén erősen javasolt (erre még nem találtam jó forrást, úgyhogy barkács van megoldva). Tehát érdemes minden mérést átlagolni.
2. A map(valtozo, minbe, maxbe, minki, maxki) nem egészen úgy szabdalja fel a dolgokat, ahogy az matematikailag indokolt lenne. Példával illusztrálva. Ha a bemenet 0,1,2,3,4,5,6,7, és a kimenetet 4 felé kell vágni (vagyis négy elemre van szükség), akkor úgy fog vagdosni, hgoy 0, 1, 2 --> 0; 3, 4 --> 1; 5, 6 --> 2, 7 --> 3. A logikus ugye az lenne, hogy 0, 1 --> 0; 2, 3 --> 1; 4, 5 --> 2; 6, 7 --> 3. A map() paraméterezésével észnél kell tehát lenni, plusz javasolt a kiváló constrain() használata.
3. A gennység az a dologban (mondjuk nem lenne ártalom egy informatikai, pontosabban egy programozó matematikai diploma), hogy a sok map() és a sokféle vizsgálat elég rendesen kiütheti fel és le is az értélmezési tartományokat, például az átlagolás eredménye lehet több, mint 1023 (számítási pontatlanság, illetve kerekítés), emiatt a map() is rossz eredményt ad. Ha a fenti (2. pont) logikátlanságot kompenzálni akarjuk, akkor a kelleténél többet kell gépészkedni. Vagy elfogadunk egy jelentős pontatlanságot különösen a szélsőértékeknél (a potméter két végpontja közelében).
4. Tapasztalati úton kb. 100 részre "osztható" egy potméter teljes tartománya anélkül, hogy a vizsgálatok túlságosan sok fals hívást eredményeznének és/vagy ezek ne röcögnének ide-oda az analóg bemenet jelentős zaja miatt (nekem elég randa a bemenet jelentős átlagolás nélkül -- ehhez kellene egy szkóp kideríteni, hogy mi lehet az oka).
Egy másik megjelenítőre kihegyezet library-vel felvértezve 3764 byte, library és a megjelenítésre vonatokzó kódrészek nélkül 2106 byte. Nem mondom, hogy tökéletesen elégedett vagyok, de nem rossz. És most jön, amit eleve csinálni akartam. :-D
-- atlag12 változónak nincs hozzárendelt értéke (van, csak random),
-- a többi számolgatás holt felesleges,
void.loop()
-- 0,01 másodpercen (egy századmásodpercen) belül kellene az egyébként is kétes értékű kuszob1 értékét meghaladó mértékben változtatni a potméterből jövő értéket ahhoz, hogy az if() vizsgálat teljesüljön (illetve ennek egy eleme),
-- az AND logikai kapocs az if() vizsgálatban felesleges, mert a másodikból következik, hogy az első vizsgálat igaz, tehát olyan eset nincs, hogy a második igaz, de az első nem, és olyan sem, hogy.
Alles zusammen. Igen, ezt, ezt SOKKAL egyszerűbbre kell megcsinálni. Véleményem szerint maga a vizsgálat van erősen túlbonyolítva, azon túl, hogy komoly logikai bukfenc is van benne (Setup szakasz, átlagolás).
Megírtam a sajátomat, UNO-ra fordítva 3562 byte lett. Illene belőle faragni, de reggel 9 óta dolgozom, ilyenkor annyira már nem megy... (U.i.: a tied is kb. ekkora.)
A teljes kód végül ilyen lett, ez a serial monitor szerint jó működik. Ilyenből nekem 3 db kéne. Nem lehet ezt egyszerűbben, rövidebben megvalósítani?
// Carbo const int pot1 = 5; // 1. potenciometer A5-re kotve int alap1; int adag1; // valtozo1 a mert ADC ertek tarolasara int adag11; int adag111; int atlag1; int maxatlag1; int minatlag1; int kuszob1;
Igen, jó a meglátás. A recegés csak ESÉLY, alapvetően az van, hogy a kevésbé jó minőségű potik végállása környékén előfordulhat, hogy egy-egy lépés között iszonyú nagy a szórás. Ezt lehet csökkenteni hardveresen és szoftveresen is. Szoftveresen egyszerűbb (az elején), gyakorlatilag meg szinte mindegy.
Viszont az sem mindegy, hogy az if() teljesülése esetén mi történik az atlag és az alap változókkal... :-)
void loop() { adag = analogRead(pot1); // poti újra lekérdezve }
Utána már szabadom számolgathatok a változóval. Az alap és az átlag segítségével ki tudom venni a minimális +- értékeket, amit majd tudok figyelni a loop-ban. Köszi, azt hiszem megértettem a leckét...
Egyébként 0-60 értékekre alakítva nem volt recegés a potin, de azért beteszem.
Kár hogy nem engedi szerkeszteni. Elkövettem ismét egy hibát, de asszem így lesz jó:
Szia!
Így működhet?
// Carbo const int pot1 = 5; // 1. potenciometer A5-re kotve int val1; // valtozo1 a mert ADC ertek tarolasara int val11; // valtozo1 a mert ADC ertek tarolasara int atlag1; byte pumpa1_rele = 38; // digit 38 az egyes pumpa
// Carbo const int pot1 = 5; // 1. potenciometer A5-re kotve int val1; // valtozo1 a mert ADC ertek tarolasara int val11; // valtozo1 a mert ADC ertek tarolasara int atlag1; byte pumpa1_rele = 38; // digit 38 az egyes pumpa
A loop()-on belül nem kell többszörös mintavétel. Én az elején szoktam egyet csinálni (void.Setup() szakaszban), mert az ottani esetleges hibás mintavétel (mondjuk egy töltődő kondenzátorból visszajövő fals jel miatt) gondot okozhat).
A többszörös mintavétel lényege, hogy van egy átmeneti változód (mondjuk átlag), és van egy mintavételed. A számítás nagyjából (persze eltérő súlyokkal lehet manipulálni): átlag = (átlag + mérés)/2. Ha ezt a számítást mondjuk 20-szor lefuttatod (minimális, már milliszekundumos várakozásokkal) az analóg bemenet értékét egész szépen ki lehet átlagolni. De ez csak egyszer kell.
A többi egy végtelenül egyszerű kód. Pont azért nem írom meg, mert az, de ha írsz valamit, szívesen segítek javítgatni.
Ha jól értem, akkor a gyakorlatban többszörös mintavétel kell, melynek átlagértéke ha meghaladja a megállapított küszöbérték felét, akkor értelmezi a változást, ha nem akkor nem.
Köszönöm a segítséget, keresem a megoldást....
A sorozatos mintavételhez van esetleg valami függvény, mely mentén elinulhatok?
Az "adag" változó tényleg nem kell, ezt már töröltem.