-
Notifications
You must be signed in to change notification settings - Fork 0
/
battery-test-harness.ino
167 lines (136 loc) · 3.63 KB
/
battery-test-harness.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include <math.h>
// pins
#define VOLTAGE_PIN 0
#define TEMP_PIN 1
#define RELAY_LOAD 3
#define RELAY_CHARGE 2
#define CHARGE_NOT_DONE_PIN 4
#define ALARM_PIN 5
// params
const int POLL_MS = 10000;
const int CELL_COUNT = 3;
const float MIN_CELL_VOLTAGE = 3.4;
const float THERM_A1 = 3.354016E-3;
const float THERM_B1 = 2.569850E-4;
const float THERM_C1 = 2.620131E-6;
const float THERM_D1 = 6.383091E-8;
// when the battery is disconnected or done, pin 4 is on
void setup() {
pinMode(RELAY_LOAD, OUTPUT);
pinMode(RELAY_CHARGE, OUTPUT);
pinMode(ALARM_PIN, OUTPUT);
pinMode(CHARGE_NOT_DONE_PIN, INPUT);
digitalWrite(ALARM_PIN, LOW);
Serial.begin(115200);
firstRow();
}
float getPinVoltage(int pin) {
return analogRead(pin) / 1024.0f * 5;
}
float getTemp() {
// voltage
float v = getPinVoltage(TEMP_PIN);
float rt = 10000; // resistance of therm @ 25C
float r = (rt * (5 - v)) / v; // resistance now
float t = 1.0f / ( // temperature of therm by steinhart-hart
THERM_A1 +
THERM_B1 * log(r/rt) +
THERM_C1 * pow(log(r/rt), 2) +
THERM_D1 * pow(log(r/rt), 3)
);
return t - 273.15; // we return C, for "cience"
}
bool isConnected() {
return getVoltage() > 1; // why not 1
}
bool isFull() {
return /*isConnected() && */!digitalRead(CHARGE_NOT_DONE_PIN) && digitalRead(RELAY_CHARGE);
}
float getVoltage() {
return getPinVoltage(VOLTAGE_PIN) * 2.8f;
}
bool isEmpty() {
return getVoltage() < (CELL_COUNT * MIN_CELL_VOLTAGE);
}
struct BatteryState {
bool isCharging;
int waitMs;
} bs;
void loop() {
delay(POLL_MS);
logData();
doStateMachine();
}
// this could be nicer, but not without some serious preproc abuse
void firstRow() {
Serial.print("millis()");
Serial.print(",");
Serial.print("getTemp()");
Serial.print(",");
Serial.print("getVoltage()");
Serial.print(",");
Serial.print("bs.isCharging");
Serial.print(",");
Serial.print("isFull()");
Serial.print(",");
Serial.print("isEmpty()");
Serial.println();
}
void logData() {
Serial.print(millis());
Serial.print(",");
Serial.print(getTemp());
Serial.print(",");
Serial.print(getVoltage());
Serial.print(",");
Serial.print(bs.isCharging);
Serial.print(",");
Serial.print(isFull());
Serial.print(",");
Serial.print(isEmpty());
Serial.println();
}
enum ChargeState { STOP, DISCHARGE, CHARGE };
void charge(ChargeState cs); // arduino is literal garbage.
void charge(ChargeState cs) {
digitalWrite(RELAY_LOAD, cs == ChargeState::DISCHARGE);
digitalWrite(RELAY_CHARGE, cs == ChargeState::CHARGE);
}
void doStateMachine() {
// section: early exit conditions
// please don't change any state here
/*if (!isConnected())
// no sense in running the harness if there's no battery...
// TODO: should we reset the harness until the battery's up?
return;*/
if (getTemp() > 35) {
digitalWrite(ALARM_PIN, HIGH);
charge(ChargeState::STOP);
return;
} else {
//digitalWrite(ALARM_PIN, LOW);
}
// this condition accounts for the delay happening first.
if (bs.waitMs > POLL_MS) {
// something has put the sensors into an undefined state;
// the state machine should sleep until the sensors are okay
bs.waitMs -= POLL_MS;
return;
}
bool isChargingLast = bs.isCharging;
// you can change state after this line
if (bs.isCharging) {
if (!isFull())
charge(ChargeState::CHARGE);
else
bs.isCharging = false;
} else {
if (!isEmpty()||!isConnected())
charge(ChargeState::DISCHARGE);
else
bs.isCharging = true;
}
// section: detect state machine changes and react to them
if (isChargingLast != bs.isCharging)
bs.waitMs = 100;
}