-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Second PT1 on DTerm #5427
Second PT1 on DTerm #5427
Changes from 3 commits
4fc43bf
e8e61b9
f00575e
d3014ff
c3f192e
1755544
decc92f
72676fb
d7fc099
4844e9b
aa42a69
416495e
0a2e5a5
2abcaeb
35f5e50
141d6ec
27bc23c
0d3ca7f
31b3959
eee15e7
f674b01
85b9223
dd25358
b286c06
c2898a4
b0e3da5
509d386
abe5b61
6056ee1
5be60dd
1a22d45
c9c26a0
b5a2805
2e2b0c4
fc6c0f8
be960ef
df382d8
b849b24
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,6 +105,7 @@ void resetPidProfile(pidProfile_t *pidProfile) | |
.pidSumLimitYaw = PIDSUM_LIMIT_YAW, | ||
.yaw_lpf_hz = 0, | ||
.dterm_lpf_hz = 100, // filtering ON by default | ||
.dterm_lpf2_hz = 0, // second Dterm LPF OFF by default | ||
.dterm_notch_hz = 260, | ||
.dterm_notch_cutoff = 160, | ||
.dterm_filter_type = FILTER_BIQUAD, | ||
|
@@ -167,28 +168,30 @@ void pidStabilisationState(pidStabilisationState_e pidControllerState) | |
|
||
const angle_index_t rcAliasToAngleIndexMap[] = { AI_ROLL, AI_PITCH }; | ||
|
||
static FAST_RAM filterApplyFnPtr dtermNotchFilterApplyFn; | ||
static FAST_RAM void *dtermFilterNotch[2]; | ||
static FAST_RAM filterApplyFnPtr dtermLpfApplyFn; | ||
static FAST_RAM void *dtermFilterLpf[2]; | ||
static FAST_RAM filterApplyFnPtr ptermYawFilterApplyFn; | ||
static FAST_RAM void *ptermYawFilter; | ||
static FAST_RAM filterApplyFnPtr dtermNotchApplyFn; | ||
static FAST_RAM void *dtermNotch[2]; | ||
static FAST_RAM filterApplyFnPtr dtermLowpassApplyFn; | ||
static FAST_RAM void *dtermLowpass[2]; | ||
static FAST_RAM filterApplyFnPtr dtermLowpass2ApplyFn; | ||
static FAST_RAM void *dtermLowpass2[2]; | ||
static FAST_RAM filterApplyFnPtr ptermYawLowpassApplyFn; | ||
static FAST_RAM void *ptermYawLowpass; | ||
|
||
typedef union dtermFilterLpf_u { | ||
typedef union dtermLowpass_u { | ||
pt1Filter_t pt1Filter[2]; | ||
biquadFilter_t biquadFilter[2]; | ||
firFilterDenoise_t denoisingFilter[2]; | ||
} dtermFilterLpf_t; | ||
} dtermLowpass_t; | ||
|
||
void pidInitFilters(const pidProfile_t *pidProfile) | ||
{ | ||
BUILD_BUG_ON(FD_YAW != 2); // only setting up Dterm filters on roll and pitch axes, so ensure yaw axis is 2 | ||
|
||
if (targetPidLooptime == 0) { | ||
// no looptime set, so set all the filters to null | ||
dtermNotchFilterApplyFn = nullFilterApply; | ||
dtermLpfApplyFn = nullFilterApply; | ||
ptermYawFilterApplyFn = nullFilterApply; | ||
dtermNotchApplyFn = nullFilterApply; | ||
dtermLowpassApplyFn = nullFilterApply; | ||
ptermYawLowpassApplyFn = nullFilterApply; | ||
return; | ||
} | ||
|
||
|
@@ -207,55 +210,67 @@ void pidInitFilters(const pidProfile_t *pidProfile) | |
|
||
if (dTermNotchHz != 0 && pidProfile->dterm_notch_cutoff != 0) { | ||
static biquadFilter_t biquadFilterNotch[2]; | ||
dtermNotchFilterApplyFn = (filterApplyFnPtr)biquadFilterApply; | ||
dtermNotchApplyFn = (filterApplyFnPtr)biquadFilterApply; | ||
const float notchQ = filterGetNotchQ(dTermNotchHz, pidProfile->dterm_notch_cutoff); | ||
for (int axis = FD_ROLL; axis <= FD_PITCH; axis++) { | ||
dtermFilterNotch[axis] = &biquadFilterNotch[axis]; | ||
biquadFilterInit(dtermFilterNotch[axis], dTermNotchHz, targetPidLooptime, notchQ, FILTER_NOTCH); | ||
dtermNotch[axis] = &biquadFilterNotch[axis]; | ||
biquadFilterInit(dtermNotch[axis], dTermNotchHz, targetPidLooptime, notchQ, FILTER_NOTCH); | ||
} | ||
} else { | ||
dtermNotchFilterApplyFn = nullFilterApply; | ||
dtermNotchApplyFn = nullFilterApply; | ||
} | ||
|
||
static dtermFilterLpf_t dtermFilterLpfUnion; | ||
|
||
//2nd Dterm Lowpass Filter | ||
static pt1Filter_t dtermLowpass2State; | ||
if (pidProfile->dterm_lpf2_hz == 0 || pidProfile->dterm_lpf2_hz > pidFrequencyNyquist) { | ||
dtermLowpass2ApplyFn = nullFilterApply; | ||
} else { | ||
dtermLowpass2ApplyFn = (filterApplyFnPtr)pt1FilterApply; | ||
for (int axis = FD_ROLL; axis <= FD_PITCH; axis++) { | ||
dtermLowpass2[axis] = &dtermLowpass2State; | ||
pt1FilterInit(dtermLowpass2[axis], pidProfile->dterm_lpf2_hz, dT); | ||
} | ||
} | ||
|
||
static dtermLowpass_t dtermLowpassUnion; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, this effectively makes state shared for all axes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK I just did some re-naming, that's all, to 'dtermLowpass2State' from previous name of 'pt1FilterD', as suggested by Fujin. The code itself is copied from yaw p lowpass further down. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I checked, I've just used exactly the same method as for the yaw code and the other filter code as in release 3.3. Hope there's nothing fundamentally wrong, but if there is, we will need to fix it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yaw is just one axis, so it's not shared by definition. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Have a look at how it's done in Fujin's PR for gyro lowpass, you need to create state for PID filters in advance. I can help when I get home There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ctzsnooze : the problem is here: https://github.com/betaflight/betaflight/pull/5427/files#r173423911 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK sorry I have to wait for actual code suggestion, too dumb to know how to do that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would this work better?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dtermLowpass_t contains 2-element arrays for filter state (roll+pitch) Use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just pushed this, hope it is now OK? Basically same structure as the preceding dterm notch.
|
||
if (pidProfile->dterm_lpf_hz == 0 || pidProfile->dterm_lpf_hz > pidFrequencyNyquist) { | ||
dtermLpfApplyFn = nullFilterApply; | ||
dtermLowpassApplyFn = nullFilterApply; | ||
} else { | ||
switch (pidProfile->dterm_filter_type) { | ||
default: | ||
dtermLpfApplyFn = nullFilterApply; | ||
dtermLowpassApplyFn = nullFilterApply; | ||
break; | ||
case FILTER_PT1: | ||
dtermLpfApplyFn = (filterApplyFnPtr)pt1FilterApply; | ||
dtermLowpassApplyFn = (filterApplyFnPtr)pt1FilterApply; | ||
for (int axis = FD_ROLL; axis <= FD_PITCH; axis++) { | ||
dtermFilterLpf[axis] = &dtermFilterLpfUnion.pt1Filter[axis]; | ||
pt1FilterInit(dtermFilterLpf[axis], pidProfile->dterm_lpf_hz, dT); | ||
dtermLowpass[axis] = &dtermLowpassUnion.pt1Filter[axis]; | ||
pt1FilterInit(dtermLowpass[axis], pidProfile->dterm_lpf_hz, dT); | ||
} | ||
break; | ||
case FILTER_BIQUAD: | ||
dtermLpfApplyFn = (filterApplyFnPtr)biquadFilterApply; | ||
dtermLowpassApplyFn = (filterApplyFnPtr)biquadFilterApply; | ||
for (int axis = FD_ROLL; axis <= FD_PITCH; axis++) { | ||
dtermFilterLpf[axis] = &dtermFilterLpfUnion.biquadFilter[axis]; | ||
biquadFilterInitLPF(dtermFilterLpf[axis], pidProfile->dterm_lpf_hz, targetPidLooptime); | ||
dtermLowpass[axis] = &dtermLowpassUnion.biquadFilter[axis]; | ||
biquadFilterInitLPF(dtermLowpass[axis], pidProfile->dterm_lpf_hz, targetPidLooptime); | ||
} | ||
break; | ||
case FILTER_FIR: | ||
dtermLpfApplyFn = (filterApplyFnPtr)firFilterDenoiseUpdate; | ||
dtermLowpassApplyFn = (filterApplyFnPtr)firFilterDenoiseUpdate; | ||
for (int axis = FD_ROLL; axis <= FD_PITCH; axis++) { | ||
dtermFilterLpf[axis] = &dtermFilterLpfUnion.denoisingFilter[axis]; | ||
firFilterDenoiseInit(dtermFilterLpf[axis], pidProfile->dterm_lpf_hz, targetPidLooptime); | ||
dtermLowpass[axis] = &dtermLowpassUnion.denoisingFilter[axis]; | ||
firFilterDenoiseInit(dtermLowpass[axis], pidProfile->dterm_lpf_hz, targetPidLooptime); | ||
} | ||
break; | ||
} | ||
} | ||
|
||
static pt1Filter_t pt1FilterYaw; | ||
static pt1Filter_t pt1LowpassYaw; | ||
if (pidProfile->yaw_lpf_hz == 0 || pidProfile->yaw_lpf_hz > pidFrequencyNyquist) { | ||
ptermYawFilterApplyFn = nullFilterApply; | ||
ptermYawLowpassApplyFn = nullFilterApply; | ||
} else { | ||
ptermYawFilterApplyFn = (filterApplyFnPtr)pt1FilterApply; | ||
ptermYawFilter = &pt1FilterYaw; | ||
pt1FilterInit(ptermYawFilter, pidProfile->yaw_lpf_hz, dT); | ||
ptermYawLowpassApplyFn = (filterApplyFnPtr)pt1FilterApply; | ||
ptermYawLowpass = &pt1LowpassYaw; | ||
pt1FilterInit(ptermYawLowpass, pidProfile->yaw_lpf_hz, dT); | ||
} | ||
} | ||
|
||
|
@@ -494,7 +509,7 @@ void pidController(const pidProfile_t *pidProfile, const rollAndPitchTrims_t *an | |
// -----calculate P component and add Dynamic Part based on stick input | ||
axisPID_P[axis] = Kp[axis] * errorRate * tpaFactor; | ||
if (axis == FD_YAW) { | ||
axisPID_P[axis] = ptermYawFilterApplyFn(ptermYawFilter, axisPID_P[axis]); | ||
axisPID_P[axis] = ptermYawLowpassApplyFn(ptermYawLowpass, axisPID_P[axis]); | ||
} | ||
|
||
// -----calculate I component | ||
|
@@ -509,10 +524,11 @@ void pidController(const pidProfile_t *pidProfile, const rollAndPitchTrims_t *an | |
// -----calculate D component | ||
if (axis != FD_YAW) { | ||
// apply filters | ||
float gyroRateFiltered = dtermNotchFilterApplyFn(dtermFilterNotch[axis], gyroRate); | ||
gyroRateFiltered = dtermLpfApplyFn(dtermFilterLpf[axis], gyroRateFiltered); | ||
float gyroRateFiltered = dtermNotchApplyFn(dtermNotch[axis], gyroRate); | ||
gyroRateFiltered = dtermLowpassApplyFn(dtermLowpass[axis], gyroRateFiltered); | ||
gyroRateFiltered = dtermLowpass2ApplyFn(dtermLowpass2[axis], gyroRateFiltered); | ||
|
||
const float rD = dynCd * MIN(getRcDeflectionAbs(axis) * relaxFactor, 1.0f) * currentPidSetpoint - gyroRateFiltered; // cr - y | ||
const float rD = dynCd * MIN(getRcDeflectionAbs(axis) * relaxFactor, 1.0f) * currentPidSetpoint - gyroRateFiltered; // cr - y | ||
// Divide rate change by deltaT to get differential (ie dr/dt) | ||
float delta = (rD - previousRateError[axis]) / deltaT; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -637,7 +637,8 @@ const clivalue_t valueTable[] = { | |
|
||
// PG_PID_PROFILE | ||
{ "dterm_lowpass_type", VAR_UINT8 | PROFILE_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_LOWPASS_TYPE }, PG_PID_PROFILE, offsetof(pidProfile_t, dterm_filter_type) }, | ||
{ "dterm_lowpass", VAR_INT16 | PROFILE_VALUE, .config.minmax = { 0, 16000 }, PG_PID_PROFILE, offsetof(pidProfile_t, dterm_lpf_hz) }, | ||
{ "dterm_lowpass_hz", VAR_INT16 | PROFILE_VALUE, .config.minmax = { 0, 16000 }, PG_PID_PROFILE, offsetof(pidProfile_t, dterm_lpf_hz) }, | ||
{ "dterm_lowpass2_hz", VAR_INT16 | PROFILE_VALUE, .config.minmax = { 0, 16000 }, PG_PID_PROFILE, offsetof(pidProfile_t, dterm_lpf2_hz) }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like there's a redundant indent :) |
||
{ "dterm_notch_hz", VAR_UINT16 | PROFILE_VALUE, .config.minmax = { 0, 16000 }, PG_PID_PROFILE, offsetof(pidProfile_t, dterm_notch_hz) }, | ||
{ "dterm_notch_cutoff", VAR_UINT16 | PROFILE_VALUE, .config.minmax = { 0, 16000 }, PG_PID_PROFILE, offsetof(pidProfile_t, dterm_notch_cutoff) }, | ||
{ "vbat_pid_gain", VAR_UINT8 | PROFILE_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_PID_PROFILE, offsetof(pidProfile_t, vbatPidCompensation) }, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This falls short of using the same state for all axes, just like @fujin's PR before