Batteries in general and lithium based batteries in particular require special attention, when it comes to charging and balancing. For this reason, the lab has a Junsi iCharger 1010B+, which offers a complete battery management solution for virtually every battery technology out there and some non-battery related features as well (like DC-Motor burn-in and foam-cutting programs).
It has proved itself as reliable hardware for over a year, especially taking care of the custom made LiPo battery packs for the orion. It even offers a USB port for software updates and data-logging. Unfortunetaly, until now, only LogView users could get the logging data, but that would require a closed-source non-free operating system to run, which isn't available here (see Apollo-NG's Code of Conduct). Additionally, while LogView itself may be free (as in free beer), it doesn't seem to be open-source, so another solution was due…
Luckily, the USB port is actually just a serial port based on the cp210x serial to USB converter. Remember to build and load the kernel module, it should look like this, when you plug-in the iCharger:
[2865177.518351] usb 1-6.2: new full-speed USB device number 60 using ehci_hcd [2865177.604715] usb 1-6.2: New USB device found, idVendor=10c4, idProduct=ea60 [2865177.604720] usb 1-6.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [2865177.604723] usb 1-6.2: Product: Junsi iCharger 1010B+ [2865177.604726] usb 1-6.2: Manufacturer: Silicon Labs [2865177.604728] usb 1-6.2: SerialNumber: 0906102520 [2865177.605380] cp210x 1-6.2:1.0: cp210x converter detected [2865177.668344] usb 1-6.2: reset full-speed USB device number 60 using ehci_hcd [2865177.753915] usb 1-6.2: cp210x converter now attached to ttyUSB0
The following code will read, translate and calculate all vital battery and voltage/current data. It was written in Python, since it's always inherently available on Gentoo systems, but should be easily adaptable into any other language. A node.js implementation with realtime web(socket) graphs would be interesting, to make it even possible to remote-monitor the process.
#!/usr/bin/env python # -*- coding: utf-8 -*- # ######################################################################## # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # ######################################################################## import os, sys import time import serial # discharge end voltage (empty) dchg_end = 3.2 # iCharger modes of operation mop=[None]*13 mop[1] = "Charging" mop[2] = "Discharging" mop[3] = "Monitor" mop[4] = "Waiting" mop[5] = "Motor burn-in" mop[6] = "Finished" mop[7] = "Error" mop[8] = "LIxx trickle" mop[9] = "NIxx trickle" mop[10] = "Foam cut" mop[11] = "Info" mop[12] = "External-discharging" # configure the serial connections # change according to the ttyUSB assigned to the iCharger (dmesg) ser = serial.Serial( port='/dev/ttyUSB0', ) ser.open() ser.isOpen() ### MAIN ############################################################# while 1 : line = ser.readline () raw = line.split (';') v_bat = float (raw[4])/1000 v_c1 = float (raw[6])/1000 v_c2 = float (raw[7])/1000 v_c3 = float (raw[8])/1000 v_in = float (raw[3])/1000 i_chg = int (raw[5])*10 i_sum = float (raw[18])/1000 t_int = float (raw[16])/10 t_ext = float (raw[17])/10 s_vc1 = ((float (raw[6])/1000)-dchg_end)*100 s_vc2 = ((float (raw[7])/1000)-dchg_end)*100 s_vc3 = ((float (raw[8])/1000)-dchg_end)*100 s_bat = round ((((float(raw[4])/1000) - (dchg_end*3))*100/3), 1) print "Mode: " + mop[int(raw[1])] print "Batt: " + str(v_bat) + " V (" + str(s_bat) + "%)" print "Cell 1: " + str(v_c1) + " V (" + str(s_vc1) + "%)" print "Cell 2: " + str(v_c2) + " V (" + str(s_vc2) + "%)" print "Cell 3: " + str(v_c3) + " V (" + str(s_vc3) + "%)" print "Supply: " + str(v_in) + " V" print "Charge Current: " + str(i_chg) + " mA" print "Charge Amount: " + str(i_sum) + " A" print "Temp INT: " + str(t_int) + " °C" print "Temp EXT: " + str(t_ext) + " °C" print ">>" + line
It only requires the pyserial package, on gentoo you can just:
$ emerge -av pyserial
To run the application, make sure your user has permission to read the ttyUSB device and run:
$ python pycharger.py
There was not enough time to come up with a fancy pygtk or any other graphical implementation to show the data in real-time on a graph. Since the basic code, the data-mapping and the calculations are done and released under GPL3+ now, maybe someone else can step-in and extend the features to have realtime graphs :)
The following example shows the data-log output of pycharger.py, with the iCharger in monitoring mode. The battery is one of orion battery packs, after half a night of recording:
Mode: Monitor Batt: 12.199 V (86.6%) Cell 1: 4.064 V (86.4%) Cell 2: 4.072 V (87.2%) Cell 3: 4.067 V (86.7%) Supply: 12.315 V Charge Current: 0 mA Charge Amount: 0.0 A Temp INT: 34.3 °C Temp EXT: 22.3 °C >>$1;3;;12315;12199;0;4064;4072;4067;0;0;0;0;0;0;0;343;223;0;46 Mode: Monitor Batt: 12.199 V (86.6%) Cell 1: 4.065 V (86.5%) Cell 2: 4.071 V (87.1%) Cell 3: 4.068 V (86.8%) Supply: 12.328 V Charge Current: 0 mA Charge Amount: 0.0 A Temp INT: 33.8 °C Temp EXT: 22.5 °C >>$1;3;;12328;12199;0;4065;4071;4068;0;0;0;0;0;0;0;338;225;0;39 Mode: Monitor Batt: 12.199 V (86.6%) Cell 1: 4.064 V (86.4%) Cell 2: 4.071 V (87.1%) Cell 3: 4.067 V (86.7%) Supply: 12.315 V Charge Current: 0 mA Charge Amount: 0.0 A Temp INT: 33.8 °C Temp EXT: 22.2 °C >>$1;3;;12315;12199;0;4064;4071;4067;0;0;0;0;0;0;0;338;222;0;32
The same battery pack, at the end of a charge cycle, in the final balancing phase:
Mode: Charging Batt: 12.618 V (100.6%) Cell 1: 4.2 V (100.0%) Cell 2: 4.205 V (100.5%) Cell 3: 4.205 V (100.5%) Supply: 12.362 V Charge Current: 180 mA Charge Amount: 0.725 A Temp INT: 40.0 °C Temp EXT: 26.7 °C >>$1;1;;12362;12618;18;4200;4205;4205;0;0;0;0;0;0;0;400;267;725;31 Mode: Charging Batt: 12.599 V (100.0%) Cell 1: 4.2 V (100.0%) Cell 2: 4.205 V (100.5%) Cell 3: 4.205 V (100.5%) Supply: 12.315 V Charge Current: 180 mA Charge Amount: 0.725 A Temp INT: 39.7 °C Temp EXT: 26.6 °C >>$1;1;;12315;12599;18;4200;4205;4205;0;0;0;0;0;0;0;397;266;725;29 Mode: Charging Batt: 12.579 V (99.3%) Cell 1: 4.194 V (99.4%) Cell 2: 4.205 V (100.5%) Cell 3: 4.204 V (100.4%) Supply: 12.315 V Charge Current: 170 mA Charge Amount: 0.725 A Temp INT: 39.7 °C Temp EXT: 26.6 °C >>$1;1;;12315;12579;17;4194;4205;4204;0;0;0;0;0;0;0;397;266;725;19
Although the code could only be tested with the 1010B+ here, it is likely to be compatible to all sister models. If you have a different Junsi model and are able to test the code, please be so kind and leave some feedback for other people, who also look for free and open-source data logging alternatives.
If you're looking for a cheap grid power supply to drive the charger, any old PC AT or ATX power supply will do, since the charger itself is nothing else but a versatile buck/boost converter, regulated by a micro controller and assisted by a battery of balancing resistors. The 12V output of a 300W ATX supply is being used here.