Skip to content

Commit af7db95

Browse files
committed
althold init
1 parent 4b1cb64 commit af7db95

File tree

11 files changed

+166
-45
lines changed

11 files changed

+166
-45
lines changed

lib/Espfc/src/Connect/MspProcessor.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -271,13 +271,14 @@ void MspProcessor::processCommand(MspMessage& m, MspResponse& r, Device::SerialD
271271
break;
272272

273273
case MSP_BOXNAMES:
274-
r.writeString(F("ARM;ANGLE;AIRMODE;BEEPER;FAILSAFE;BLACKBOX;BLACKBOXERASE;"));
274+
r.writeString(F("ARM;AIRMODE;ANGLE;ALTHOLD;BEEPER;FAILSAFE;BLACKBOX;BLACKBOXERASE;"));
275275
break;
276276

277277
case MSP_BOXIDS:
278278
r.writeU8(MODE_ARMED);
279-
r.writeU8(MODE_ANGLE);
280279
r.writeU8(MODE_AIRMODE);
280+
r.writeU8(MODE_ANGLE);
281+
r.writeU8(MODE_ALTHOLD);
281282
r.writeU8(MODE_BUZZER);
282283
r.writeU8(MODE_FAILSAFE);
283284
r.writeU8(MODE_BLACKBOX);
@@ -1419,7 +1420,12 @@ void MspProcessor::processCommand(MspMessage& m, MspResponse& r, Device::SerialD
14191420
disableRunawayTakeoff = m.readU8();
14201421
}
14211422
(void)disableRunawayTakeoff;
1422-
_model.setArmingDisabled(ARMING_DISABLED_MSP, cmd);
1423+
#if defined(ESPFC_DEV_PRESET_UNSAFE_ARMING)
1424+
(void)cmd;
1425+
#warning "Danger macro used ESPFC_DEV_PRESET_UNSAFE_ARMING"
1426+
#else
1427+
_model.setArmingDisabled(ARMING_DISABLED_MSP, cmd);
1428+
#endif
14231429
if (_model.isModeActive(MODE_ARMED)) _model.disarm(DISARM_REASON_ARMING_DISABLED);
14241430
}
14251431
break;

lib/Espfc/src/Control/Actuator.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ bool Actuator::canActivateMode(FlightMode mode)
154154
return _model.accelActive();
155155
case MODE_AIRMODE:
156156
return _model.state.mode.airmodeAllowed;
157+
case MODE_ALTHOLD:
158+
return _model.state.baro.dev;
157159
default:
158160
return true;
159161
}

lib/Espfc/src/Control/Altitude.hpp

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#pragma once
2+
3+
#include "Model.h"
4+
5+
namespace Espfc::Control {
6+
7+
class Altitude
8+
{
9+
public:
10+
Altitude(Model& model): _model(model) {}
11+
12+
int begin()
13+
{
14+
_model.state.altitude.height = 0.0f;
15+
_model.state.altitude.heightPrev = 0.0f;
16+
_model.state.altitude.rate = 0.0f;
17+
18+
return 1;
19+
}
20+
21+
int update()
22+
{
23+
// initialy use baro altitude only, in feature mix with other sources according to trust level
24+
_model.state.altitude.height = _model.state.altitude.height + _model.state.baro.altitude;
25+
_model.state.altitude.rate = (_model.state.altitude.height - _model.state.altitude.heightPrev) * _model.state.loopTimer.rate;
26+
_model.state.altitude.heightPrev = _model.state.altitude.height;
27+
28+
return 1;
29+
}
30+
31+
private:
32+
Model& _model;
33+
};
34+
35+
}

lib/Espfc/src/Control/Controller.cpp

