#include "Copter.h"
#if FRAME_CONFIG == HELI_FRAME
#ifndef HELI_DYNAMIC_FLIGHT_SPEED_MIN
#define HELI_DYNAMIC_FLIGHT_SPEED_MIN 250
#endif
static int8_t heli_dynamic_flight_counter;
void Copter::heli_init()
{
input_manager.set_use_stab_col(true);
input_manager.set_collective_ramp(0);
}
void Copter::check_dynamic_flight(void)
{
if (motors->get_spool_state() != AP_Motors::SpoolState::THROTTLE_UNLIMITED ||
flightmode->is_landing()) {
heli_dynamic_flight_counter = 0;
heli_flags.dynamic_flight = false;
return;
}
bool moving = false;
Vector3f vel_ned_ms;
if (AP::ahrs().get_velocity_NED(vel_ned_ms)) {
moving = (vel_ned_ms.xy().length() * 100.0 >= HELI_DYNAMIC_FLIGHT_SPEED_MIN);
} else {
moving = (motors->get_throttle() > 0.8f || ahrs.get_pitch_deg() < -15);
}
#if AP_RANGEFINDER_ENABLED
if (!moving && rangefinder_state.enabled && rangefinder.status_orient(ROTATION_PITCH_270) == RangeFinder::Status::Good) {
moving = (rangefinder.distance_orient(ROTATION_PITCH_270) > 2);
}
#endif
if (moving) {
if (!heli_flags.dynamic_flight) {
heli_dynamic_flight_counter++;
if (heli_dynamic_flight_counter >= 100) {
heli_flags.dynamic_flight = true;
heli_dynamic_flight_counter = 100;
}
}
} else {
if (heli_flags.dynamic_flight) {
if (heli_dynamic_flight_counter > 0) {
heli_dynamic_flight_counter--;
} else {
heli_flags.dynamic_flight = false;
}
}
}
}
void Copter::update_heli_control_dynamics(void)
{
if (!motors->using_leaky_integrator()) {
attitude_control->use_leaky_i(false);
if (ap.land_complete || ap.land_complete_maybe) {
motors->set_land_complete(true);
} else {
motors->set_land_complete(false);
}
} else {
attitude_control->use_leaky_i(!heli_flags.dynamic_flight);
motors->set_land_complete(false);
}
if (ap.land_complete || (is_zero(motors->get_desired_rotor_speed()))) {
hover_roll_trim_scalar_slew--;
} else {
hover_roll_trim_scalar_slew++;
}
hover_roll_trim_scalar_slew = constrain_int16(hover_roll_trim_scalar_slew, 0, scheduler.get_loop_rate_hz());
attitude_control->set_hover_roll_trim_scalar((float) hover_roll_trim_scalar_slew/(float) scheduler.get_loop_rate_hz());
}
bool Copter::should_use_landing_swash() const
{
if (flightmode->has_manual_throttle() ||
flightmode->mode_number() == Mode::Number::DRIFT ||
attitude_control->get_inverted_flight()) {
return false;
}
if (flightmode->is_landing()) {
return true;
}
if (ap.land_complete) {
return true;
}
if (!ap.auto_armed) {
return true;
}
if (!heli_flags.dynamic_flight) {
return true;
}
return false;
}
void Copter::heli_update_landing_swash()
{
motors->set_collective_for_landing(should_use_landing_swash());
update_collective_low_flag(channel_throttle->get_control_in());
}
float Copter::get_pilot_desired_rotor_speed() const
{
RC_Channel *rc_ptr = rc().find_channel_for_option(RC_Channel::AUX_FUNC::MOTOR_INTERLOCK);
if (rc_ptr != nullptr) {
rc_ptr->set_range(1000);
return (float)rc_ptr->get_control_in() * 0.001f;
}
return 0.0f;
}
void Copter::heli_update_rotor_speed_targets()
{
uint8_t rsc_control_mode = motors->get_rsc_mode();
switch (rsc_control_mode) {
case ROTOR_CONTROL_MODE_PASSTHROUGH:
if (get_pilot_desired_rotor_speed() > 0.01) {
ap.motor_interlock_switch = true;
motors->set_desired_rotor_speed(get_pilot_desired_rotor_speed());
} else {
ap.motor_interlock_switch = false;
motors->set_desired_rotor_speed(0.0f);
}
break;
case ROTOR_CONTROL_MODE_SETPOINT:
case ROTOR_CONTROL_MODE_THROTTLECURVE:
case ROTOR_CONTROL_MODE_AUTOTHROTTLE:
if (motors->get_interlock()) {
motors->set_desired_rotor_speed(motors->get_rsc_setpoint());
} else {
motors->set_desired_rotor_speed(0.0f);
}
break;
}
}
void Copter::heli_update_autorotation()
{
bool in_autorotation_mode = false;
#if MODE_AUTOROTATE_ENABLED
in_autorotation_mode = flightmode == &mode_autorotate;
#endif
if (ap.land_complete || ap.land_complete_maybe) {
motors->force_deactivate_autorotation();
return;
}
if (!motors->get_interlock() && (flightmode->has_manual_throttle() || in_autorotation_mode)) {
motors->set_autorotation_active(true);
} else {
motors->set_autorotation_active(false);
}
}
void Copter::update_collective_low_flag(int16_t throttle_control)
{
static uint32_t last_nonzero_collective_ms = 0;
uint32_t tnow_ms = millis();
if (throttle_control > 0) {
last_nonzero_collective_ms = tnow_ms;
heli_flags.coll_stk_low = false;
} else if (tnow_ms - last_nonzero_collective_ms > 400) {
heli_flags.coll_stk_low = true;
}
}
#endif