Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ardupilot
GitHub Repository: Ardupilot/ardupilot
Path: blob/master/libraries/AP_BattMonitor/AP_BattMonitor_Generator.cpp
9417 views
1
/*
2
This program is free software: you can redistribute it and/or modify
3
it under the terms of the GNU General Public License as published by
4
the Free Software Foundation, either version 3 of the License, or
5
(at your option) any later version.
6
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
11
12
You should have received a copy of the GNU General Public License
13
along with this program. If not, see <http://www.gnu.org/licenses/>.
14
*/
15
16
#include "AP_BattMonitor_config.h"
17
18
#if AP_BATTERY_GENERATOR_ENABLED
19
20
#include <AP_Common/AP_Common.h>
21
#include <AP_Math/AP_Math.h>
22
23
#include "AP_BattMonitor_Generator.h"
24
25
/*
26
Fuel class
27
*/
28
// This is where we tell the battery monitor 'we have current' if we want to report a fuel level remaining
29
bool AP_BattMonitor_Generator_FuelLevel::has_current(void) const
30
{
31
// If the generator has fuel remaining we must also state that we have current
32
return has_consumed_energy();
33
}
34
35
// This is where we tell the battery monitor 'we have consumed energy' if we want to report a fuel level remaining
36
bool AP_BattMonitor_Generator_FuelLevel::has_consumed_energy(void) const
37
{
38
// Get pointer to generator singleton
39
AP_Generator *generator = AP::generator();
40
41
if (generator == nullptr) {
42
return false;
43
}
44
45
// Use consumed_mAh in BattMonitor to display fuel remaining
46
return generator->has_consumed_energy();
47
}
48
49
bool AP_BattMonitor_Generator_FuelLevel::reset_remaining(float percentage)
50
{
51
// Get pointer to generator singleton
52
AP_Generator *generator = AP::generator();
53
54
if (generator == nullptr) {
55
return false;
56
}
57
58
if (generator->reset_consumed_energy()) {
59
percentage = constrain_float(percentage, 0.0, 100.0);
60
_initial_fuel_pct = percentage;
61
return true;
62
}
63
64
return false;
65
}
66
67
void AP_BattMonitor_Generator_FuelLevel::init()
68
{
69
}
70
71
// Read the fuel level. Should be called at 10hz
72
void AP_BattMonitor_Generator_FuelLevel::read()
73
{
74
_state.healthy = false;
75
76
// Get pointer to generator singleton
77
AP_Generator *generator = AP::generator();
78
79
// Not healthy if we can't find a generator
80
if (generator == nullptr) {
81
return;
82
}
83
84
if (!generator->healthy()) {
85
return;
86
}
87
88
if (generator->has_fuel_remaining()) {
89
// Set params for users:
90
// Fuel level is only reported as a percentage
91
_params._pack_capacity.set(100);
92
// Fuel only reports a fixed 1v, don't want batt monitor failsafes on this instance
93
_params._low_voltage.set(0);
94
_params._critical_voltage.set(0);
95
}
96
97
// As this is a battery monitor instance report voltage
98
// Report fixed voltage of 1V
99
_state.voltage = 1.0f;
100
101
// This is a bodge to display tank level as a percentage on GCS. Users should set _params.pack_capacity == 100 to get a clear percentage in GCS
102
if (generator->has_fuel_remaining()) {
103
_state.consumed_mah = (1 - generator->get_fuel_remaining()) * _params._pack_capacity.get();
104
} else {
105
_state.consumed_mah = generator->get_batt_consumed();
106
}
107
108
// If we got this far then must be healthy
109
_state.healthy = true;
110
_state.last_time_micros = AP_HAL::micros();
111
}
112
113
// capacity_remaining_ml - returns true if the capacity remaining in (mL) is valid and writes to capacity_ml
114
bool AP_BattMonitor_Generator_FuelLevel::capacity_remaining_ml(float &capacity_ml) const
115
{
116
// we consider anything under 10 ml as being an invalid capacity and so will be our measurement of remaining capacity
117
if ( _params._pack_capacity <= 10) {
118
return false;
119
}
120
121
// we get the initial fuel multiplying pack capacity parameter by initial fuel percentage.
122
// this initial fuel percentage will be 100% by default, but we can change it using the
123
// mavlink command MAV_CMD_BATTERY_RESET
124
const float initial_fuel = _params._pack_capacity * _initial_fuel_pct * 0.01;
125
126
// to get the actual remaining level we need to substract the consumed ml
127
capacity_ml = initial_fuel - _state.consumed_mah;
128
129
return true;
130
}
131
132
bool AP_BattMonitor_Generator_FuelLevel::capacity_remaining_pct(uint8_t &percentage) const
133
{
134
// Get pointer to generator singleton
135
AP_Generator *generator = AP::generator();
136
137
// If generator is not setup or not healthy, use the base class method
138
if (generator == nullptr) {
139
return AP_BattMonitor_Backend::capacity_remaining_pct(percentage);
140
}
141
142
if (!generator->healthy()) {
143
return AP_BattMonitor_Backend::capacity_remaining_pct(percentage);
144
}
145
146
// If generator doesn't have its own pct count, use ours
147
if (!generator->has_fuel_remaining()) {
148
float remaining_ml;
149
// return false if _params._pack_capacity is too small
150
if (!capacity_remaining_ml(remaining_ml)) {
151
return false;
152
}
153
154
// now we get the percentage according to tank capacity (pack_capacity parameter)
155
percentage = constrain_float(100 * remaining_ml / _params._pack_capacity, 0, UINT8_MAX);;
156
return true;
157
158
// Otherwise use generator's own percentage
159
} else {
160
percentage = generator->get_fuel_remaining() * 100; // convert from scale to actual percentage
161
return true;
162
}
163
}
164
165
AP_BattMonitor::Failsafe AP_BattMonitor_Generator_FuelLevel::update_failsafes()
166
{
167
AP_Generator *generator = AP::generator();
168
if (generator == nullptr) {
169
return AP_BattMonitor::Failsafe::None;
170
}
171
172
if (generator->has_fuel_remaining()) {
173
// work is being done for us by the generator
174
return AP_BattMonitor_Backend::update_failsafes();
175
}
176
177
// If we are using our own calculated percentage, not the one from
178
// the generator, manage capacity failsafes here
179
float remaining_ml;
180
// only returns false if _params._pack_capacity is too small less than 10 mL
181
if (!capacity_remaining_ml(remaining_ml)) {
182
return AP_BattMonitor::Failsafe::Critical;
183
}
184
185
if (remaining_ml < _params._critical_capacity) {
186
return AP_BattMonitor::Failsafe::Critical;
187
}
188
189
if (remaining_ml < _params._low_capacity) {
190
return AP_BattMonitor::Failsafe::Low;
191
}
192
193
return AP_BattMonitor::Failsafe::None;
194
}
195
196
/*
197
Electrical class
198
*/
199
bool AP_BattMonitor_Generator_Elec::has_current(void) const
200
{
201
// Get pointer to generator singleton
202
AP_Generator *generator = AP::generator();
203
204
if (generator == nullptr) {
205
return false;
206
}
207
208
return generator->has_current();
209
}
210
211
bool AP_BattMonitor_Generator_Elec::has_consumed_energy(void) const
212
{
213
// Get pointer to generator singleton
214
AP_Generator *generator = AP::generator();
215
216
if (generator == nullptr) {
217
return false;
218
}
219
220
return generator->has_consumed_energy();
221
}
222
223
// Read the electrical measurements from the generator
224
void AP_BattMonitor_Generator_Elec::read()
225
{
226
_state.healthy = false;
227
228
// Get pointer to generator singleton
229
AP_Generator *generator = AP::generator();
230
231
// Not healthy if we can't find a generator
232
if (generator == nullptr) {
233
return;
234
}
235
236
if (!generator->healthy()) {
237
return;
238
}
239
240
// Update readings
241
_state.voltage = generator->get_voltage();
242
243
_state.current_amps = generator->get_current();
244
245
// Always reset consumed value, integration is done in AP_Generator library
246
_state.consumed_mah = generator->get_batt_consumed();
247
_state.consumed_wh = 0.001f * _state.consumed_mah * _state.voltage;
248
249
// If we got this far then must be healthy
250
_state.healthy = true;
251
_state.last_time_micros = AP_HAL::micros();
252
}
253
254
AP_BattMonitor::Failsafe AP_BattMonitor_Generator_Elec::update_failsafes()
255
{
256
AP_BattMonitor::Failsafe failsafe = AP_BattMonitor::Failsafe::None;
257
258
AP_Generator *generator = AP::generator();
259
260
// Only check for failsafes on the electrical monitor
261
// no point in having the same failsafe on two battery monitors
262
if (generator != nullptr) {
263
failsafe = generator->update_failsafes();
264
}
265
return MAX(AP_BattMonitor_Backend::update_failsafes(), failsafe);
266
}
267
#endif // AP_BATTERY_GENERATOR_ENABLED
268
269