+85-32
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ namespace Espfc {
55

66
namespace Control {
77

8-
Controller::Controller(Model& model): _model(model) {}
8+
Controller::Controller(Model& model): _model(model), _altitude(model) {}
99

1010
int Controller::begin()
1111
{
1212
_rates.begin(_model.config.input);
1313
_speedFilter.begin(FilterConfig(FILTER_BIQUAD, 10), _model.state.loopTimer.rate);
14+
_altitude.begin();
1415
return 1;
1516
}
1617

@@ -25,26 +26,31 @@ int FAST_CODE_ATTR Controller::update()
2526

2627
{
2728
Utils::Stats::Measure(_model.state.stats, COUNTER_OUTER_PID);
29+
_altitude.update();
2830
resetIterm();
29-
if(_model.config.mixer.type == FC_MIXER_GIMBAL)
31+
switch(_model.config.mixer.type)
3032
{
31-
outerLoopRobot();
32-
}
33-
else
34-
{
35-
outerLoop();
33+
case FC_MIXER_GIMBAL:
34+
outerLoopRobot();
35+
break;
36+
37+
default:
38+
outerLoop();
39+
break;
3640
}
3741
}
3842

3943
{
4044
Utils::Stats::Measure(_model.state.stats, COUNTER_INNER_PID);
41-
if(_model.config.mixer.type == FC_MIXER_GIMBAL)
42-
{
43-
innerLoopRobot();
44-
}
45-
else
45+
switch(_model.config.mixer.type)
4646
{
47-
innerLoop();
47+
case FC_MIXER_GIMBAL:
48+
innerLoopRobot();
49+
break;
50+
51+
default:
52+
innerLoop();
53+
break;
4854
}
4955
}
5056

@@ -110,27 +116,44 @@ void Controller::innerLoopRobot()
110116

111117
void FAST_CODE_ATTR Controller::outerLoop()
112118
{
119+
// Roll/Pitch rates control
113120
if(_model.isModeActive(MODE_ANGLE))
114121
{
115-
_model.state.setpoint.angle = VectorFloat(
116-
_model.state.input.ch[AXIS_ROLL] * Utils::toRad(_model.config.level.angleLimit),
117-
_model.state.input.ch[AXIS_PITCH] * Utils::toRad(_model.config.level.angleLimit),
118-
_model.state.attitude.euler[AXIS_YAW]
119-
);
120-
_model.state.setpoint.rate[AXIS_ROLL] = _model.state.outerPid[AXIS_ROLL].update(_model.state.setpoint.angle[AXIS_ROLL], _model.state.attitude.euler[AXIS_ROLL]);
121-
_model.state.setpoint.rate[AXIS_PITCH] = _model.state.outerPid[AXIS_PITCH].update(_model.state.setpoint.angle[AXIS_PITCH], _model.state.attitude.euler[AXIS_PITCH]);
122-
// disable fterm in angle mode
123-
_model.state.innerPid[AXIS_ROLL].fScale = 0.f;
124-
_model.state.innerPid[AXIS_PITCH].fScale = 0.f;
122+
for(size_t i = 0; i < AXIS_COUNT_RP; i++)
123+
{
124+
const float angleSetpoint = Utils::toRad(_model.config.level.angleLimit) * _model.state.input.ch[i];
125+
_model.state.setpoint.rate[i] = _model.state.outerPid[i].update(angleSetpoint, _model.state.attitude.euler[i]);
126+
// disable fterm in angle mode
127+
_model.state.innerPid[i].fScale = 0.f;
128+
}
125129
}
126130
else
127131
{
128-
_model.state.setpoint.rate[AXIS_ROLL] = calculateSetpointRate(AXIS_ROLL, _model.state.input.ch[AXIS_ROLL]);
129-
_model.state.setpoint.rate[AXIS_PITCH] = calculateSetpointRate(AXIS_PITCH, _model.state.input.ch[AXIS_PITCH]);
132+
for(size_t i = 0; i < AXIS_COUNT_RP; i++)
133+
{
134+
_model.state.setpoint.rate[i] = calculateSetpointRate(i, _model.state.input.ch[i]);
135+
}
130136
}
137+
138+
// Yaw rates control
131139
_model.state.setpoint.rate[AXIS_YAW] = calculateSetpointRate(AXIS_YAW, _model.state.input.ch[AXIS_YAW]);
132-
_model.state.setpoint.rate[AXIS_THRUST] = _model.state.input.ch[AXIS_THRUST];
133140

141+
// thrust control
142+
if(_model.isModeActive(MODE_ALTHOLD))
143+
{
144+
_model.state.setpoint.rate[AXIS_THRUST] = calcualteAltHoldSetpoint();
145+
if(_model.config.debug.mode == DEBUG_ALTITUDE)
146+
{
147+
_model.state.debug[0] = lrintf(_model.state.input.ch[AXIS_THRUST] * 1000.0f);
148+
_model.state.debug[1] = lrintf(_model.state.setpoint.rate[AXIS_THRUST] * 1000.0f);
149+
}
150+
}
151+
else
152+
{
153+
_model.state.setpoint.rate[AXIS_THRUST] = _model.state.input.ch[AXIS_THRUST];
154+
}
155+
156+
// debug
134157
if(_model.config.debug.mode == DEBUG_ANGLERATE)
135158
{
136159
for(size_t i = 0; i < AXIS_COUNT_RPY; ++i)
@@ -142,14 +165,29 @@ void FAST_CODE_ATTR Controller::outerLoop()
142165

143166
void FAST_CODE_ATTR Controller::innerLoop()
144167
{
168+
// Roll/Pitch/Yaw rates control
145169
const float tpaFactor = getTpaFactor();
146170
for(size_t i = 0; i < AXIS_COUNT_RPY; ++i)
147171
{
148172
_model.state.output.ch[i] = _model.state.innerPid[i].update(_model.state.setpoint.rate[i], _model.state.gyro.adc[i]) * tpaFactor;
149-
//_model.state.debug[i] = lrintf(_model.state.innerPid[i].fTerm * 1000);
150173
}
151-
_model.state.output.ch[AXIS_THRUST] = _model.state.setpoint.rate[AXIS_THRUST];
152174

175+
// thrust control
176+
if(_model.isModeActive(MODE_ALTHOLD))
177+
{
178+
_model.state.output.ch[AXIS_THRUST] = _model.state.innerPid[AXIS_THRUST].update(_model.state.setpoint.rate[AXIS_THRUST], _model.state.altitude.rate);
179+
if(_model.config.debug.mode == DEBUG_ALTITUDE)
180+
{
181+
_model.state.debug[2] = lrintf(_model.state.output.ch[AXIS_THRUST] * 1000.0f);
182+
_model.state.debug[3] = lrintf(_model.state.innerPid[AXIS_THRUST].iTerm * 1000.0f);
183+
}
184+
}
185+
else
186+
{
187+
_model.state.output.ch[AXIS_THRUST] = _model.state.setpoint.rate[AXIS_THRUST];
188+
}
189+
190+
// debug
153191
if(_model.config.debug.mode == DEBUG_ITERM_RELAX)
154192
{
155193
_model.state.debug[0] = lrintf(Utils::toDeg(_model.state.innerPid[0].itermRelaxBase));
@@ -159,6 +197,17 @@ void FAST_CODE_ATTR Controller::innerLoop()
159197
}
160198
}
161199

200+
float Controller::calcualteAltHoldSetpoint() const
201+
{
202+
float thrust = _model.state.input.ch[AXIS_THRUST];
203+
204+
if(_model.isThrottleLow()) thrust = 0.0f; // stick below min check, no command
205+
206+
thrust = Utils::deadband(thrust, 0.125f); // +/- 12.5% deadband
207+
208+
return thrust * 0.5f; // climb/descend rate factor 0.5 m/s
209+
}
210+
162211
float Controller::getTpaFactor() const
163212
{
164213
if(_model.config.controller.tpaScale == 0) return 1.f;
@@ -172,15 +221,19 @@ void Controller::resetIterm()
172221
|| (!_model.isAirModeActive() && _model.config.iterm.lowThrottleZeroIterm && _model.isThrottleLow()) // on low throttle (not in air mode)
173222
)
174223
{
175-
for(size_t i = 0; i < AXIS_COUNT_RPYT; i++)
224+
for(size_t i = 0; i < AXIS_COUNT_RPY; i++)
176225
{
177-
_model.state.innerPid[i].iTerm = 0;
178-
_model.state.outerPid[i].iTerm = 0;
226+
_model.state.innerPid[i].iTerm = 0.0f;
227+
_model.state.outerPid[i].iTerm = 0.0f;
179228
}
180229
}
230+
if(!_model.isModeActive(MODE_ARMED))
231+
{
232+
_model.state.innerPid[AXIS_THRUST].iTerm = 0.0f;
233+
}
181234
}
182235

183-
float Controller::calculateSetpointRate(int axis, float input)
236+
float Controller::calculateSetpointRate(int axis, float input) const
184237
{
185238
if(axis == AXIS_YAW) input *= -1.f;
186239
return _rates.getSetpoint(axis, input);

lib/Espfc/src/Control/Controller.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "Model.h"
44
#include "Control/Rates.h"
5+
#include "Control/Altitude.hpp"
56

67
namespace Espfc {
78

@@ -21,10 +22,12 @@ class Controller
2122

2223
inline float getTpaFactor() const;
2324
inline void resetIterm();
24-
float calculateSetpointRate(int axis, float input);
25+
float calculateSetpointRate(int axis, float input) const;
26+
float calcualteAltHoldSetpoint() const;
2527

2628
private:
2729
Model& _model;
30+
Altitude _altitude;
2831
Rates _rates;
2932
Utils::Filter _speedFilter;
3033
};

lib/Espfc/src/Control/Fusion.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ int FAST_CODE_ATTR Fusion::update()
7272
}
7373
//else madgwickFusion1();
7474

75-
if(_model.config.debug.mode == DEBUG_ALTITUDE)
75+
if(_model.config.debug.mode == DEBUG_AC_CORRECTION)
7676
{
7777
_model.state.debug[0] = lrintf(Utils::toDeg(_model.state.attitude.euler[0]) * 10);
7878
_model.state.debug[1] = lrintf(Utils::toDeg(_model.state.attitude.euler[1]) * 10);

lib/Espfc/src/Control/Pid.h

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ constexpr float LEVEL_ITERM_SCALE = 0.1f; // 1/10
2222
constexpr float LEVEL_DTERM_SCALE = 0.001f; // 1/1000
2323
constexpr float LEVEL_FTERM_SCALE = 0.001f; // 1/1000
2424

25+
constexpr float VEL_PTERM_SCALE = 0.02f;
26+
constexpr float VEL_ITERM_SCALE = 0.01f;
27+
constexpr float VEL_DTERM_SCALE = 0.001f;
28+
2529
enum ItermRelaxType {
2630
ITERM_RELAX_OFF,
2731
ITERM_RELAX_RP,

lib/Espfc/src/Control/Rates.cpp

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
#include "Rates.h"
22
#include "Utils/MemoryHelper.h"
33

4-
namespace Espfc {
5-
6-
namespace Control {
4+
namespace Espfc::Control {
75

86
constexpr float SETPOINT_RATE_LIMIT = 1998.0f;
97
constexpr float RC_RATE_INCREMENTAL = 14.54f;
@@ -113,5 +111,3 @@ float FAST_CODE_ATTR Rates::quick(const int axis, float rcCommandf, const float
113111
}
114112

115113
}
116-
117-
}

lib/Espfc/src/Model.h

+12
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ class Model
155155
{
156156
#if defined(ESPFC_DEV_PRESET_UNSAFE_ARMING)
157157
return false;
158+
#warning "Danger macro used ESPFC_DEV_PRESET_UNSAFE_ARMING"
158159
#else
159160
return state.mode.armingDisabledFlags != 0;
160161
#endif
@@ -549,6 +550,17 @@ class Model
549550
}
550551
state.customMixer = MixerConfig(config.customMixerCount, config.customMixes);
551552

553+
PidConfig& pcav = config.pid[FC_PID_VEL];
554+
Control::Pid& pidav = state.innerPid[AXIS_THRUST];
555+
pidav.Kp = (float)pcav.P * VEL_PTERM_SCALE;
556+
pidav.Ki = (float)pcav.I * VEL_ITERM_SCALE;
557+
pidav.Kd = (float)pcav.D * VEL_DTERM_SCALE;
558+
pidav.Kf = 0.0f;
559+
pidav.iLimit = 0.6f;
560+
pidav.oLimit = 1.0f;
561+
pidav.rate = state.loopTimer.rate;
562+
pidav.begin();
563+
552564
// override temporary
553565
//state.telemetryTimer.setRate(100);
554566
}

lib/Espfc/src/ModelConfig.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,9 @@ struct FusionConfig
8181

8282
enum FlightMode {
8383
MODE_ARMED,
84-
MODE_ANGLE,
8584
MODE_AIRMODE,
85+
MODE_ANGLE,
86+
MODE_ALTHOLD,
8687
MODE_BUZZER,
8788
MODE_FAILSAFE,
8889
MODE_BLACKBOX,
@@ -411,8 +412,8 @@ struct InputConfig
411412
int8_t ppmMode = PPM_MODE_NORMAL;
412413
uint8_t serialRxProvider = SERIALRX_SBUS;
413414

414-
int16_t maxCheck = 1050;
415-
int16_t minCheck = 1900;
415+
int16_t minCheck = 1050;
416+
int16_t maxCheck = 1900;
416417
int16_t minRc = 885;
417418
int16_t midRc = 1500;
418419
int16_t maxRc = 2115;

lib/Espfc/src/ModelState.h

+9
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,13 @@ struct ModeState
320320
bool airmodeAllowed;
321321
};
322322

323+
struct AltitudeState
324+
{
325+
float height;
326+
float heightPrev;
327+
float rate;
328+
};
329+
323330
// runtime data
324331
struct ModelState
325332
{
@@ -334,6 +341,8 @@ struct ModelState
334341
AttitudeState attitude;
335342
RotationMatrixFloat boardAlignment;
336343

344+
AltitudeState altitude;
345+
337346
SetpointState setpoint;
338347
Control::Pid innerPid[AXIS_COUNT_RPYT];
339348
Control::Pid outerPid[AXIS_COUNT_RPYT];

0 commit comments

Comments
 (0)