My arduino design is still evolving, but it is now close enough for a detailed preview. I keep thinking of new features as usually happens when a computer is included. Here are pictures, schematic and preliminary code. It works but it isn't finished. I'm going to add a solid state relay for ac control. That will need a heatsink. I'm not sure yet whether I'll just control the on board charger or switch the QuiQs too. And it can now enable packs for discharge so it may become my Tesla Wall if I can find an inverter. It works very well right now and can communicate with a laptop or run independently.
/* Y Cable Controller for Zero Motorcycle use 7/28/2017 Keith Thomas Version 1.0
Arduino Nano program to control the enable lines between external chargers and the bike or power pack(s).
Purpose is to end the charging cycle at less than full charge or 100% SOC, can also enable packs for discharge
Method is to measure the pack voltage while charging and turn the enable signal off when a desired setting is reached.
Pack voltage is reduced by a 10/304 resistive divider, ADC 0-1023, 4.096v full scale reference
Design adjustment range for at least 50% to 100% SOC, with +/- 2.4% accuracy, 0.12v resolution
Dial nominal reading is 102 to 120, 18 volt range, 0-100 dial
*/
// I/O constants
const int acRelay = 2; // D2 is control for AC relay
const int packEnable1 = 3; // D3 pull up to close pack contactor
const int packEnable2 = 4; // D4 second pack
const int enableOut1 = 7; // Charger 1 enable
const int enableOut2 = 8; // Charger 2 enable
const int ledPin = 13; // LED connected to digital pin 13
// A0 is set potentiometer wiper
// A1 is pack voltage divider
// A2 is charger 1 enable
// voltage constants
const int packMin = 842; //105V max, 102.5 nominal, min < 50% SOC
const int packMax = 986; //117.2V min, 120.0 nominal, max > 100% SOC
const float packMinF = 102.49;
const float packMaxF = 120.01;
// variables
boolean disabled = false; //use to latch enable at stop
int packV; //voltage of battery pack
int setV; //setting potentiometer 0-1023
int packMap; //pack voltage typical range mapped to 0-1023
int enableV; //analog enable measure 0-1023
float setMap; //set voltage mapped to pack range for serial out
float readMap; //pack voltage adc mapped to real voltage for serial out
void setup() {
digitalWrite (acRelay, HIGH) ; //AC on initially
digitalWrite (enableOut1, LOW) ; //pull low to disable charging
digitalWrite (enableOut2, LOW) ; //second charger disable
digitalWrite (packEnable1, HIGH) ; //pull up pack enable
digitalWrite (packEnable2, HIGH) ; //pull up second enable
pinMode(acRelay, OUTPUT); // drive ssr control
pinMode(enableOut1, INPUT); // Hi-Z to allow enable pass through
pinMode(enableOut2, INPUT); // Hi-Z to allow enable pass through
pinMode(packEnable1, INPUT); // Hi-Z unless pack enable
pinMode(packEnable2, INPUT); // Hi-Z unless pack enable
pinMode(ledPin, OUTPUT); // use built in LED as charging indicator
digitalWrite(ledPin, LOW); // charging LED off
Serial.begin(9600); // report activity if usb has serial terminal
Serial.println();
Serial.println("Y Cable Controller");
delay(1000); // wait for things to settle before measuring
digitalWrite(ledPin, HIGH); // LED on to indicate measuring and enabled
}
void loop() {
setV = analogRead(A0); // read knob setting
digitalWrite(ledPin, HIGH); // charging
setMap = mapf(setV, 0, 1023, packMinF, packMaxF);
Serial.print("set ");
Serial.print(setMap);
packV = analogRead(A1);
readMap = mapf(packV, packMin, packMax, packMinF, packMaxF);
if (packV == 0) {
readMap = 0; // not connected to pack
}
Serial.print(" pack ");
Serial.print(readMap);
Serial.print(" ");
Serial.println(disabled);
delay(500);
packMap = map(packV, packMin, packMax, 0, 1023); // map(value, fromLow, fromHigh, toLow, toHigh)
if (not disabled) {
if (packMap > setV) { // voltage exceeds setting, disable
pinMode(enableOut1, OUTPUT);
pinMode(enableOut2, OUTPUT);
digitalWrite(ledPin, LOW); // LED off to indicate charging stopped
disabled = true;
Serial.println("Set voltage reached, charging disabled.");
}
}
digitalWrite(ledPin, LOW); // LED off
delay(100);
}
float mapf(float x, float in_min, float in_max, float out_min, float out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}