CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
Ardupilot

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: Ardupilot/ardupilot
Path: blob/master/libraries/AP_BattMonitor/AP_BattMonitor_FuelFlow.cpp
Views: 1798
1
#include "AP_BattMonitor_config.h"
2
3
#if AP_BATTERY_FUELFLOW_ENABLED
4
5
#include "AP_BattMonitor_FuelFlow.h"
6
7
#include <AP_HAL/AP_HAL.h>
8
#include <GCS_MAVLink/GCS.h>
9
10
/*
11
"battery" monitor for liquid fuel flow systems that give a pulse on
12
a pin for fixed volumes of fuel.
13
14
this driver assumes that BATTx_AMP_PERVLT is set to give the
15
number of millilitres per pulse.
16
17
Output is:
18
19
- current in Amps maps to in litres/hour
20
- consumed mAh is in consumed millilitres
21
- fixed 1.0v voltage
22
*/
23
extern const AP_HAL::HAL& hal;
24
25
#define FUELFLOW_MIN_PULSE_DELTA_US 10
26
27
/// Constructor
28
AP_BattMonitor_FuelFlow::AP_BattMonitor_FuelFlow(AP_BattMonitor &mon,
29
AP_BattMonitor::BattMonitor_State &mon_state,
30
AP_BattMonitor_Params &params) :
31
AP_BattMonitor_Analog(mon, mon_state, params)
32
{
33
_state.voltage = 1.0; // show a fixed voltage of 1v
34
35
// we can't tell if it is healthy as we expect zero pulses when no
36
// fuel is flowing
37
_state.healthy = true;
38
}
39
40
/*
41
handle interrupt on an instance
42
*/
43
void AP_BattMonitor_FuelFlow::irq_handler(uint8_t pin, bool pin_state, uint32_t timestamp)
44
{
45
if (irq_state.last_pulse_us == 0) {
46
irq_state.last_pulse_us = timestamp;
47
return;
48
}
49
uint32_t delta = timestamp - irq_state.last_pulse_us;
50
if (delta < FUELFLOW_MIN_PULSE_DELTA_US) {
51
// simple de-bounce
52
return;
53
}
54
irq_state.pulse_count++;
55
irq_state.total_us += delta;
56
irq_state.last_pulse_us = timestamp;
57
}
58
59
/*
60
read - read the "voltage" and "current"
61
*/
62
void AP_BattMonitor_FuelFlow::read()
63
{
64
int8_t pin = _curr_pin;
65
if (last_pin != pin) {
66
// detach from last pin
67
if (last_pin != -1) {
68
hal.gpio->detach_interrupt(last_pin);
69
}
70
// attach to new pin
71
last_pin = pin;
72
if (last_pin > 0) {
73
hal.gpio->pinMode(last_pin, HAL_GPIO_INPUT);
74
if (!hal.gpio->attach_interrupt(
75
last_pin,
76
FUNCTOR_BIND_MEMBER(&AP_BattMonitor_FuelFlow::irq_handler, void, uint8_t, bool, uint32_t),
77
AP_HAL::GPIO::INTERRUPT_RISING)) {
78
GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "FuelFlow: Failed to attach to pin %u", last_pin);
79
}
80
}
81
}
82
83
uint32_t now_us = AP_HAL::micros();
84
if (_state.last_time_micros == 0) {
85
// need initial time, so we can work out expected pulse rate
86
_state.last_time_micros = now_us;
87
return;
88
}
89
float dt = (now_us - _state.last_time_micros) * 1.0e-6f;
90
91
if (dt < 1 && irq_state.pulse_count == 0) {
92
// we allow for up to 1 second with no pulses to cope with low
93
// flow idling. After that we will start reading zero current
94
return;
95
}
96
97
// get the IRQ state with interrupts disabled
98
struct IrqState state;
99
void *irqstate = hal.scheduler->disable_interrupts_save();
100
state = irq_state;
101
irq_state.pulse_count = 0;
102
irq_state.total_us = 0;
103
hal.scheduler->restore_interrupts(irqstate);
104
105
/*
106
this driver assumes that BATTx_AMP_PERVLT is set to give the
107
number of millilitres per pulse.
108
*/
109
float irq_dt = state.total_us * 1.0e-6f;
110
float litres, litres_pec_sec;
111
if (state.pulse_count == 0) {
112
litres = 0;
113
litres_pec_sec = 0;
114
} else {
115
litres = state.pulse_count * _curr_amp_per_volt * 0.001f;
116
litres_pec_sec = litres / irq_dt;
117
}
118
119
_state.last_time_micros = now_us;
120
121
// map amps to litres/hour
122
_state.current_amps = litres_pec_sec * (60*60);
123
124
// map consumed_mah to consumed millilitres
125
_state.consumed_mah += litres * 1000;
126
127
// map consumed_wh using fixed voltage of 1
128
_state.consumed_wh = _state.consumed_mah;
129
}
130
131
#endif // AP_BATTERY_FUELFLOW_ENABLED
132
133