mc_pos_control: new velocity low pass and notch filter (optional, disabled by default)

- MPC_VEL_LP: new velocity first order low pass filter (off by default)
 - MPC_VEL_NF_FRQ/MPC_VEL_NF_BW: new velocity notch filter (off by default)
 - MPC_VELD_LP: existing velocity derivative low pass filter, but I've dropped the remaining controllib usage
This commit is contained in:
Daniel Agar
2024-06-18 11:47:19 -04:00
committed by GitHub
parent ac13fb77a9
commit 8b9900cce3
4 changed files with 141 additions and 32 deletions
@@ -42,14 +42,11 @@
using namespace matrix;
MulticopterPositionControl::MulticopterPositionControl(bool vtol) :
SuperBlock(nullptr, "MPC"),
ModuleParams(nullptr),
ScheduledWorkItem(MODULE_NAME, px4::wq_configurations::nav_and_controllers),
_vehicle_attitude_setpoint_pub(vtol ? ORB_ID(mc_virtual_attitude_setpoint) : ORB_ID(vehicle_attitude_setpoint)),
_vel_x_deriv(this, "VELD"),
_vel_y_deriv(this, "VELD"),
_vel_z_deriv(this, "VELD")
_vehicle_attitude_setpoint_pub(vtol ? ORB_ID(mc_virtual_attitude_setpoint) : ORB_ID(vehicle_attitude_setpoint))
{
_sample_interval_s.update(0.01f); // 100 Hz default
parameters_update(true);
_tilt_limit_slew_rate.setSlewRate(.2f);
_takeoff_status_pub.advertise();
@@ -83,7 +80,42 @@ void MulticopterPositionControl::parameters_update(bool force)
// update parameters from storage
ModuleParams::updateParams();
SuperBlock::updateParams();
float sample_freq_hz = 1.f / _sample_interval_s.mean();
// velocity notch filter
if ((_param_mpc_vel_nf_frq.get() > 0.f) && (_param_mpc_vel_nf_bw.get() > 0.f)) {
_vel_xy_notch_filter.setParameters(sample_freq_hz, _param_mpc_vel_nf_frq.get(), _param_mpc_vel_nf_bw.get());
_vel_z_notch_filter.setParameters(sample_freq_hz, _param_mpc_vel_nf_frq.get(), _param_mpc_vel_nf_bw.get());
} else {
_vel_xy_notch_filter.disable();
_vel_z_notch_filter.disable();
}
// velocity xy/z low pass filter
if (_param_mpc_vel_lp.get() > 0.f) {
_vel_xy_lp_filter.setCutoffFreq(sample_freq_hz, _param_mpc_vel_lp.get());
_vel_z_lp_filter.setCutoffFreq(sample_freq_hz, _param_mpc_vel_lp.get());
} else {
// disable filtering
_vel_xy_lp_filter.setAlpha(1.f);
_vel_z_lp_filter.setAlpha(1.f);
}
// velocity derivative xy/z low pass filter
if (_param_mpc_veld_lp.get() > 0.f) {
_vel_deriv_xy_lp_filter.setCutoffFreq(sample_freq_hz, _param_mpc_veld_lp.get());
_vel_deriv_z_lp_filter.setCutoffFreq(sample_freq_hz, _param_mpc_veld_lp.get());
} else {
// disable filtering
_vel_deriv_xy_lp_filter.setAlpha(1.f);
_vel_deriv_z_lp_filter.setAlpha(1.f);
}
int num_changed = 0;
@@ -276,7 +308,7 @@ void MulticopterPositionControl::parameters_update(bool force)
}
PositionControlStates MulticopterPositionControl::set_vehicle_states(const vehicle_local_position_s
&vehicle_local_position)
&vehicle_local_position, const float dt_s)
{
PositionControlStates states;
@@ -300,29 +332,42 @@ PositionControlStates MulticopterPositionControl::set_vehicle_states(const vehic
const Vector2f velocity_xy(vehicle_local_position.vx, vehicle_local_position.vy);
if (vehicle_local_position.v_xy_valid && velocity_xy.isAllFinite()) {
states.velocity.xy() = velocity_xy;
states.acceleration(0) = _vel_x_deriv.update(velocity_xy(0));
states.acceleration(1) = _vel_y_deriv.update(velocity_xy(1));
const Vector2f vel_xy_prev = _vel_xy_lp_filter.getState();
// vel xy notch filter, then low pass filter
states.velocity.xy() = _vel_xy_lp_filter.update(_vel_xy_notch_filter.apply(velocity_xy));
// vel xy derivative low pass filter
states.acceleration.xy() = _vel_deriv_xy_lp_filter.update((_vel_xy_lp_filter.getState() - vel_xy_prev) / dt_s);
} else {
states.velocity(0) = states.velocity(1) = NAN;
states.acceleration(0) = states.acceleration(1) = NAN;
// reset derivatives to prevent acceleration spikes when regaining velocity
_vel_x_deriv.reset();
_vel_y_deriv.reset();
// reset filters to prevent acceleration spikes when regaining velocity
_vel_xy_lp_filter.reset({});
_vel_xy_notch_filter.reset();
_vel_deriv_xy_lp_filter.reset({});
}
if (PX4_ISFINITE(vehicle_local_position.vz) && vehicle_local_position.v_z_valid) {
states.velocity(2) = vehicle_local_position.vz;
states.acceleration(2) = _vel_z_deriv.update(states.velocity(2));
const float vel_z_prev = _vel_z_lp_filter.getState();
// vel z notch filter, then low pass filter
states.velocity(2) = _vel_z_lp_filter.update(_vel_z_notch_filter.apply(vehicle_local_position.vz));
// vel z derivative low pass filter
states.acceleration(2) = _vel_deriv_z_lp_filter.update((_vel_z_lp_filter.getState() - vel_z_prev) / dt_s);
} else {
states.velocity(2) = NAN;
states.acceleration(2) = NAN;
// reset derivative to prevent acceleration spikes when regaining velocity
_vel_z_deriv.reset();
// reset filters to prevent acceleration spikes when regaining velocity
_vel_z_lp_filter.reset({});
_vel_z_notch_filter.reset();
_vel_deriv_z_lp_filter.reset({});
}
states.yaw = vehicle_local_position.heading;
@@ -351,8 +396,7 @@ void MulticopterPositionControl::Run()
math::constrain(((vehicle_local_position.timestamp_sample - _time_stamp_last_loop) * 1e-6f), 0.002f, 0.04f);
_time_stamp_last_loop = vehicle_local_position.timestamp_sample;
// set _dt in controllib Block for BlockDerivative
setDt(dt);
_sample_interval_s.update(dt);
if (_vehicle_control_mode_sub.updated()) {
const bool previous_position_control_enabled = _vehicle_control_mode.flag_multicopter_position_control_enabled;
@@ -380,7 +424,7 @@ void MulticopterPositionControl::Run()
}
}
PositionControlStates states{set_vehicle_states(vehicle_local_position)};
PositionControlStates states{set_vehicle_states(vehicle_local_position, dt)};
// if a goto setpoint available this publishes a trajectory setpoint to go there
if (_goto_control.checkForSetpoint(vehicle_local_position.timestamp_sample,
@@ -638,12 +682,13 @@ void MulticopterPositionControl::adjustSetpointForEKFResets(const vehicle_local_
}
if (vehicle_local_position.vxy_reset_counter != _vxy_reset_counter) {
_vel_x_deriv.reset();
_vel_y_deriv.reset();
_vel_xy_lp_filter.reset(_vel_xy_lp_filter.getState() + Vector2f(vehicle_local_position.delta_vxy));
_vel_xy_notch_filter.reset();
}
if (vehicle_local_position.vz_reset_counter != _vz_reset_counter) {
_vel_z_deriv.reset();
_vel_z_lp_filter.reset(_vel_z_lp_filter.getState() + vehicle_local_position.delta_vz);
_vel_z_notch_filter.reset();
}
// save latest reset counters