mirror of https://github.com/ArduPilot/ardupilot
AC_AutoTune: combine dwell_run_test for angle and rate
This commit is contained in:
parent
68f0eb9e5d
commit
da7164c1e4
|
@ -155,11 +155,11 @@ void AC_AutoTune_Heli::test_init()
|
||||||
}
|
}
|
||||||
if (!is_equal(start_freq,stop_freq)) {
|
if (!is_equal(start_freq,stop_freq)) {
|
||||||
// initialize determine_gain function whenever test is initialized
|
// initialize determine_gain function whenever test is initialized
|
||||||
freqresp_rate.init(AC_AutoTune_FreqResp::InputType::SWEEP, AC_AutoTune_FreqResp::ResponseType::RATE);
|
freqresp.init(AC_AutoTune_FreqResp::InputType::SWEEP, AC_AutoTune_FreqResp::ResponseType::RATE);
|
||||||
dwell_test_init(start_freq, stop_freq, RATE);
|
dwell_test_init(start_freq, stop_freq, RATE);
|
||||||
} else {
|
} else {
|
||||||
// initialize determine_gain function whenever test is initialized
|
// initialize determine_gain function whenever test is initialized
|
||||||
freqresp_rate.init(AC_AutoTune_FreqResp::InputType::DWELL, AC_AutoTune_FreqResp::ResponseType::RATE);
|
freqresp.init(AC_AutoTune_FreqResp::InputType::DWELL, AC_AutoTune_FreqResp::ResponseType::RATE);
|
||||||
dwell_test_init(start_freq, start_freq, RATE);
|
dwell_test_init(start_freq, start_freq, RATE);
|
||||||
}
|
}
|
||||||
if (!is_zero(start_freq)) {
|
if (!is_zero(start_freq)) {
|
||||||
|
@ -185,11 +185,11 @@ void AC_AutoTune_Heli::test_init()
|
||||||
|
|
||||||
if (!is_equal(start_freq,stop_freq)) {
|
if (!is_equal(start_freq,stop_freq)) {
|
||||||
// initialize determine gain function
|
// initialize determine gain function
|
||||||
freqresp_angle.init(AC_AutoTune_FreqResp::InputType::SWEEP, AC_AutoTune_FreqResp::ResponseType::ANGLE);
|
freqresp.init(AC_AutoTune_FreqResp::InputType::SWEEP, AC_AutoTune_FreqResp::ResponseType::ANGLE);
|
||||||
dwell_test_init(start_freq, stop_freq, ANGLE);
|
dwell_test_init(start_freq, stop_freq, ANGLE);
|
||||||
} else {
|
} else {
|
||||||
// initialize determine gain function
|
// initialize determine gain function
|
||||||
freqresp_angle.init(AC_AutoTune_FreqResp::InputType::DWELL, AC_AutoTune_FreqResp::ResponseType::ANGLE);
|
freqresp.init(AC_AutoTune_FreqResp::InputType::DWELL, AC_AutoTune_FreqResp::ResponseType::ANGLE);
|
||||||
dwell_test_init(start_freq, start_freq, ANGLE);
|
dwell_test_init(start_freq, start_freq, ANGLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,13 +246,13 @@ void AC_AutoTune_Heli::test_run(AxisType test_axis, const float dir_sign)
|
||||||
break;
|
break;
|
||||||
case RP_UP:
|
case RP_UP:
|
||||||
case RD_UP:
|
case RD_UP:
|
||||||
dwell_test_run(1, start_freq, stop_freq, test_gain[freq_cnt], test_phase[freq_cnt]);
|
dwell_test_run(1, start_freq, stop_freq, test_gain[freq_cnt], test_phase[freq_cnt], RATE);
|
||||||
break;
|
break;
|
||||||
case MAX_GAINS:
|
case MAX_GAINS:
|
||||||
dwell_test_run(0, start_freq, stop_freq, test_gain[freq_cnt], test_phase[freq_cnt]);
|
dwell_test_run(0, start_freq, stop_freq, test_gain[freq_cnt], test_phase[freq_cnt], RATE);
|
||||||
break;
|
break;
|
||||||
case SP_UP:
|
case SP_UP:
|
||||||
angle_dwell_test_run(start_freq, stop_freq, test_gain[freq_cnt], test_phase[freq_cnt]);
|
dwell_test_run(1, start_freq, stop_freq, test_gain[freq_cnt], test_phase[freq_cnt], ANGLE);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
step = UPDATE_GAINS;
|
step = UPDATE_GAINS;
|
||||||
|
@ -996,230 +996,38 @@ void AC_AutoTune_Heli::dwell_test_init(float start_frq, float filt_freq, DwellTy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AC_AutoTune_Heli::dwell_test_run(uint8_t freq_resp_input, float start_frq, float stop_frq, float &dwell_gain, float &dwell_phase)
|
void AC_AutoTune_Heli::dwell_test_run(uint8_t freq_resp_input, float start_frq, float stop_frq, float &dwell_gain, float &dwell_phase, DwellType dwell_type)
|
||||||
{
|
{
|
||||||
float gyro_reading = 0.0f;
|
float gyro_reading = 0.0f;
|
||||||
float command_reading = 0.0f;
|
float command_reading = 0.0f;
|
||||||
float tgt_rate_reading = 0.0f;
|
float tgt_rate_reading = 0.0f;
|
||||||
float tgt_attitude = 2.5f * 0.01745f;
|
float tgt_attitude;
|
||||||
const uint32_t now = AP_HAL::millis();
|
|
||||||
float target_rate_cds;
|
|
||||||
float sweep_time_ms = 23000;
|
|
||||||
const float att_hold_gain = 4.5f;
|
|
||||||
Vector3f attitude_cd;
|
|
||||||
|
|
||||||
float dwell_freq = start_frq;
|
|
||||||
float cycle_time_ms = 0;
|
|
||||||
if (!is_zero(dwell_freq)) {
|
|
||||||
cycle_time_ms = 1000.0f * 2.0f * M_PI / dwell_freq;
|
|
||||||
}
|
|
||||||
|
|
||||||
attitude_cd = Vector3f((float)ahrs_view->roll_sensor, (float)ahrs_view->pitch_sensor, (float)ahrs_view->yaw_sensor);
|
|
||||||
Vector3f velocity_ned, velocity_bf;
|
|
||||||
if (ahrs_view->get_velocity_NED(velocity_ned)) {
|
|
||||||
velocity_bf.x = velocity_ned.x * ahrs_view->cos_yaw() + velocity_ned.y * ahrs_view->sin_yaw();
|
|
||||||
velocity_bf.y = -velocity_ned.x * ahrs_view->sin_yaw() + velocity_ned.y * ahrs_view->cos_yaw();
|
|
||||||
}
|
|
||||||
|
|
||||||
// keep controller from requesting too high of a rate
|
|
||||||
float target_rate_mag_cds = dwell_freq * tgt_attitude * 5730.0f;
|
|
||||||
if (target_rate_mag_cds > 5000.0f) {
|
|
||||||
target_rate_mag_cds = 5000.0f;
|
|
||||||
}
|
|
||||||
if (settle_time == 0) {
|
|
||||||
// give gentler start for the dwell
|
|
||||||
if ((float)(now - dwell_start_time_ms) < 0.5f * cycle_time_ms) {
|
|
||||||
target_rate_cds = -0.5f * target_rate_mag_cds * sinf(dwell_freq * (now - dwell_start_time_ms) * 0.001);
|
|
||||||
} else {
|
|
||||||
if (is_equal(start_frq,stop_frq)) {
|
|
||||||
target_rate_cds = - target_rate_mag_cds * cosf(dwell_freq * (now - dwell_start_time_ms - 0.25f * cycle_time_ms) * 0.001);
|
|
||||||
} else {
|
|
||||||
target_rate_cds = waveform((now - dwell_start_time_ms - 0.5f * cycle_time_ms) * 0.001, (sweep_time_ms - 0.5f * cycle_time_ms) * 0.001f, target_rate_mag_cds, start_frq, stop_frq);
|
|
||||||
dwell_freq = waveform_freq_rads;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filt_pit_roll_cd.apply(Vector2f(attitude_cd.x,attitude_cd.y), AP::scheduler().get_loop_period_s());
|
|
||||||
filt_heading_error_cd.apply(wrap_180_cd(trim_attitude_cd.z - attitude_cd.z), AP::scheduler().get_loop_period_s());
|
|
||||||
Vector2f att_fdbk = Vector2f(-5730.0f * vel_hold_gain * velocity_bf.y, 5730.0f * vel_hold_gain * velocity_bf.x);
|
|
||||||
filt_att_fdbk_from_velxy_cd.apply(att_fdbk, AP::scheduler().get_loop_period_s());
|
|
||||||
} else {
|
|
||||||
target_rate_cds = 0.0f;
|
|
||||||
settle_time--;
|
|
||||||
dwell_start_time_ms = now;
|
|
||||||
trim_command = command_out;
|
|
||||||
trim_attitude_cd = attitude_cd;
|
|
||||||
filt_pit_roll_cd.reset(Vector2f(attitude_cd.x,attitude_cd.y));
|
|
||||||
filt_heading_error_cd.reset(0.0f);
|
|
||||||
filt_att_fdbk_from_velxy_cd.reset(Vector2f(0.0f,0.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
// limit rate correction for position hold
|
|
||||||
Vector3f trim_rate_cds {
|
|
||||||
constrain_float(att_hold_gain * ((trim_attitude_cd.x + filt_att_fdbk_from_velxy_cd.get().x) - filt_pit_roll_cd.get().x), -15000.0f, 15000.0f),
|
|
||||||
constrain_float(att_hold_gain * ((trim_attitude_cd.y + filt_att_fdbk_from_velxy_cd.get().y) - filt_pit_roll_cd.get().y), -15000.0f, 15000.0f),
|
|
||||||
constrain_float(att_hold_gain * filt_heading_error_cd.get(), -15000.0f, 15000.0f)
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (axis) {
|
|
||||||
case ROLL:
|
|
||||||
gyro_reading = ahrs_view->get_gyro().x;
|
|
||||||
command_reading = motors->get_roll();
|
|
||||||
tgt_rate_reading = attitude_control->rate_bf_targets().x;
|
|
||||||
if (settle_time == 0) {
|
|
||||||
float ff_rate_contr = 0.0f;
|
|
||||||
if (tune_roll_rff > 0.0f) {
|
|
||||||
ff_rate_contr = 5730.0f * trim_command / tune_roll_rff;
|
|
||||||
}
|
|
||||||
trim_rate_cds.x += ff_rate_contr;
|
|
||||||
attitude_control->input_rate_bf_roll_pitch_yaw(0.0f, trim_rate_cds.y, 0.0f);
|
|
||||||
attitude_control->rate_bf_roll_target(target_rate_cds + trim_rate_cds.x);
|
|
||||||
} else {
|
|
||||||
attitude_control->input_rate_bf_roll_pitch_yaw(0.0f, 0.0f, 0.0f);
|
|
||||||
if (!is_zero(attitude_control->get_rate_roll_pid().ff() + attitude_control->get_rate_roll_pid().kP())) {
|
|
||||||
float trim_tgt_rate_cds = 5730.0f * (trim_pff_out + trim_meas_rate * attitude_control->get_rate_roll_pid().kP()) / (attitude_control->get_rate_roll_pid().ff() + attitude_control->get_rate_roll_pid().kP());
|
|
||||||
attitude_control->rate_bf_roll_target(trim_tgt_rate_cds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PITCH:
|
|
||||||
gyro_reading = ahrs_view->get_gyro().y;
|
|
||||||
command_reading = motors->get_pitch();
|
|
||||||
tgt_rate_reading = attitude_control->rate_bf_targets().y;
|
|
||||||
if (settle_time == 0) {
|
|
||||||
float ff_rate_contr = 0.0f;
|
|
||||||
if (tune_pitch_rff > 0.0f) {
|
|
||||||
ff_rate_contr = 5730.0f * trim_command / tune_pitch_rff;
|
|
||||||
}
|
|
||||||
trim_rate_cds.y += ff_rate_contr;
|
|
||||||
attitude_control->input_rate_bf_roll_pitch_yaw(trim_rate_cds.x, 0.0f, 0.0f);
|
|
||||||
attitude_control->rate_bf_pitch_target(target_rate_cds + trim_rate_cds.y);
|
|
||||||
} else {
|
|
||||||
attitude_control->input_rate_bf_roll_pitch_yaw(0.0f, 0.0f, 0.0f);
|
|
||||||
if (!is_zero(attitude_control->get_rate_pitch_pid().ff() + attitude_control->get_rate_pitch_pid().kP())) {
|
|
||||||
float trim_tgt_rate_cds = 5730.0f * (trim_pff_out + trim_meas_rate * attitude_control->get_rate_pitch_pid().kP()) / (attitude_control->get_rate_pitch_pid().ff() + attitude_control->get_rate_pitch_pid().kP());
|
|
||||||
attitude_control->rate_bf_pitch_target(trim_tgt_rate_cds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case YAW:
|
|
||||||
gyro_reading = ahrs_view->get_gyro().z;
|
|
||||||
command_reading = motors->get_yaw();
|
|
||||||
tgt_rate_reading = attitude_control->rate_bf_targets().z;
|
|
||||||
if (settle_time == 0) {
|
|
||||||
float rp_rate_contr = 0.0f;
|
|
||||||
if (tune_yaw_rp > 0.0f) {
|
|
||||||
rp_rate_contr = 5730.0f * trim_command / tune_yaw_rp;
|
|
||||||
}
|
|
||||||
trim_rate_cds.z += rp_rate_contr;
|
|
||||||
attitude_control->input_rate_bf_roll_pitch_yaw(trim_rate_cds.x, trim_rate_cds.y, 0.0f);
|
|
||||||
attitude_control->rate_bf_yaw_target(target_rate_cds + trim_rate_cds.z);
|
|
||||||
} else {
|
|
||||||
attitude_control->input_rate_bf_roll_pitch_yaw(0.0f, 0.0f, 0.0f);
|
|
||||||
if (!is_zero(attitude_control->get_rate_yaw_pid().ff() + attitude_control->get_rate_yaw_pid().kP())) {
|
|
||||||
float trim_tgt_rate_cds = 5730.0f * (trim_pff_out + trim_meas_rate * attitude_control->get_rate_yaw_pid().kP()) / (attitude_control->get_rate_yaw_pid().ff() + attitude_control->get_rate_yaw_pid().kP());
|
|
||||||
attitude_control->rate_bf_yaw_target(trim_tgt_rate_cds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settle_time == 0) {
|
|
||||||
filt_command_reading.apply(command_reading, AP::scheduler().get_loop_period_s());
|
|
||||||
filt_gyro_reading.apply(gyro_reading, AP::scheduler().get_loop_period_s());
|
|
||||||
filt_tgt_rate_reading.apply(tgt_rate_reading, AP::scheduler().get_loop_period_s());
|
|
||||||
} else {
|
|
||||||
filt_command_reading.reset(command_reading);
|
|
||||||
filt_gyro_reading.reset(gyro_reading);
|
|
||||||
filt_tgt_rate_reading.reset(tgt_rate_reading);
|
|
||||||
}
|
|
||||||
|
|
||||||
// looks at gain and phase of input rate to output rate
|
|
||||||
rotation_rate = rotation_rate_filt.apply((gyro_reading - filt_gyro_reading.get()),
|
|
||||||
AP::scheduler().get_loop_period_s());
|
|
||||||
filt_target_rate = target_rate_filt.apply((tgt_rate_reading - filt_tgt_rate_reading.get()),
|
|
||||||
AP::scheduler().get_loop_period_s());
|
|
||||||
command_out = command_filt.apply((command_reading - filt_command_reading.get()),
|
|
||||||
AP::scheduler().get_loop_period_s());
|
|
||||||
|
|
||||||
// wait for dwell to start before determining gain and phase or just start if sweep
|
|
||||||
if ((float)(now - dwell_start_time_ms) > 6.25f * cycle_time_ms || (!is_equal(start_frq,stop_frq) && settle_time == 0)) {
|
|
||||||
if (freq_resp_input == 1) {
|
|
||||||
freqresp_rate.update(command_out,filt_target_rate,rotation_rate, dwell_freq);
|
|
||||||
} else {
|
|
||||||
freqresp_rate.update(command_out,command_out,rotation_rate, dwell_freq);
|
|
||||||
}
|
|
||||||
if (freqresp_rate.is_cycle_complete()) {
|
|
||||||
if (!is_equal(start_frq,stop_frq)) {
|
|
||||||
curr_test.freq = freqresp_rate.get_freq();
|
|
||||||
curr_test.gain = freqresp_rate.get_gain();
|
|
||||||
curr_test.phase = freqresp_rate.get_phase();
|
|
||||||
// reset cycle_complete to allow indication of next cycle
|
|
||||||
freqresp_rate.reset_cycle_complete();
|
|
||||||
// log sweep data
|
|
||||||
Log_AutoTuneSweep();
|
|
||||||
} else {
|
|
||||||
dwell_gain = freqresp_rate.get_gain();
|
|
||||||
dwell_phase = freqresp_rate.get_phase();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set sweep data if a frequency sweep is being conducted
|
|
||||||
if (!is_equal(start_frq,stop_frq) && (float)(now - dwell_start_time_ms) > 2.5f * cycle_time_ms) {
|
|
||||||
// track sweep phase to prevent capturing 180 deg and 270 deg data after phase has wrapped.
|
|
||||||
if (curr_test.phase > 180.0f && sweep.progress == 0) {
|
|
||||||
sweep.progress = 1;
|
|
||||||
} else if (curr_test.phase > 270.0f && sweep.progress == 1) {
|
|
||||||
sweep.progress = 2;
|
|
||||||
}
|
|
||||||
if (curr_test.phase <= 160.0f && curr_test.phase >= 150.0f && sweep.progress == 0) {
|
|
||||||
sweep.ph180.freq = curr_test.freq;
|
|
||||||
sweep.ph180.gain = curr_test.gain;
|
|
||||||
sweep.ph180.phase = curr_test.phase;
|
|
||||||
}
|
|
||||||
if (curr_test.phase <= 250.0f && curr_test.phase >= 240.0f && sweep.progress == 1) {
|
|
||||||
sweep.ph270.freq = curr_test.freq;
|
|
||||||
sweep.ph270.gain = curr_test.gain;
|
|
||||||
sweep.ph270.phase = curr_test.phase;
|
|
||||||
}
|
|
||||||
if (curr_test.gain > sweep.maxgain.gain) {
|
|
||||||
sweep.maxgain.gain = curr_test.gain;
|
|
||||||
sweep.maxgain.freq = curr_test.freq;
|
|
||||||
sweep.maxgain.phase = curr_test.phase;
|
|
||||||
}
|
|
||||||
if (now - step_start_time_ms >= sweep_time_ms + 200) {
|
|
||||||
// we have passed the maximum stop time
|
|
||||||
step = UPDATE_GAINS;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (now - step_start_time_ms >= step_time_limit_ms || freqresp_rate.is_cycle_complete()) {
|
|
||||||
// we have passed the maximum stop time
|
|
||||||
step = UPDATE_GAINS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AC_AutoTune_Heli::angle_dwell_test_run(float start_frq, float stop_frq, float &dwell_gain, float &dwell_phase)
|
|
||||||
{
|
|
||||||
float gyro_reading = 0.0f;
|
|
||||||
float command_reading = 0.0f;
|
|
||||||
float tgt_rate_reading = 0.0f;
|
|
||||||
float tgt_attitude = 5.0f * 0.01745f;
|
|
||||||
const uint32_t now = AP_HAL::millis();
|
const uint32_t now = AP_HAL::millis();
|
||||||
float target_angle_cd;
|
float target_angle_cd;
|
||||||
|
float target_rate_cds;
|
||||||
float sweep_time_ms = 23000;
|
float sweep_time_ms = 23000;
|
||||||
float dwell_freq = start_frq;
|
float dwell_freq = start_frq;
|
||||||
|
float target_rate_mag_cds;
|
||||||
// adjust target attitude based on input_tc so amplitude decrease with increased frequency is minimized
|
const float att_hold_gain = 4.5f;
|
||||||
const float freq_co = 1.0f / attitude_control->get_input_tc();
|
|
||||||
const float added_ampl = (safe_sqrt(powf(dwell_freq,2.0) + powf(freq_co,2.0)) / freq_co) - 1.0f;
|
|
||||||
tgt_attitude = constrain_float(0.08725f * (1.0f + 0.2f * added_ampl), 0.08725f, 0.5235f);
|
|
||||||
|
|
||||||
float cycle_time_ms = 0;
|
float cycle_time_ms = 0;
|
||||||
if (!is_zero(dwell_freq)) {
|
if (!is_zero(dwell_freq)) {
|
||||||
cycle_time_ms = 1000.0f * 6.28f / dwell_freq;
|
cycle_time_ms = 1000.0f * M_2PI / dwell_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dwell_type == RATE) {
|
||||||
|
// keep controller from requesting too high of a rate
|
||||||
|
tgt_attitude = 2.5f * 0.01745f;
|
||||||
|
target_rate_mag_cds = dwell_freq * tgt_attitude * 5730.0f;
|
||||||
|
if (target_rate_mag_cds > 5000.0f) {
|
||||||
|
target_rate_mag_cds = 5000.0f;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tgt_attitude = 5.0f * 0.01745f;
|
||||||
|
// adjust target attitude based on input_tc so amplitude decrease with increased frequency is minimized
|
||||||
|
const float freq_co = 1.0f / attitude_control->get_input_tc();
|
||||||
|
const float added_ampl = (safe_sqrt(powf(dwell_freq,2.0) + powf(freq_co,2.0)) / freq_co) - 1.0f;
|
||||||
|
tgt_attitude = constrain_float(0.08725f * (1.0f + 0.2f * added_ampl), 0.08725f, 0.5235f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// body frame calculation of velocity
|
// body frame calculation of velocity
|
||||||
|
@ -1229,55 +1037,132 @@ void AC_AutoTune_Heli::angle_dwell_test_run(float start_frq, float stop_frq, flo
|
||||||
velocity_bf.y = -velocity_ned.x * ahrs_view->sin_yaw() + velocity_ned.y * ahrs_view->cos_yaw();
|
velocity_bf.y = -velocity_ned.x * ahrs_view->sin_yaw() + velocity_ned.y * ahrs_view->cos_yaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3f attitude_cd = Vector3f((float)ahrs_view->roll_sensor, (float)ahrs_view->pitch_sensor, (float)ahrs_view->yaw_sensor);
|
||||||
if (settle_time == 0) {
|
if (settle_time == 0) {
|
||||||
// give gentler start for the dwell
|
if (dwell_type == RATE) {
|
||||||
if ((float)(now - dwell_start_time_ms) < 0.5f * cycle_time_ms) {
|
target_rate_cds = -waveform((now - dwell_start_time_ms) * 0.001, sweep_time_ms * 0.001f, target_rate_mag_cds, start_frq, stop_frq);
|
||||||
target_angle_cd = 0.5f * tgt_attitude * 5730.0f * (cosf(dwell_freq * (now - dwell_start_time_ms) * 0.001) - 1.0f);
|
filt_pit_roll_cd.apply(Vector2f(attitude_cd.x,attitude_cd.y), AP::scheduler().get_loop_period_s());
|
||||||
|
filt_heading_error_cd.apply(wrap_180_cd(trim_attitude_cd.z - attitude_cd.z), AP::scheduler().get_loop_period_s());
|
||||||
} else {
|
} else {
|
||||||
if (is_equal(start_frq,stop_frq)) {
|
target_angle_cd = -waveform((now - dwell_start_time_ms) * 0.001, sweep_time_ms * 0.001f, tgt_attitude * 5730.0f, start_frq, stop_frq);
|
||||||
target_angle_cd = -tgt_attitude * 5730.0f * sinf(dwell_freq * (now - dwell_start_time_ms - 0.25f * cycle_time_ms) * 0.001);
|
|
||||||
} else {
|
|
||||||
target_angle_cd = -waveform((now - dwell_start_time_ms - 0.25f * cycle_time_ms) * 0.001, (sweep_time_ms - 0.25f * cycle_time_ms) * 0.001f, tgt_attitude * 5730.0f, start_frq, stop_frq);
|
|
||||||
dwell_freq = waveform_freq_rads;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const Vector2f att_fdbk {
|
const Vector2f att_fdbk {
|
||||||
-5730.0f * vel_hold_gain * velocity_bf.y,
|
-5730.0f * vel_hold_gain * velocity_bf.y,
|
||||||
5730.0f * vel_hold_gain * velocity_bf.x
|
5730.0f * vel_hold_gain * velocity_bf.x
|
||||||
};
|
};
|
||||||
filt_att_fdbk_from_velxy_cd.apply(att_fdbk, AP::scheduler().get_loop_period_s());
|
filt_att_fdbk_from_velxy_cd.apply(att_fdbk, AP::scheduler().get_loop_period_s());
|
||||||
|
dwell_freq = waveform_freq_rads;
|
||||||
} else {
|
} else {
|
||||||
target_angle_cd = 0.0f;
|
if (dwell_type == RATE) {
|
||||||
trim_yaw_tgt_reading = (float)attitude_control->get_att_target_euler_cd().z;
|
target_rate_cds = 0.0f;
|
||||||
trim_yaw_heading_reading = (float)ahrs_view->yaw_sensor;
|
trim_command = command_out;
|
||||||
settle_time--;
|
trim_attitude_cd = attitude_cd;
|
||||||
|
filt_pit_roll_cd.reset(Vector2f(attitude_cd.x,attitude_cd.y));
|
||||||
|
filt_heading_error_cd.reset(0.0f);
|
||||||
|
} else {
|
||||||
|
target_angle_cd = 0.0f;
|
||||||
|
trim_yaw_tgt_reading = (float)attitude_control->get_att_target_euler_cd().z;
|
||||||
|
trim_yaw_heading_reading = (float)ahrs_view->yaw_sensor;
|
||||||
|
}
|
||||||
dwell_start_time_ms = now;
|
dwell_start_time_ms = now;
|
||||||
filt_att_fdbk_from_velxy_cd.reset(Vector2f(0.0f,0.0f));
|
filt_att_fdbk_from_velxy_cd.reset(Vector2f(0.0f,0.0f));
|
||||||
|
settle_time--;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Vector2f trim_angle_cd {
|
if (dwell_type == RATE) {
|
||||||
constrain_float(filt_att_fdbk_from_velxy_cd.get().x, -2000.0f, 2000.0f),
|
// limit rate correction for position hold
|
||||||
constrain_float(filt_att_fdbk_from_velxy_cd.get().y, -2000.0f, 2000.0f)
|
Vector3f trim_rate_cds {
|
||||||
};
|
constrain_float(att_hold_gain * ((trim_attitude_cd.x + filt_att_fdbk_from_velxy_cd.get().x) - filt_pit_roll_cd.get().x), -15000.0f, 15000.0f),
|
||||||
switch (axis) {
|
constrain_float(att_hold_gain * ((trim_attitude_cd.y + filt_att_fdbk_from_velxy_cd.get().y) - filt_pit_roll_cd.get().y), -15000.0f, 15000.0f),
|
||||||
case ROLL:
|
constrain_float(att_hold_gain * filt_heading_error_cd.get(), -15000.0f, 15000.0f)
|
||||||
attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(target_angle_cd + trim_angle_cd.x, trim_angle_cd.y, 0.0f);
|
};
|
||||||
command_reading = motors->get_roll();
|
switch (axis) {
|
||||||
tgt_rate_reading = ((float)attitude_control->get_att_target_euler_cd().x) / 5730.0f;
|
case ROLL:
|
||||||
gyro_reading = ((float)ahrs_view->roll_sensor) / 5730.0f;
|
gyro_reading = ahrs_view->get_gyro().x;
|
||||||
break;
|
command_reading = motors->get_roll();
|
||||||
case PITCH:
|
tgt_rate_reading = attitude_control->rate_bf_targets().x;
|
||||||
attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(trim_angle_cd.x, target_angle_cd + trim_angle_cd.y, 0.0f);
|
if (settle_time == 0) {
|
||||||
command_reading = motors->get_pitch();
|
float ff_rate_contr = 0.0f;
|
||||||
tgt_rate_reading = ((float)attitude_control->get_att_target_euler_cd().y) / 5730.0f;
|
if (tune_roll_rff > 0.0f) {
|
||||||
gyro_reading = ((float)ahrs_view->pitch_sensor) / 5730.0f;
|
ff_rate_contr = 5730.0f * trim_command / tune_roll_rff;
|
||||||
break;
|
}
|
||||||
case YAW:
|
trim_rate_cds.x += ff_rate_contr;
|
||||||
command_reading = motors->get_yaw();
|
attitude_control->input_rate_bf_roll_pitch_yaw(0.0f, trim_rate_cds.y, 0.0f);
|
||||||
tgt_rate_reading = (wrap_180_cd((float)attitude_control->get_att_target_euler_cd().z - trim_yaw_tgt_reading)) / 5730.0f;
|
attitude_control->rate_bf_roll_target(target_rate_cds + trim_rate_cds.x);
|
||||||
gyro_reading = (wrap_180_cd((float)ahrs_view->yaw_sensor - trim_yaw_heading_reading)) / 5730.0f;
|
} else {
|
||||||
attitude_control->input_euler_angle_roll_pitch_yaw(trim_angle_cd.x, trim_angle_cd.y, wrap_180_cd(trim_yaw_tgt_reading + target_angle_cd), false);
|
attitude_control->input_rate_bf_roll_pitch_yaw(0.0f, 0.0f, 0.0f);
|
||||||
break;
|
if (!is_zero(attitude_control->get_rate_roll_pid().ff() + attitude_control->get_rate_roll_pid().kP())) {
|
||||||
|
float trim_tgt_rate_cds = 5730.0f * (trim_pff_out + trim_meas_rate * attitude_control->get_rate_roll_pid().kP()) / (attitude_control->get_rate_roll_pid().ff() + attitude_control->get_rate_roll_pid().kP());
|
||||||
|
attitude_control->rate_bf_roll_target(trim_tgt_rate_cds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PITCH:
|
||||||
|
gyro_reading = ahrs_view->get_gyro().y;
|
||||||
|
command_reading = motors->get_pitch();
|
||||||
|
tgt_rate_reading = attitude_control->rate_bf_targets().y;
|
||||||
|
if (settle_time == 0) {
|
||||||
|
float ff_rate_contr = 0.0f;
|
||||||
|
if (tune_pitch_rff > 0.0f) {
|
||||||
|
ff_rate_contr = 5730.0f * trim_command / tune_pitch_rff;
|
||||||
|
}
|
||||||
|
trim_rate_cds.y += ff_rate_contr;
|
||||||
|
attitude_control->input_rate_bf_roll_pitch_yaw(trim_rate_cds.x, 0.0f, 0.0f);
|
||||||
|
attitude_control->rate_bf_pitch_target(target_rate_cds + trim_rate_cds.y);
|
||||||
|
} else {
|
||||||
|
attitude_control->input_rate_bf_roll_pitch_yaw(0.0f, 0.0f, 0.0f);
|
||||||
|
if (!is_zero(attitude_control->get_rate_pitch_pid().ff() + attitude_control->get_rate_pitch_pid().kP())) {
|
||||||
|
float trim_tgt_rate_cds = 5730.0f * (trim_pff_out + trim_meas_rate * attitude_control->get_rate_pitch_pid().kP()) / (attitude_control->get_rate_pitch_pid().ff() + attitude_control->get_rate_pitch_pid().kP());
|
||||||
|
attitude_control->rate_bf_pitch_target(trim_tgt_rate_cds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case YAW:
|
||||||
|
gyro_reading = ahrs_view->get_gyro().z;
|
||||||
|
command_reading = motors->get_yaw();
|
||||||
|
tgt_rate_reading = attitude_control->rate_bf_targets().z;
|
||||||
|
if (settle_time == 0) {
|
||||||
|
float rp_rate_contr = 0.0f;
|
||||||
|
if (tune_yaw_rp > 0.0f) {
|
||||||
|
rp_rate_contr = 5730.0f * trim_command / tune_yaw_rp;
|
||||||
|
}
|
||||||
|
trim_rate_cds.z += rp_rate_contr;
|
||||||
|
attitude_control->input_rate_bf_roll_pitch_yaw(trim_rate_cds.x, trim_rate_cds.y, 0.0f);
|
||||||
|
attitude_control->rate_bf_yaw_target(target_rate_cds + trim_rate_cds.z);
|
||||||
|
} else {
|
||||||
|
attitude_control->input_rate_bf_roll_pitch_yaw(0.0f, 0.0f, 0.0f);
|
||||||
|
if (!is_zero(attitude_control->get_rate_yaw_pid().ff() + attitude_control->get_rate_yaw_pid().kP())) {
|
||||||
|
float trim_tgt_rate_cds = 5730.0f * (trim_pff_out + trim_meas_rate * attitude_control->get_rate_yaw_pid().kP()) / (attitude_control->get_rate_yaw_pid().ff() + attitude_control->get_rate_yaw_pid().kP());
|
||||||
|
attitude_control->rate_bf_yaw_target(trim_tgt_rate_cds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const Vector2f trim_angle_cd {
|
||||||
|
constrain_float(filt_att_fdbk_from_velxy_cd.get().x, -2000.0f, 2000.0f),
|
||||||
|
constrain_float(filt_att_fdbk_from_velxy_cd.get().y, -2000.0f, 2000.0f)
|
||||||
|
};
|
||||||
|
switch (axis) {
|
||||||
|
case ROLL:
|
||||||
|
attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(target_angle_cd + trim_angle_cd.x, trim_angle_cd.y, 0.0f);
|
||||||
|
command_reading = motors->get_roll();
|
||||||
|
tgt_rate_reading = ((float)attitude_control->get_att_target_euler_cd().x) / 5730.0f;
|
||||||
|
gyro_reading = ((float)ahrs_view->roll_sensor) / 5730.0f;
|
||||||
|
break;
|
||||||
|
case PITCH:
|
||||||
|
attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(trim_angle_cd.x, target_angle_cd + trim_angle_cd.y, 0.0f);
|
||||||
|
command_reading = motors->get_pitch();
|
||||||
|
tgt_rate_reading = ((float)attitude_control->get_att_target_euler_cd().y) / 5730.0f;
|
||||||
|
gyro_reading = ((float)ahrs_view->pitch_sensor) / 5730.0f;
|
||||||
|
break;
|
||||||
|
case YAW:
|
||||||
|
command_reading = motors->get_yaw();
|
||||||
|
tgt_rate_reading = (wrap_180_cd((float)attitude_control->get_att_target_euler_cd().z - trim_yaw_tgt_reading)) / 5730.0f;
|
||||||
|
gyro_reading = (wrap_180_cd((float)ahrs_view->yaw_sensor - trim_yaw_heading_reading)) / 5730.0f;
|
||||||
|
attitude_control->input_euler_angle_roll_pitch_yaw(trim_angle_cd.x, trim_angle_cd.y, wrap_180_cd(trim_yaw_tgt_reading + target_angle_cd), false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settle_time == 0) {
|
if (settle_time == 0) {
|
||||||
|
@ -1300,31 +1185,42 @@ void AC_AutoTune_Heli::angle_dwell_test_run(float start_frq, float stop_frq, flo
|
||||||
|
|
||||||
// wait for dwell to start before determining gain and phase
|
// wait for dwell to start before determining gain and phase
|
||||||
if ((float)(now - dwell_start_time_ms) > 6.25f * cycle_time_ms || (!is_equal(start_frq,stop_frq) && settle_time == 0)) {
|
if ((float)(now - dwell_start_time_ms) > 6.25f * cycle_time_ms || (!is_equal(start_frq,stop_frq) && settle_time == 0)) {
|
||||||
freqresp_angle.update(command_out, filt_target_rate, rotation_rate, dwell_freq);
|
if (freq_resp_input == 1) {
|
||||||
if (freqresp_angle.is_cycle_complete()) {
|
freqresp.update(command_out,filt_target_rate,rotation_rate, dwell_freq);
|
||||||
|
} else {
|
||||||
|
freqresp.update(command_out,command_out,rotation_rate, dwell_freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (freqresp.is_cycle_complete()) {
|
||||||
if (!is_equal(start_frq,stop_frq)) {
|
if (!is_equal(start_frq,stop_frq)) {
|
||||||
curr_test.freq = freqresp_angle.get_freq();
|
curr_test.freq = freqresp.get_freq();
|
||||||
curr_test.gain = freqresp_angle.get_gain();
|
curr_test.gain = freqresp.get_gain();
|
||||||
curr_test.phase = freqresp_angle.get_phase();
|
curr_test.phase = freqresp.get_phase();
|
||||||
test_accel_max = freqresp_angle.get_accel_max();
|
if (dwell_type == ANGLE) {test_accel_max = freqresp.get_accel_max();}
|
||||||
// reset cycle_complete to allow indication of next cycle
|
// reset cycle_complete to allow indication of next cycle
|
||||||
freqresp_angle.reset_cycle_complete();
|
freqresp.reset_cycle_complete();
|
||||||
// log sweep data
|
// log sweep data
|
||||||
Log_AutoTuneSweep();
|
Log_AutoTuneSweep();
|
||||||
} else {
|
} else {
|
||||||
dwell_gain = freqresp_angle.get_gain();
|
dwell_gain = freqresp.get_gain();
|
||||||
dwell_phase = freqresp_angle.get_phase();
|
dwell_phase = freqresp.get_phase();
|
||||||
test_accel_max = freqresp_angle.get_accel_max();
|
if (dwell_type == ANGLE) {test_accel_max = freqresp.get_accel_max();}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set sweep data if a frequency sweep is being conducted
|
// set sweep data if a frequency sweep is being conducted
|
||||||
if (!is_equal(start_frq,stop_frq)) {
|
if (!is_equal(start_frq,stop_frq) && (float)(now - dwell_start_time_ms) > 2.5f * cycle_time_ms) {
|
||||||
if (curr_test.phase <= 160.0f && curr_test.phase >= 150.0f) {
|
// track sweep phase to prevent capturing 180 deg and 270 deg data after phase has wrapped.
|
||||||
|
if (curr_test.phase > 180.0f && sweep.progress == 0) {
|
||||||
|
sweep.progress = 1;
|
||||||
|
} else if (curr_test.phase > 270.0f && sweep.progress == 1) {
|
||||||
|
sweep.progress = 2;
|
||||||
|
}
|
||||||
|
if (curr_test.phase <= 160.0f && curr_test.phase >= 150.0f && sweep.progress == 0) {
|
||||||
sweep.ph180 = curr_test;
|
sweep.ph180 = curr_test;
|
||||||
}
|
}
|
||||||
if (curr_test.phase <= 250.0f && curr_test.phase >= 240.0f) {
|
if (curr_test.phase <= 250.0f && curr_test.phase >= 240.0f && sweep.progress == 1) {
|
||||||
sweep.ph270 = curr_test;
|
sweep.ph270 = curr_test;
|
||||||
}
|
}
|
||||||
if (curr_test.gain > sweep.maxgain.gain) {
|
if (curr_test.gain > sweep.maxgain.gain) {
|
||||||
|
@ -1335,13 +1231,12 @@ void AC_AutoTune_Heli::angle_dwell_test_run(float start_frq, float stop_frq, flo
|
||||||
step = UPDATE_GAINS;
|
step = UPDATE_GAINS;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (now - step_start_time_ms >= step_time_limit_ms || freqresp_angle.is_cycle_complete()) {
|
if (now - step_start_time_ms >= step_time_limit_ms || freqresp.is_cycle_complete()) {
|
||||||
// we have passed the maximum stop time
|
// we have passed the maximum stop time
|
||||||
step = UPDATE_GAINS;
|
step = UPDATE_GAINS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// init_test - initialises the test
|
// init_test - initialises the test
|
||||||
float AC_AutoTune_Heli::waveform(float time, float time_record, float waveform_magnitude, float wMin, float wMax)
|
float AC_AutoTune_Heli::waveform(float time, float time_record, float waveform_magnitude, float wMin, float wMax)
|
||||||
{
|
{
|
||||||
|
|
|
@ -150,10 +150,7 @@ private:
|
||||||
void dwell_test_init(float start_frq, float filt_freq, DwellType dwell_type);
|
void dwell_test_init(float start_frq, float filt_freq, DwellType dwell_type);
|
||||||
|
|
||||||
// dwell test used to perform frequency dwells for rate gains
|
// dwell test used to perform frequency dwells for rate gains
|
||||||
void dwell_test_run(uint8_t freq_resp_input, float start_frq, float stop_frq, float &dwell_gain, float &dwell_phase);
|
void dwell_test_run(uint8_t freq_resp_input, float start_frq, float stop_frq, float &dwell_gain, float &dwell_phase, DwellType dwell_type);
|
||||||
|
|
||||||
// dwell test used to perform frequency dwells for angle gains
|
|
||||||
void angle_dwell_test_run(float start_frq, float stop_frq, float &dwell_gain, float &dwell_phase);
|
|
||||||
|
|
||||||
// generates waveform for frequency sweep excitations
|
// generates waveform for frequency sweep excitations
|
||||||
float waveform(float time, float time_record, float waveform_magnitude, float wMin, float wMax);
|
float waveform(float time, float time_record, float waveform_magnitude, float wMin, float wMax);
|
||||||
|
@ -292,8 +289,6 @@ private:
|
||||||
AP_Float max_resp_gain; // maximum response gain
|
AP_Float max_resp_gain; // maximum response gain
|
||||||
AP_Float vel_hold_gain; // gain for velocity hold
|
AP_Float vel_hold_gain; // gain for velocity hold
|
||||||
|
|
||||||
// freqresp object for the rate frequency response tests
|
// freqresp object for the frequency response tests
|
||||||
AC_AutoTune_FreqResp freqresp_rate;
|
AC_AutoTune_FreqResp freqresp;
|
||||||
// freqresp object for the angle frequency response tests
|
|
||||||
AC_AutoTune_FreqResp freqresp_angle;
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue