PX4 Firmware
PX4 Autopilot Software http://px4.io
battery.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2016 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file battery.cpp
36  *
37  * Library calls for battery functionality.
38  *
39  * @author Julian Oes <julian@oes.ch>
40  */
41 
42 #include "battery.h"
43 #include <mathlib/mathlib.h>
44 #include <cstring>
45 #include <px4_platform_common/defines.h>
46 
48  ModuleParams(nullptr),
49  _warning(battery_status_s::BATTERY_WARNING_NONE),
50  _last_timestamp(0)
51 {
52 }
53 
54 void
56 {
57  memset(battery_status, 0, sizeof(*battery_status));
58  battery_status->current_a = -1.f;
59  battery_status->remaining = 1.f;
60  battery_status->scale = 1.f;
61  battery_status->cell_count = _param_bat_n_cells.get();
62  // TODO: check if it is sane to reset warning to NONE
63  battery_status->warning = battery_status_s::BATTERY_WARNING_NONE;
64  battery_status->connected = false;
65 }
66 
67 void
68 Battery::updateBatteryStatus(hrt_abstime timestamp, float voltage_v, float current_a,
69  bool connected, bool selected_source, int priority,
70  float throttle_normalized,
72 {
73  reset(battery_status);
74  battery_status->timestamp = timestamp;
75  filterVoltage(voltage_v);
76  filterThrottle(throttle_normalized);
77  filterCurrent(current_a);
78  sumDischarged(timestamp, current_a);
80  computeScale();
81 
82  if (_battery_initialized) {
83  determineWarning(connected);
84  }
85 
86  if (_voltage_filtered_v > 2.1f) {
87  _battery_initialized = true;
88  battery_status->voltage_v = voltage_v;
89  battery_status->voltage_filtered_v = _voltage_filtered_v;
90  battery_status->scale = _scale;
91  battery_status->current_a = current_a;
92  battery_status->current_filtered_a = _current_filtered_a;
93  battery_status->discharged_mah = _discharged_mah;
94  battery_status->warning = _warning;
95  battery_status->remaining = _remaining;
96  battery_status->connected = connected;
97  battery_status->system_source = selected_source;
98  battery_status->priority = priority;
99  }
100 
101  battery_status->temperature = NAN;
102 }
103 
104 void
105 Battery::filterVoltage(float voltage_v)
106 {
107  if (!_battery_initialized) {
108  _voltage_filtered_v = voltage_v;
109  }
110 
111  // TODO: inspect that filter performance
112  const float filtered_next = _voltage_filtered_v * 0.99f + voltage_v * 0.01f;
113 
114  if (PX4_ISFINITE(filtered_next)) {
115  _voltage_filtered_v = filtered_next;
116  }
117 }
118 
119 void
120 Battery::filterCurrent(float current_a)
121 {
122  if (!_battery_initialized) {
123  _current_filtered_a = current_a;
124  }
125 
126  // ADC poll is at 100Hz, this will perform a low pass over approx 500ms
127  const float filtered_next = _current_filtered_a * 0.98f + current_a * 0.02f;
128 
129  if (PX4_ISFINITE(filtered_next)) {
130  _current_filtered_a = filtered_next;
131  }
132 }
133 
134 void Battery::filterThrottle(float throttle)
135 {
136  if (!_battery_initialized) {
137  _throttle_filtered = throttle;
138  }
139 
140  const float filtered_next = _throttle_filtered * 0.99f + throttle * 0.01f;
141 
142  if (PX4_ISFINITE(filtered_next)) {
143  _throttle_filtered = filtered_next;
144  }
145 }
146 
147 void
148 Battery::sumDischarged(hrt_abstime timestamp, float current_a)
149 {
150  // Not a valid measurement
151  if (current_a < 0.f) {
152  // Because the measurement was invalid we need to stop integration
153  // and re-initialize with the next valid measurement
154  _last_timestamp = 0;
155  return;
156  }
157 
158  // Ignore first update because we don't know dt.
159  if (_last_timestamp != 0) {
160  const float dt = (timestamp - _last_timestamp) / 1e6;
161  // mAh since last loop: (current[A] * 1000 = [mA]) * (dt[s] / 3600 = [h])
162  _discharged_mah_loop = (current_a * 1e3f) * (dt / 3600.f);
164  }
165 
166  _last_timestamp = timestamp;
167 }
168 
169 void
170 Battery::estimateRemaining(float voltage_v, float current_a, float throttle, bool armed)
171 {
172  // remaining battery capacity based on voltage
173  float cell_voltage = voltage_v / _param_bat_n_cells.get();
174 
175  // correct battery voltage locally for load drop to avoid estimation fluctuations
176  if (_param_bat_r_internal.get() >= 0.f) {
177  cell_voltage += _param_bat_r_internal.get() * current_a;
178 
179  } else {
180  // assume linear relation between throttle and voltage drop
181  cell_voltage += throttle * _param_bat_v_load_drop.get();
182  }
183 
184  _remaining_voltage = math::gradual(cell_voltage, _param_bat_v_empty.get(), _param_bat_v_charged.get(), 0.f, 1.f);
185 
186  // choose which quantity we're using for final reporting
187  if (_param_bat_capacity.get() > 0.f) {
188  // if battery capacity is known, fuse voltage measurement with used capacity
189  if (!_battery_initialized) {
190  // initialization of the estimation state
192 
193  } else {
194  // The lower the voltage the more adjust the estimate with it to avoid deep discharge
195  const float weight_v = 3e-4f * (1 - _remaining_voltage);
196  _remaining = (1 - weight_v) * _remaining + weight_v * _remaining_voltage;
197  // directly apply current capacity slope calculated using current
198  _remaining -= _discharged_mah_loop / _param_bat_capacity.get();
199  _remaining = math::max(_remaining, 0.f);
200  }
201 
202  } else {
203  // else use voltage
205  }
206 }
207 
208 void
210 {
211  if (connected) {
212  // propagate warning state only if the state is higher, otherwise remain in current warning state
213  if (_remaining < _param_bat_emergen_thr.get() || (_warning == battery_status_s::BATTERY_WARNING_EMERGENCY)) {
214  _warning = battery_status_s::BATTERY_WARNING_EMERGENCY;
215 
216  } else if (_remaining < _param_bat_crit_thr.get() || (_warning == battery_status_s::BATTERY_WARNING_CRITICAL)) {
217  _warning = battery_status_s::BATTERY_WARNING_CRITICAL;
218 
219  } else if (_remaining < _param_bat_low_thr.get() || (_warning == battery_status_s::BATTERY_WARNING_LOW)) {
220  _warning = battery_status_s::BATTERY_WARNING_LOW;
221  }
222  }
223 }
224 
225 void
227 {
228  const float voltage_range = (_param_bat_v_charged.get() - _param_bat_v_empty.get());
229 
230  // reusing capacity calculation to get single cell voltage before drop
231  const float bat_v = _param_bat_v_empty.get() + (voltage_range * _remaining_voltage);
232 
233  _scale = _param_bat_v_charged.get() / bat_v;
234 
235  if (_scale > 1.3f) { // Allow at most 30% compensation
236  _scale = 1.3f;
237 
238  } else if (!PX4_ISFINITE(_scale) || _scale < 1.f) { // Shouldn't ever be more than the power at full battery
239  _scale = 1.f;
240  }
241 }
float _discharged_mah
Definition: battery.h:114
float _scale
Definition: battery.h:118
float _current_filtered_a
Definition: battery.h:113
void filterThrottle(float throttle)
Definition: battery.cpp:134
float _throttle_filtered
Definition: battery.h:112
void reset(battery_status_s *battery_status)
Reset all battery stats and report invalid/nothing.
Definition: battery.cpp:55
hrt_abstime _last_timestamp
Definition: battery.h:120
float _discharged_mah_loop
Definition: battery.h:115
void sumDischarged(hrt_abstime timestamp, float current_a)
Definition: battery.cpp:148
Library calls for battery functionality.
float _remaining_voltage
normalized battery charge level remaining based on voltage
Definition: battery.h:116
const T gradual(const T &value, const T &x_low, const T &x_high, const T &y_low, const T &y_high)
Definition: Functions.hpp:139
void filterVoltage(float voltage_v)
Definition: battery.cpp:105
void estimateRemaining(float voltage_v, float current_a, float throttle, bool armed)
Definition: battery.cpp:170
static struct actuator_armed_s armed
Definition: Commander.cpp:139
void computeScale()
Definition: battery.cpp:226
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
void determineWarning(bool connected)
Definition: battery.cpp:209
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
Definition: drv_hrt.h:58
void updateBatteryStatus(hrt_abstime timestamp, float voltage_v, float current_a, bool connected, bool selected_source, int priority, float throttle_normalized, bool armed, battery_status_s *status)
Update current battery status message.
Definition: battery.cpp:68
float _remaining
normalized battery charge level, selected based on config param
Definition: battery.h:117
constexpr _Tp max(_Tp a, _Tp b)
Definition: Limits.hpp:60
float _voltage_filtered_v
Definition: battery.h:111
float dt
Definition: px4io.c:73
uint8_t _warning
Definition: battery.h:119
void filterCurrent(float current_a)
Definition: battery.cpp:120
Battery()
Definition: battery.cpp:47