15#define SOC_REST_TAU 2.0f
16#define SOC_V_TAU 10.0f
17#define SOC_CORR_TAU 600.0f
18#define I_SLOW_TAU 10.0f
37 3.27f, 3.61f, 3.69f, 3.71f, 3.73f, 3.75f, 3.77f, 3.79f, 3.80f, 3.82f, 3.84f,
38 3.85f, 3.87f, 3.91f, 3.95f, 3.98f, 4.02f, 4.08f, 4.11f, 4.15f, 4.20f
43 if (!(v >
k_ocv[0]))
return 0.0f;
44 if (v >=
k_ocv[20])
return 1.0f;
45 for (
int k = 1; k <= 20; ++k) {
48 return 0.05f * ((float)(k - 1) + f);
54static float lpf(
float y,
float x,
float dt,
float tau) {
return y + (x - y) * (dt / (tau + dt)); }
55static float clamp01(
float v) {
return v < 0.0f ? 0.0f : (v > 1.0f ? 1.0f : v); }
63 memset(&
s, 0,
sizeof s);
86 for (
int tries = 0; tries < 8; ++tries) {
87 const uint32_t s0 =
s_seq;
88 if (s0 & 1u)
continue;
92 if (
s_seq == s0) { *out = v;
return; }
128 const float di = mi -
s_pi;
130 const float r = -(mv -
s_pv) / di / (
float)
s.
cells;
131 if (r > 0.002f && r < 0.5f)
s.
r_cell = 0.9f *
s.
r_cell + 0.1f * r;
147 const float dt = (float)dt_ms * 1e-3f;
168 if (
L->cells >= 1u &&
L->cells <= 6u)
s.
cells =
L->cells;
171 s.
cells = (uint8_t)(
n < 1 ? 1 : (
n > 6 ? 6 :
n));
175 const float n = (float)
s.
cells;
176 const float cell =
s.
vbat /
n;
182 const float thr[4] = { 0.0f,
L->warn,
L->crit,
L->emerg };
183 for (uint8_t k = 1u; k <= 3u; ++k) {
202 }
else if (counting) {
209 s.
pct = (uint8_t)(
s.
soc * 100.0f + 0.5f);
212 if (armed && counting &&
s_i_slow > 0.2f) {
void batt_init(const batt_cfg_t *cfg)
static const float k_ocv[21]
static uint8_t level_of(float cv, const batt_limits_t *L, float hyst)
float batt_soc_from_ocv(float v)
LiPo open-circuit voltage → state of charge 0…1 (exposed for the tests)
static float s_used_anchor
static void publish(void)
static uint32_t s_below_ms[4]
static void r_estimate(float v, float i, uint32_t dt)
static uint32_t s_recover_ms
static uint32_t s_absent_ms
static float lpf(float y, float x, float dt, float tau)
static void lost_battery(void)
void batt_read(batt_state_t *out)
seqlock snapshot for other tasks; keeps *out on a race
const batt_state_t * batt_state(void)
state as computed by the last step (same context)
static float clamp01(float v)
static uint8_t s_have_anchor
void batt_get_cfg(batt_cfg_t *out)
static uint32_t s_present_ms
static float s_soc_anchor
static volatile uint32_t s_seq
void batt_set_scales(float sv, float si)
void batt_step(float pin_v, float cur_pin_v, uint32_t dt_ms, uint8_t armed, const batt_limits_t *L)
one sample: pin voltages, time step, armed flag (flight-control context)
static batt_state_t s_pub
Battery monitor: voltage, current, consumed charge, cell count, state of charge, flight time left and...
#define BATT_PRESENT_V
pack above this = battery connected
#define BATT_CELL_DETECT_V
max cell voltage used to count cells
#define BATT_RESERVE_SOC
charge kept for landing (remain)
#define BATT_RECOVER_MS
disarmed, above threshold + hyst
#define BATT_LEVEL_MS
below a threshold this long -> level
#define BATT_RECOVER_HYST
V/cell
#define BATT_R_CELL_DEFAULT
Ω per cell before any estimate
ACwing Pilot app protocol v2: identifiers and frame layouts.
Lock-free single-producer single-consumer queue of fixed-size items.
float sens_v_per_a
current sensor gain, V/A
uint8_t has_current
a current sensor is wired
float scale_i
current multiplier (1 = nominal sensor)
float scale_v
×10 divider ratio (110 = ×11)
thresholds and settings (from the parameters)
uint8_t level
PV2_BATT_OK / LOW / CRITICAL / EMERGENCY
uint8_t cells
0 = not known
uint8_t present
a battery is connected
float remain_s
s of flight left, < 0 = n/a
float vbat_raw
V, last sample, unfiltered (calibration)
float current
A, filtered (τ 0.05 s); 0 without a sensor
float vbat
V, pack, filtered (τ 0.1 s)
float r_cell
Ω per cell, estimate
float used_mah
since power-on
float cell_v
V, sagged, filtered (τ 0.5 s): failsafes, CHECKS.
float cell_rest_v
V, sag compensated: state of charge