From ad14e153e82580977ca303bbdb0ac57dcffacc57 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 3 Dec 2020 17:42:39 +1100 Subject: [PATCH] Plane: fixed tilt vectoring to cope with large tilt angles This uses vectoring for both roll and yaw when tilted, and uses differential thrust for yaw when tilted --- ArduPlane/quadplane.cpp | 26 +++++-- ArduPlane/quadplane.h | 4 +- ArduPlane/tiltrotor.cpp | 155 ++++++++++++++++------------------------ 3 files changed, 84 insertions(+), 101 deletions(-) diff --git a/ArduPlane/quadplane.cpp b/ArduPlane/quadplane.cpp index 4a3f505c9d..be24f5865a 100644 --- a/ArduPlane/quadplane.cpp +++ b/ArduPlane/quadplane.cpp @@ -735,6 +735,15 @@ bool QuadPlane::setup(void) if (!motors->initialised_ok()) { AP_BoardConfig::config_error("unknown Q_FRAME_TYPE %u", (unsigned)frame_type.get()); } + + if (motors_var_info == AP_MotorsMatrix::var_info && + tilt.tilt_mask != 0 && + tilt.tilt_type == TILT_TYPE_VECTORED_YAW) { + // we will be using vectoring for yaw + motors->disable_yaw_torque(); + } + + motors->set_throttle_range(thr_min_pwm, thr_max_pwm); motors->set_update_rate(rc_speed); motors->set_interlock(true); @@ -1728,11 +1737,18 @@ void QuadPlane::update_transition(void) } hold_hover(climb_rate_cms); - // set desired yaw to current yaw in both desired angle and - // rate request. This reduces wing twist in transition due to - // multicopter yaw demands - attitude_control->set_yaw_target_to_current_heading(); - attitude_control->rate_bf_yaw_target(ahrs.get_gyro().z); + if (tilt.tilt_mask == 0 || + tilt.tilt_type != TILT_TYPE_VECTORED_YAW || + now - transition_start_ms < 100) { + // set desired yaw to current yaw in both desired angle + // and rate request. This reduces wing twist in transition + // due to multicopter yaw demands. This is disabled when + // using vectored yaw for tilt-rotors as the yaw control + // is needed to maintain good control in forward + // transitions + attitude_control->set_yaw_target_to_current_heading(); + attitude_control->rate_bf_yaw_target(ahrs.get_gyro().z); + } last_throttle = motors->get_throttle(); diff --git a/ArduPlane/quadplane.h b/ArduPlane/quadplane.h index 15daf859af..4c333888b3 100644 --- a/ArduPlane/quadplane.h +++ b/ArduPlane/quadplane.h @@ -480,6 +480,7 @@ private: float current_tilt; float current_throttle; bool motors_active:1; + float transition_yaw; } tilt; // bit 0 enables plane mode and bit 1 enables body-frame roll mode @@ -542,8 +543,7 @@ private: void tiltrotor_binary_update(void); void tiltrotor_vectored_yaw(void); void tiltrotor_bicopter(void); - void tilt_compensate_up(float *thrust, uint8_t num_motors); - void tilt_compensate_down(float *thrust, uint8_t num_motors); + void tilt_compensate_angle(float *thrust, uint8_t num_motors, float non_tilted_mul, float tilted_mul); void tilt_compensate(float *thrust, uint8_t num_motors); bool is_motor_tilting(uint8_t motor) const { return (((uint8_t)tilt.tilt_mask.get()) & (1U< 0.98f) { - inv_tilt_factor = 1.0 / cosf(radians(0.98f*90)); - } else { - inv_tilt_factor = 1.0 / cosf(radians(tilt.current_tilt*90)); - } - - // when we got past Q_TILT_MAX we gang the tilted motors together - // to generate equal thrust. This makes them act as a single pitch - // control motor while preventing them trying to do roll and yaw - // control while angled over. This greatly improves the stability - // of the last phase of transitions - float tilt_threshold = (tilt.max_angle_deg/90.0f); - bool equal_thrust = (tilt.current_tilt > tilt_threshold); - float tilt_total = 0; uint8_t tilt_count = 0; - // apply inv_tilt_factor first + // apply tilt_factors first for (uint8_t i=0; iget_roll_factor(i) * motors->get_yaw() * sin_tilt * yaw_gain; + thrust[i] += diff_thrust; largest_tilted = MAX(largest_tilted, thrust[i]); } } - // if we are saturating one of the tilted motors then reduce all - // motors to keep them in proportion to the original thrust. This - // helps maintain stability when tilted at a large angle + // if we are saturating one of the motors then reduce all motors + // to keep them in proportion to the original thrust. This helps + // maintain stability when tilted at a large angle if (largest_tilted > 1.0f) { float scale = 1.0f / largest_tilted; for (uint8_t i=0; i tilt_threshold); - - float tilt_total = 0; - uint8_t tilt_count = 0; - - // apply tilt_factor first - for (uint8_t i=0; i 0.98f) { + inv_tilt_factor = 1.0 / cosf(radians(0.98f*90)); + } else { + inv_tilt_factor = 1.0 / cosf(radians(tilt.current_tilt*90)); + } + tilt_compensate_angle(thrust, num_motors, 1, inv_tilt_factor); } } @@ -386,8 +342,8 @@ void QuadPlane::tiltrotor_vectored_yaw(void) yaw_out /= plane.channel_rudder->get_range(); float yaw_range = zero_out; - SRV_Channels::set_output_scaled(SRV_Channel::k_tiltMotorLeft, 1000 * (base_output + yaw_out * yaw_range)); - SRV_Channels::set_output_scaled(SRV_Channel::k_tiltMotorRight, 1000 * (base_output - yaw_out * yaw_range)); + SRV_Channels::set_output_scaled(SRV_Channel::k_tiltMotorLeft, 1000 * constrain_float(base_output + yaw_out * yaw_range,0,1)); + SRV_Channels::set_output_scaled(SRV_Channel::k_tiltMotorRight, 1000 * constrain_float(base_output - yaw_out * yaw_range,0,1)); } return; } @@ -398,11 +354,22 @@ void QuadPlane::tiltrotor_vectored_yaw(void) SRV_Channels::set_output_scaled(SRV_Channel::k_tiltMotorLeft, 1000 * base_output); SRV_Channels::set_output_scaled(SRV_Channel::k_tiltMotorRight, 1000 * base_output); } else { - float yaw_out = motors->get_yaw(); + const float yaw_out = motors->get_yaw(); + const float roll_out = motors->get_roll(); float yaw_range = zero_out; - SRV_Channels::set_output_scaled(SRV_Channel::k_tiltMotorLeft, 1000 * (base_output + yaw_out * yaw_range)); - SRV_Channels::set_output_scaled(SRV_Channel::k_tiltMotorRight, 1000 * (base_output - yaw_out * yaw_range)); + // now apply vectored thrust for yaw and roll. + const float tilt_rad = radians(tilt.current_tilt*90); + const float sin_tilt = sinf(tilt_rad); + const float cos_tilt = cosf(tilt_rad); + // the MotorsMatrix library normalises roll factor to 0.5, so + // we need to use the same factor here to keep the same roll + // gains when tilted as we have when not tilted + const float avg_roll_factor = 0.5; + const float tilt_offset = constrain_float(yaw_out * cos_tilt + avg_roll_factor * roll_out * sin_tilt, -1, 1); + + SRV_Channels::set_output_scaled(SRV_Channel::k_tiltMotorLeft, 1000 * constrain_float(base_output + tilt_offset * yaw_range,0,1)); + SRV_Channels::set_output_scaled(SRV_Channel::k_tiltMotorRight, 1000 * constrain_float(base_output - tilt_offset * yaw_range,0,1)); } }