Kell egy akkuteszter
Felgyűlt egy csomó 18650 cellám, bontott akkukból, amiknek nem ismertem az állapotát. Szükségem lett hát egy akkuteszterre. Normális ember ilyenkor vesz egyet, de nekem valahogy nem sikerült. Egy megérkezett, de a második mérésnél már nem működött. A pótlásként küldött ugyanezt művelte.
Egy másik fajta nem érkezett meg. A pótlása sem. Az sem, amit utána rendeltem.
Valamiért nem vehettem saját tesztert. :D Más megoldást kellett keresnem, ami azt jelenti, hogy építhetek magamnak, ha akkukapacitást akarok mérni. A végül elkészült eszköz pontosságára sajnos garancia nincs, de ha valaki arra kíváncsi, hogy kuka, vagy használható egy cella, annak jól jöhet.
Ezek sok mindent tudnak, de 1-2 mérés után meghaltak :(
Mit is mérünk?
Az elmélet egyszerű. Arra vagyunk kíváncsiak, hogy egy akku milyen kapacitású. Ez lehet mérni coulombban, de a gyakorlatban inkább az amperóra (milliamperóra) használatos. Egyszerűen annyiról van szó, hogy egy órán keresztül hány milliampert lehet kihúzni az akkuból. Ha x milliamper erősségű áram egy óráig folyik, az x milliamperóra. Ha kettőig, akkor 2x mAh.
Alapvetően annyit kell tenni, hogy megfigyeljük, mennyi ideig folyik egy adott erősségű áram egy, az akkura kapcsolt terhelésen, amíg az akku annyira ki nem merül, hogy egy bizonyos érték alá nem csökken a feszültsége. (Az áram-idő függvény integrálja. :) )
Terhelés céljára lehet használni egyszerű ellenállást, de az ezzel való merítés során az akku feszültsége és árama is változik, ami a mérés pontosságát befolyásolja. Sokkal jobb állandó áramú terhelést használni, amit szintén nem nehéz elkészíteni.
Az Arduinoval történő árammérés pont úgy történik, mint ahogyan egy egyszerű műszerrel mérünk áramot : egy kis ellenállású vezetőn kell feszültségkülönbséget mérni, nagy pontosan. Kis keresés után megtaláltam a MAX471 IC-t, és a rá épülő modulokat. Így már nem kellett azon elmélkedni, hogy hogyan kellene LM386-tal erősítőt építeni, és miből lesz söntellenállás, amin azzal mérhetek.
A MAX471 pont azt csinálja, amit kell, a rajta átfolyó áram függvényében feszültséget ad ki, azaz amperenként 1V -ot. Ezt könnyen lehet mérni az Arduinoval. Ugyan az IC a mért eszközről szívja a tápot, de ez szerencsére minimális, az Arduino pedig külön USB táplálásról megy.
Szerencsére (azt hittem, szerencsére) létezik olyan modul, ami a feszültségmérést is megoldja. Na persze ez csak egy feszültségosztó, ami 1:5 arányban osztja az 1-25V közti bemenő feszültséget. (És az egyik modulomon fordítva rakta össze a kínai, egy Arduino, egy 328P, és a modul bánta a 12V feszt...) Amíg a pótlásként rendelt MAX471 modulokra vártam, szereztem kölcsön egy akkutesztert, aminek az eredményeihez (gondoltam én) hasonlíthatom majd a saját méréseimet. Na, az a hasonlítás meglepő lett. :D
Az áramkör
Az áramkört kicsit jobban bonyolítottam. Alapvetően az volt a cél, hogy minél kevesebb feszültségesés, nem kívánatos ellenállás legyen az akku és a terhelés között, ezért egy relével oldottam meg az akku és a terhelés összekapcsolását. Szerencsére volt itthon Hamlin 721 relé, ami 5V-os, nem terheli túl az Arduinot, beépített védődiódával bír, és IC foglalatba tehető (a kapcsolási rajzon 715 van, és berajzoltam külön a diódát, ha valaki olyan relével építené, amiben nincs (ezt érdemes ellenőrizni, mert lehet, hogy fordítva sikerült, de nem tudom, mikor lesz időm javítani :D ). A fordított polaritás elleni védelem már nehezebb volt, de nem lehetett kikerülni, mert ilyen a MAX471-ben, és az Arduinoban sincsen. Egy óvatlanul fordítva bekötött feszültséggel az Arduino analóg része, és a MAX is megölhető.
Több megoldás kipróbálása (és a Hobby elektronika topicban való kérdezősködés) után a soros dióda nyert. 1N5822 Schottky-diódát építettem be, amin 0,3-0,1V esik nyitóirányban, és gyorsan kapcsol. Elvileg a FET-es védelem jobb, szinte feszültségesés-mentes, de nekem valamiért ugyanúgy 0,1-0,3V esett rajta (IRF9540), ráadásul kevésbé lineárisan, mint a diódán. Utóbbin a jellemző 3-4V körüli lítiumcella-feszültségek esetén 0,30-0,32V esik, a FET nálam a 0,1V-t csak 5V körüli betápnál érte el (valószínűleg nem is volt jól megépítve). A diódán eső feszültséget természetesen szoftveresen korrigálni kellett.
(A fórumban volt egy jó javaslat, ha valaki mégis FET-tel akarna polaritásvédeni :) Meg még egy a FET-es megoldásra. )
A terhelés egy egyszerű műterhelés, amit esetemben egy LM317T feszültségszabályozó IC, és egy megfelelő ellenállás alkot. 2,8-3 Ohm körüli ellenállással ez 460mA áramot vesz fel, ráadásul, ahogy néztem, nem is melegszik rettenetesen (azért elég meleg a 317T, inkább az 500mA alatti áramokat erőltessük egy ilyennel). Persze lehet venni sokkal jobb, FET-es loadokat is eBay-ről.
Természetesen a cucc működik ellenállással terhelve is, de ilyenkor egyáltalán nem pontos, bár a kezdő és a legutolsó áramerősséget átlagolva, majd az átlagos áramerősséggel számolva közel lehet a kapott érték a valósághoz.
A kapcsolási rajz itt tölthető le PDF-ben :) (vagy a képre kattintva)
Arduino és PC oldali szoftver
A szoftver nem volt nehéz, legalábbis az a része, hogy megfelelő parancsra induljon a mérés, majd küldje a mérési adatokat soros porton. Az alapot a Henry's Bench oldal fogyasztásmérő sketch-e adta, amit ezúton is köszi nekik. :) Az egyetlen gond a megfelelő számítással adódott. :D Az elsőre kitalált módszernek nem hittem, ám mivel nem volt mivel visszaellenőrizni az eredményeket, csak sorozatos mérésekkel tudtam tesztelni, és több más módszer esetén is csak a korábban (a kínai teszterrel) lemért akkuk újramérésére hagyatkozhattam. Aztán találtam egy oldalt, ami mAh-ból és időből áramot számol, és fordítva, és ez az általam mért eredményeket igazolta is. A furcsaságokat több dolog is okozhatta.
- a cella nem ugyanúgy merül különböző ohmos terhelésekkel, 300mA folyamatos kivételét tovább húzza, mint 450-et
- rossz állapotú cellákat választottam, amik nagyon hamar vesztik a töltést, így a kínaival való mérés előtt túl sokat állva kevesebb jött ki...
Mindenesetre miután vissza tudtam ellenőrizni, már biztos volt, hogy amennyire lehet, pontos eredményeket ad a mérés. Lehetne persze cifrázni a feszültségek mintavételezését, stb. (Kéne is, a következő verzióban...) A végeredmény az, hogy a convert-formula.com oda-vissza számított értékei max. 50mAh-val térnek el a mérttől, a kölcsön kínai teszterétől viszont nagyon sokkal. Ettől nem voltam nyugodt, de ha valamiből másfél órán át folyik ki 450mA, az nem lehet 300mAh-s akku, már csak tapasztalatilag sem. :D
Az Arduino sketch alant található. Vár, amíg a soros porton a végfeszültséget (pl. -e3.5) és/vagy a start parancsot nem kapja. A start után zárja a relét, és küldi a mérési eredményeket a soros portra. Ha elérte a végfeszültséget, nyitja a relét, és megáll, csak az Arduino resetelésével indul újra.
Fontos, hogy a program elején definiált icorrection és vcorrection értékeket egyedileg kell a MAX471 modulhoz és diódához belőni. Ezt a DEBUG-gal jelzett programrészek kommentségét megszüntetve lehet ellenőrizni, így már a setup() részben is történik mérés. A korrekciók százalékban értendők, ennyi százalékkal fog többet mérni a program a MAX által szolgáltatott értéknél. Érdemes egy, vagy több, lehetőleg pontos műszerrel is összehasonlítani a mért értékeket, 3 és 4V, valamint a tervezett áramfelvétel esetén is.
// Based on
// Henry's Bench
// MAX471 Power Meter Tutorial
//http://henrysbench.capnfatz.com/henrys-bench/arduino-projects-tips-and-more/arduino-max471-power-meter-tutorial/
// Other pages
//https://convert-formula.com/a-h-mAh
//https://www.convertworld.com/hu/ido/
//https://www.rapidtables.com/calc/electric/wh-to-mah-calculator.html
//https://electronics.stackexchange.com/questions/18612/how-to-measure-capacity-of-a-lithium-ion-battery
#define VT_PIN A1
#define AT_PIN A2
#define RELAY 13
float vcorrection = 4;
float icorrection = -5;
float ah = 0;
float flow = 0;
int vcc = 0;
int vt_read = 0;
int at_read = 0;
int t=0;
String input;
boolean started=false;
float endvoltage=3.3;
int i;
String s;
char char1[5];
float voltage=0;
float current=0;
float watts=0;
int milli=0;
void setup()
{
pinMode(RELAY,OUTPUT);
digitalWrite(RELAY,LOW);
Serial.begin(9600);
while (started == false) {
/* //for DEBUG
delay(200);
digitalWrite(RELAY,HIGH);
vt_read = analogRead(VT_PIN);
voltage = vt_read * (5.0 / 1024.0) * 5.0;
voltage=(voltage+((voltage/100)*(vcorrection)));
at_read = analogRead(AT_PIN);
current = at_read * (5.0 / 1024.0);
current=(current+((current/100)*icorrection));
Serial.print(voltage);Serial.println("V");Serial.println(" "); Serial.print(current);Serial.println("A");
*/
if (Serial.available()) {input=Serial.readString(); }
if (input.indexOf('start',0) > 0) {started=true; }
if (input.indexOf('-e',0) > 0) {
for (i=input.indexOf('-e',0);input.substring(i)!="";i++) {
}
s=input.substring((input.indexOf('-e',0)),i);
s=s.substring(1, s.length());
s.toCharArray(char1, sizeof(char1));
endvoltage=atof(char1);
//For DEBUG
//Serial.print(s);
//Serial.print("float : ");
//Serial.println(endvoltage);
}
}
digitalWrite(RELAY,HIGH);
delay(100);
vt_read = analogRead(VT_PIN);
voltage = vt_read * (5.0 / 1024.0) * 5.0;
voltage=(voltage+((voltage/100)*(vcorrection)));
at_read = analogRead(AT_PIN);
current = at_read * (5.0 / 1024.0);
current=(current+((current/100)*icorrection));
Serial.print("Battery tester end voltage is : ");
Serial.print(endvoltage);
Serial.println("V");
}
void loop()
{
while ((millis() % 1000) !=0 ) {}
while (voltage > endvoltage) {
while (((millis()+2) % 1000) !=0 ) {}
vt_read = analogRead(VT_PIN);
at_read = analogRead(AT_PIN);
t++;
voltage = (vt_read * (5.0 / 1024.0) * 5.0);
voltage=(voltage+((voltage/100)*(vcorrection)));
current = at_read * (5.0 / 1024.0);
current=(current+((current/100)*icorrection));
watts = voltage * current;
flow=flow+current;
ah=flow/3600;
Serial.print(" V:");
Serial.print(voltage, 3);
Serial.print("\t I:");
Serial.print(current,3);
Serial.print("\t P:");
Serial.print(watts,3);
Serial.print("\t Ah:");
Serial.print(ah,6);
Serial.print("\t t:");
Serial.print(t);
Serial.println();
if (Serial.available()) {input=Serial.readString(); }
if (input.indexOf('stop',0) > 0) {break; }
}
digitalWrite(RELAY,LOW);
Serial.print("Battery test finished at ");
Serial.print(ah,4);
Serial.println("Ah ");
Serial.print("In ");
Serial.print(t);
Serial.println("s");
Serial.println(""); Serial.println("");
Serial.println("Reset device to begin new test.");
while(true){
}
}
Szoftver a PC oldalon
A szoftver PC oldala elsőre egy egyszerű Bash script lett. Ugyan az Arduino Serial monitor is használható erre, de egy shell script kevesebb erőforrást fogyaszt (nálam az Arduino IDE néha elég rendes prociterhelést okoz). Annyi a dolga, hogy a paraméterként kapott végfeszültséget, és a start parancsot kiküldje a megadott soros portra, majd az érkező eredményeket egy dátumozott file-ba, és a standard out-ra küldje. Egyszer lehet, hogy írok egy .net vagy GTK+ felületet is, vagy teszek egy kijelzőt a teszterre.
A script használata amúgy ennyi :
sh batterytest_2.sh /dev/ttyUSB0 start -e3.3
A -e3.3 a végfeszültség, a start parancs indítja, a /dev/ttyUSB0 pedig az a soros port, amin az Arduino lóg. (A -e3.3 elhagyható, ha 3.3V-ig szeretnénk meríteni, mivel az Arduinon is ennyi az alapérték.)
Maga a script ennyi :
#Script for controlling USB battery tester
#Parameters : Serial device name, command (stop or start), -eendvoltage (otpional)
#
#example : sh batterytest.sh /dev/ttyUSB0 start -e3.3
#
#this starts a test on /dev/ttyUSB0 with end voltage of 3,3V
#the output is stored in the batterytest.txt file
#--help parameter or run without parameter prints help
#
#!/bin/sh
CURR=$(date +"%Y%m%d%H%M")
OUTFILE=$CURR"_batterytest.txt"
touch $OUTFILE
if [ "$1" = "--help" ] || [ $# -lt 1 ]; then
echo ' #Script for controlling USB battery tester '
echo ' #Parameters : Serial device name, command (stop or start), -eendvoltage (otpional)'
echo ' '
echo ' #example : sh batterytest.sh /dev/ttyUSB0 start -e3.3'
echo ' '
echo ' #this starts a test on /dev/ttyUSB0 with end voltage of 3,3V'
echo ' #the output is stored in the batterytest.txt file'
echo ' #--help parameter or run without parameter prints help'
fi
if [ "$2" = "start" ]; then
echo "$2 test at $1 "
stty -F /dev/ttyUSB0 ispeed 9600 ospeed 9600 -ignpar cs8 -cstopb -echo
sleep 1
echo $2 $3 > $1
tail -f /dev/ttyUSB0 |tee $OUTFILE
fi
if [ "$2" = "stop" ]; then
echo $2 > $1
fi
A script indítása előtt érdemes kinyitni az Arduino soros monitorát, mert az lereseteli a soros portot, enélkül sajnos nem mindig működik a stty parancs a scriptben - nem jöttem rá, miért.
A script futásának eredménye, persze a közepét kihagytam
A kész áramkör
A kész áramkör dobozolásával szokás szerint nem sokat vesződtem - nem az a dolga, hogy szép legyen, s később úgyis fogok módosítani rajta. Egy selejtes USB CD meghajtó házba (jól megvetemedett, így érkezett...) éppen belefért, jó igényesen. :D (Van teteje is, csak az a képhez nem volt jó.) Az elsőnek rendelt, csupasz kínai akkutesztereket szépen dobozoltam, aztán mire mentem vele... NYÁK-ot hasonló megfontolásból nem készítettem, bár ez még kézzel is megrajzolható lenne, próbapanelre került az Arduinon kívüli rész.
A load-ot igazából jobb lett volna beépíteni a házba, hiszen úgyis nagyrészt ezzel lesz használva – de az eredeti terv az volt, hogy egyszerű teljesítményellenállás lesz a terhelés.
Végszó, és felhasznált oldalak
Amilyen könnyűnek tűnt az elején, végül olyan sok munka akadt ezzel a kapcsolással. Ugyanakkor a későbbiekben a tapasztalatok, és a teszter is hasznos lesz. Ha másnak is, az még jobb. :)
Az építés során felhasznált oldalak :
Henry's Bench MAX471 Power Meter Tutorial
http://henrysbench.capnfatz.com/henrys-bench/arduino-projects-tips-and-more/arduino-max471-power-meter-tutorial/
Amper-idő számítás oda-vissza
https://convert-formula.com/a-h-mAh
Az mAh számolóhoz hasznos időátváltó
https://www.convertworld.com/hu/ido/
Az egyszerű műterhelést itt találtam
https://electronics.stackexchange.com/questions/18612/how-to-measure-capacity-of-a-lithium-ion-battery