dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
battery.c
Go to the documentation of this file.
1 
17 /*
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 3 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful, but
24  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26  * for more details.
27  *
28  * You should have received a copy of the GNU General Public License along
29  * with this program; if not, see <http://www.gnu.org/licenses/>
30  *
31  * Additional note on redistribution: The copyright and license notices above
32  * must be maintained in each individual source file that is a derivative work
33  * of this source file; otherwise redistribution is prohibited.
34  */
35 
36 #include "openpilot.h"
37 
38 #include "flightbatterystate.h"
39 #include "flightbatterysettings.h"
40 #include "modulesettings.h"
41 #include "pios_thread.h"
42 
43 // ****************
44 // Private constants
45 #define STACK_SIZE_BYTES 624
46 #define TASK_PRIORITY PIOS_THREAD_PRIO_LOW
47 #define SAMPLE_PERIOD_MS 250
48 // Private types
49 
50 // Private variables
51 static bool module_enabled = false;
52 static struct pios_thread *batteryTaskHandle;
53 static int8_t voltageADCPin = -1; //ADC pin for voltage
54 static int8_t currentADCPin = -1; //ADC pin for current
56 
58 
59 // ****************
60 // Private functions
61 static void batteryTask(void * parameters);
62 
63 static int32_t BatteryStart(void)
64 {
65  if (module_enabled) {
66  FlightBatterySettingsConnectCallbackCtx(UAVObjCbSetFlag, &battery_settings_updated);
67 
68  // Start tasks
70  TaskMonitorAdd(TASKINFO_RUNNING_BATTERY, batteryTaskHandle);
71  return 0;
72  }
73  return -1;
74 }
79 int32_t BatteryInitialize(void)
80 {
81  if (FlightBatterySettingsInitialize() == -1) {
82  module_enabled = true;
83  return -1;
84  }
85 #ifdef MODULE_Battery_BUILTIN
86  module_enabled = true;
87 #else
88  uint8_t module_state[MODULESETTINGS_ADMINSTATE_NUMELEM];
89  ModuleSettingsAdminStateGet(module_state);
90  if (module_state[MODULESETTINGS_ADMINSTATE_BATTERY] == MODULESETTINGS_ADMINSTATE_ENABLED) {
91  module_enabled = true;
92  } else {
93  module_enabled = false;
94  return 0;
95  }
96 #endif
97  if (FlightBatteryStateInitialize() == -1) {
98  module_enabled = true;
99  return -1;
100  }
101 
102  return 0;
103 }
105 
106 
109 static void batteryTask(void * parameters)
110 {
111  const float dT = SAMPLE_PERIOD_MS / 1000.0f;
112 
114  bool cells_calculated = false;
115  int cells_holddown = 0;
116  unsigned cells = 1;
117 
118  FlightBatteryStateData flightBatteryData;
119  FlightBatterySettingsData batterySettings;
120 
121  FlightBatteryStateGet(&flightBatteryData);
122 
123  // Main task loop
124  uint32_t lastSysTime;
125  lastSysTime = PIOS_Thread_Systime();
126  while (true) {
128  float energyRemaining;
129 
131  battery_settings_updated = false;
132  FlightBatterySettingsGet(&batterySettings);
133 
134  voltageADCPin = batterySettings.VoltagePin;
135  if (voltageADCPin == FLIGHTBATTERYSETTINGS_VOLTAGEPIN_NONE)
136  voltageADCPin = -1;
137 
138  currentADCPin = batterySettings.CurrentPin;
139  if (currentADCPin == FLIGHTBATTERYSETTINGS_CURRENTPIN_NONE)
140  currentADCPin = -1;
141 
142  cells_calculated = false;
143  }
144 
145  bool adc_pin_invalid = false;
146  bool adc_offset_invalid = false;
147 
148  // handle voltage
149  if (voltageADCPin >= 0) {
150  float adc_voltage = (float)PIOS_ADC_GetChannelVolt(voltageADCPin);
151  float scaled_voltage = 0.0f;
152 
153  // A negative result indicates an error (PIOS_ADC_GetChannelVolt returns negative on error)
154  if(adc_voltage < 0.0f)
155  adc_pin_invalid = true;
156  else {
157  // scale to actual voltage
158  scaled_voltage = (adc_voltage * 1000.0f
159  / batterySettings.SensorCalibrationFactor[FLIGHTBATTERYSETTINGS_SENSORCALIBRATIONFACTOR_VOLTAGE])
160  + batterySettings.SensorCalibrationOffset[FLIGHTBATTERYSETTINGS_SENSORCALIBRATIONOFFSET_VOLTAGE]; //in Volts
161 
162  // disallow negative values as these are cast to unsigned integral types
163  // in some telemetry layers
164  if (scaled_voltage < 0.0f) {
165  scaled_voltage = 0.0f;
166  adc_offset_invalid = true;
167  } else if (batterySettings.MaxCellVoltage > 0.0f && scaled_voltage > 2.5f) {
168  if (!cells_calculated) {
169  cells = ((scaled_voltage / batterySettings.MaxCellVoltage) + 0.9f);
170  if (cells > 0) {
171  cells_holddown++;
172  } else {
173  cells_holddown = 0;
174  }
175 
176  if (cells_holddown >= (1000 / SAMPLE_PERIOD_MS)) {
177  cells_calculated = true;
178  flightBatteryData.DetectedCellCount = cells;
179  }
180  }
181  } else {
182  cells_calculated = false;
183  }
184 
185  if (!cells_calculated) {
186  cells = batterySettings.NbCells;
187  flightBatteryData.DetectedCellCount = 0;
188  }
189  }
190 
191  flightBatteryData.Voltage = scaled_voltage;
192 
193  // generate alarms and warnings
194  if (flightBatteryData.Voltage < (batterySettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_ALARM] * cells))
195  AlarmsSet(SYSTEMALARMS_ALARM_BATTERY, SYSTEMALARMS_ALARM_CRITICAL);
196  else if (flightBatteryData.Voltage < (batterySettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_WARNING] * cells))
197  AlarmsSet(SYSTEMALARMS_ALARM_BATTERY, SYSTEMALARMS_ALARM_WARNING);
198  else
199  AlarmsClear(SYSTEMALARMS_ALARM_BATTERY);
200  } else {
201  flightBatteryData.Voltage = 0;
202  }
203 
204  // handle current
205  if (currentADCPin >= 0) {
206  float adc_voltage = (float)PIOS_ADC_GetChannelVolt(currentADCPin);
207  float scaled_current = 0.0f;
208 
209  // A negative result indicates an error (PIOS_ADC_GetChannelVolt returns -1 on error)
210  if(adc_voltage < 0.0f)
211  adc_pin_invalid = true;
212  else {
213  // scale to actual current
214  scaled_current = (adc_voltage * 1000.0f
215  / batterySettings.SensorCalibrationFactor[FLIGHTBATTERYSETTINGS_SENSORCALIBRATIONFACTOR_CURRENT])
216  + batterySettings.SensorCalibrationOffset[FLIGHTBATTERYSETTINGS_SENSORCALIBRATIONOFFSET_CURRENT]; //in Amps
217 
218  // disallow negative values as these are cast to unsigned integral types
219  // in some telemetry layers
220  if(scaled_current < 0.0f) {
221  scaled_current = 0.0f;
222  adc_offset_invalid = true;
223  }
224  }
225 
226  flightBatteryData.Current = scaled_current;
227 
228  if (flightBatteryData.Current > flightBatteryData.PeakCurrent)
229  flightBatteryData.PeakCurrent = flightBatteryData.Current; //in Amps
230 
231  flightBatteryData.ConsumedEnergy += (flightBatteryData.Current * dT * 1000.0f / 3600.0f); //in mAh
232 
233  //Apply a 2 second rise time low-pass filter to average the current
234  float alpha = 1.0f - dT / (dT + 2.0f);
235  flightBatteryData.AvgCurrent = alpha * flightBatteryData.AvgCurrent + (1 - alpha) * flightBatteryData.Current; //in Amps
236 
237  // XXX Arguably this should be to 10% capacity or 15%
238  energyRemaining = batterySettings.Capacity - flightBatteryData.ConsumedEnergy; // in mAh
239 
240  // And for time estimation, smooth things much more.
241  // Second order since it incorporates the above
242  // smoothing, 12s time constant for this layer.
243  alpha = 1.0f - dT / (dT + 12.0f);
244 
245  avg_current_lpf_for_time = avg_current_lpf_for_time * alpha + (1 - alpha) * flightBatteryData.AvgCurrent;
246 
248  flightBatteryData.EstimatedFlightTime = (energyRemaining / (avg_current_lpf_for_time * 1000.0f)) * 3600.0f; //in Sec
249  else
250  flightBatteryData.EstimatedFlightTime = 9999;
251 
252  // generate alarms and warnings
253  if ((batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_FLIGHTTIMETHRESHOLDS_ALARM] > 0)
254  && (flightBatteryData.EstimatedFlightTime < batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_FLIGHTTIMETHRESHOLDS_ALARM]))
255  AlarmsSet(SYSTEMALARMS_ALARM_FLIGHTTIME, SYSTEMALARMS_ALARM_CRITICAL);
256  else if ((batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_FLIGHTTIMETHRESHOLDS_WARNING] > 0)
257  && (flightBatteryData.EstimatedFlightTime < batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_FLIGHTTIMETHRESHOLDS_WARNING]))
258  AlarmsSet(SYSTEMALARMS_ALARM_FLIGHTTIME, SYSTEMALARMS_ALARM_WARNING);
259  else
260  AlarmsClear(SYSTEMALARMS_ALARM_FLIGHTTIME);
261  } else {
262  flightBatteryData.Current = 0;
263  }
264 
265  if(adc_pin_invalid)
266  AlarmsSet(SYSTEMALARMS_ALARM_ADC, SYSTEMALARMS_ALARM_CRITICAL);
267  else if(adc_offset_invalid)
268  AlarmsSet(SYSTEMALARMS_ALARM_ADC, SYSTEMALARMS_ALARM_WARNING);
269  else if(voltageADCPin >= 0 || currentADCPin >= 0)
270  AlarmsSet(SYSTEMALARMS_ALARM_ADC, SYSTEMALARMS_ALARM_OK);
271  else
272  AlarmsSet(SYSTEMALARMS_ALARM_ADC, SYSTEMALARMS_ALARM_UNINITIALISED);
273 
274  FlightBatteryStateSet(&flightBatteryData);
275  }
276 }
277 
uint32_t PIOS_Thread_Systime(void)
Definition: pios_thread.c:212
static int8_t currentADCPin
Definition: battery.c:54
static int8_t voltageADCPin
Definition: battery.c:53
void UAVObjCbSetFlag(const UAVObjEvent *objEv, void *ctx, void *obj, int len)
int32_t AlarmsSet(SystemAlarmsAlarmElem alarm, SystemAlarmsAlarmOptions severity)
Definition: alarms.c:97
#define STACK_SIZE_BYTES
Definition: battery.c:45
static int32_t BatteryStart(void)
Definition: battery.c:63
#define SAMPLE_PERIOD_MS
Definition: battery.c:47
#define MODULE_INITCALL(ifn, sfn)
Definition: pios_initcall.h:67
static float avg_current_lpf_for_time
Definition: battery.c:57
static bool module_enabled
Definition: battery.c:51
static void batteryTask(void *parameters)
Definition: battery.c:109
struct pios_thread * PIOS_Thread_Create(void(*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio)
Definition: pios_thread.c:89
#define TASK_PRIORITY
Definition: battery.c:46
int32_t TaskMonitorAdd(TaskInfoRunningElem task, struct pios_thread *threadp)
Definition: taskmonitor.c:67
void PIOS_Thread_Sleep_Until(uint32_t *previous_ms, uint32_t increment_ms)
Definition: pios_thread.c:255
float PIOS_ADC_GetChannelVolt(uint32_t channel)
tuple f
Definition: px_mkfw.py:81
int32_t BatteryInitialize(void)
Definition: battery.c:79
Includes PiOS and core architecture components.
int32_t AlarmsClear(SystemAlarmsAlarmElem alarm)
Definition: alarms.c:171
static struct pios_thread * batteryTaskHandle
Definition: battery.c:52
static uint32_t lastSysTime
static bool battery_settings_updated
Definition: battery.c:55
if(BaroAltitudeHandle()!=NULL)