123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742 |
- #include "AP_MotorsMulticopter.h"
- #include <AP_HAL/AP_HAL.h>
- #include <AP_BattMonitor/AP_BattMonitor.h>
- extern const AP_HAL::HAL& hal;
- const AP_Param::GroupInfo AP_MotorsMulticopter::var_info[] = {
-
-
-
-
-
-
-
-
-
- AP_GROUPINFO("YAW_HEADROOM", 6, AP_MotorsMulticopter, _yaw_headroom, AP_MOTORS_YAW_HEADROOM_DEFAULT),
-
-
-
-
-
-
- AP_GROUPINFO("THST_EXPO", 8, AP_MotorsMulticopter, _thrust_curve_expo, AP_MOTORS_THST_EXPO_DEFAULT),
-
-
-
-
-
- AP_GROUPINFO("SPIN_MAX", 9, AP_MotorsMulticopter, _spin_max, AP_MOTORS_SPIN_MAX_DEFAULT),
-
-
-
-
-
-
- AP_GROUPINFO("BAT_VOLT_MAX", 10, AP_MotorsMulticopter, _batt_voltage_max, AP_MOTORS_BAT_VOLT_MAX_DEFAULT),
-
-
-
-
-
-
- AP_GROUPINFO("BAT_VOLT_MIN", 11, AP_MotorsMulticopter, _batt_voltage_min, AP_MOTORS_BAT_VOLT_MIN_DEFAULT),
-
-
-
-
-
-
- AP_GROUPINFO("BAT_CURR_MAX", 12, AP_MotorsMulticopter, _batt_current_max, AP_MOTORS_BAT_CURR_MAX_DEFAULT),
-
-
-
-
-
-
-
- AP_GROUPINFO("PWM_TYPE", 15, AP_MotorsMulticopter, _pwm_type, PWM_TYPE_NORMAL),
-
-
-
-
-
-
- AP_GROUPINFO("PWM_MIN", 16, AP_MotorsMulticopter, _pwm_min, 0),
-
-
-
-
-
-
- AP_GROUPINFO("PWM_MAX", 17, AP_MotorsMulticopter, _pwm_max, 0),
-
-
-
-
-
- AP_GROUPINFO("SPIN_MIN", 18, AP_MotorsMulticopter, _spin_min, AP_MOTORS_SPIN_MIN_DEFAULT),
-
-
-
-
-
- AP_GROUPINFO("SPIN_ARM", 19, AP_MotorsMulticopter, _spin_arm, AP_MOTORS_SPIN_ARM_DEFAULT),
-
-
-
-
-
-
- AP_GROUPINFO("BAT_CURR_TC", 20, AP_MotorsMulticopter, _batt_current_time_constant, AP_MOTORS_BAT_CURR_TC_DEFAULT),
-
-
-
-
-
- AP_GROUPINFO("THST_HOVER", 21, AP_MotorsMulticopter, _throttle_hover, AP_MOTORS_THST_HOVER_DEFAULT),
-
-
-
-
-
-
-
- AP_GROUPINFO("HOVER_LEARN", 22, AP_MotorsMulticopter, _throttle_hover_learn, HOVER_LEARN_AND_SAVE),
-
-
-
-
-
- AP_GROUPINFO("SAFE_DISARM", 23, AP_MotorsMulticopter, _disarm_disable_pwm, 0),
-
-
-
-
-
-
-
- AP_GROUPINFO_FRAME("YAW_SV_ANGLE", 35, AP_MotorsMulticopter, _yaw_servo_angle_max_deg, 30, AP_PARAM_FRAME_TRICOPTER),
-
-
-
-
-
-
-
- AP_GROUPINFO("SPOOL_TIME", 36, AP_MotorsMulticopter, _spool_up_time, AP_MOTORS_SPOOL_UP_TIME_DEFAULT),
-
-
-
-
-
-
- AP_GROUPINFO("BOOST_SCALE", 37, AP_MotorsMulticopter, _boost_scale, 0),
-
-
-
-
-
-
-
- AP_GROUPINFO("BAT_IDX", 39, AP_MotorsMulticopter, _batt_idx, 0),
-
-
-
-
-
-
-
- AP_GROUPINFO("SLEW_UP_TIME", 40, AP_MotorsMulticopter, _slew_up_time, AP_MOTORS_SLEW_TIME_DEFAULT),
-
-
-
-
-
-
-
- AP_GROUPINFO("SLEW_DN_TIME", 41, AP_MotorsMulticopter, _slew_dn_time, AP_MOTORS_SLEW_TIME_DEFAULT),
- AP_GROUPEND
- };
- AP_MotorsMulticopter::AP_MotorsMulticopter(uint16_t loop_rate, uint16_t speed_hz) :
- AP_Motors(loop_rate, speed_hz),
- _lift_max(1.0f),
- _throttle_limit(1.0f)
- {
- AP_Param::setup_object_defaults(this, var_info);
-
- _batt_voltage_filt.set_cutoff_frequency(AP_MOTORS_BATT_VOLT_FILT_HZ);
- _batt_voltage_filt.reset(1.0f);
-
- _throttle_radio_min = 1100;
- _throttle_radio_max = 1900;
- };
- void AP_MotorsMulticopter::output()
- {
-
- update_throttle_filter();
-
- update_lift_max_from_batt_voltage();
-
- output_logic();
-
- output_armed_stabilizing();
-
- thrust_compensation();
-
- output_to_PWM();
-
- output_boost_throttle();
- };
- void AP_MotorsMulticopter::output_boost_throttle(void)
- {
- if (_boost_scale > 0) {
- float throttle = constrain_float(get_throttle() * _boost_scale, 0, 1);
- SRV_Channels::set_output_scaled(SRV_Channel::k_boost_throttle, throttle * 1000);
- }
- }
- void AP_MotorsMulticopter::output_min()
- {
- set_desired_spool_state(DesiredSpoolState::SHUT_DOWN);
- _spool_state = SpoolState::SHUT_DOWN;
- output();
- }
- void AP_MotorsMulticopter::update_throttle_filter()
- {
- if (armed()) {
- _throttle_filter.apply(_throttle_in, 1.0f / _loop_rate);
-
- if (_throttle_filter.get() < 0.0f) {
- _throttle_filter.reset(0.0f);
- }
- if (_throttle_filter.get() > 1.0f) {
- _throttle_filter.reset(1.0f);
- }
- } else {
- _throttle_filter.reset(0.0f);
- }
- }
- float AP_MotorsMulticopter::get_current_limit_max_throttle()
- {
- AP_BattMonitor &battery = AP::battery();
- float _batt_current;
- if (_batt_current_max <= 0 ||
- !_flags.armed ||
- !battery.current_amps(_batt_current, _batt_idx)) {
- _throttle_limit = 1.0f;
- return 1.0f;
- }
- float _batt_resistance = battery.get_resistance(_batt_idx);
- if (is_zero(_batt_resistance)) {
- _throttle_limit = 1.0f;
- return 1.0f;
- }
-
- float batt_current_max = MIN(_batt_current_max, _batt_current + (battery.voltage(_batt_idx) - _batt_voltage_min) / _batt_resistance);
- float batt_current_ratio = _batt_current / batt_current_max;
- float loop_interval = 1.0f / _loop_rate;
- _throttle_limit += (loop_interval / (loop_interval + _batt_current_time_constant)) * (1.0f - batt_current_ratio);
-
- _throttle_limit = constrain_float(_throttle_limit, 0.2f, 1.0f);
-
- return get_throttle_hover() + ((1.0 - get_throttle_hover()) * _throttle_limit);
- }
- float AP_MotorsMulticopter::apply_thrust_curve_and_volt_scaling(float thrust) const
- {
- float throttle_ratio = thrust;
-
- float thrust_curve_expo = constrain_float(_thrust_curve_expo, -1.0f, 1.0f);
- if (fabsf(thrust_curve_expo) < 0.001) {
-
- return thrust;
- }
- if (!is_zero(_batt_voltage_filt.get())) {
- throttle_ratio = ((thrust_curve_expo - 1.0f) + safe_sqrt((1.0f - thrust_curve_expo) * (1.0f - thrust_curve_expo) + 4.0f * thrust_curve_expo * _lift_max * thrust)) / (2.0f * thrust_curve_expo * _batt_voltage_filt.get());
- } else {
- throttle_ratio = ((thrust_curve_expo - 1.0f) + safe_sqrt((1.0f - thrust_curve_expo) * (1.0f - thrust_curve_expo) + 4.0f * thrust_curve_expo * _lift_max * thrust)) / (2.0f * thrust_curve_expo);
- }
- return constrain_float(throttle_ratio, 0.0f, 1.0f);
- }
- void AP_MotorsMulticopter::update_lift_max_from_batt_voltage()
- {
-
-
- float _batt_voltage_resting_estimate = AP::battery().voltage_resting_estimate(_batt_idx);
- if ((_batt_voltage_max <= 0) || (_batt_voltage_min >= _batt_voltage_max) || (_batt_voltage_resting_estimate < 0.25f * _batt_voltage_min)) {
- _batt_voltage_filt.reset(1.0f);
- _lift_max = 1.0f;
- return;
- }
- _batt_voltage_min = MAX(_batt_voltage_min, _batt_voltage_max * 0.6f);
-
- _batt_voltage_resting_estimate = constrain_float(_batt_voltage_resting_estimate, _batt_voltage_min, _batt_voltage_max);
-
- float batt_voltage_filt = _batt_voltage_filt.apply(_batt_voltage_resting_estimate / _batt_voltage_max, 1.0f / _loop_rate);
-
- float thrust_curve_expo = constrain_float(_thrust_curve_expo, -1.0f, 1.0f);
- _lift_max = batt_voltage_filt * (1 - thrust_curve_expo) + thrust_curve_expo * batt_voltage_filt * batt_voltage_filt;
- }
- float AP_MotorsMulticopter::get_compensation_gain() const
- {
-
- if (_lift_max <= 0.0f) {
- return 1.0f;
- }
- float ret = 1.0f / _lift_max;
- #if AP_MOTORS_DENSITY_COMP == 1
-
- if (_air_density_ratio > 0.3f && _air_density_ratio < 1.5f) {
- ret *= 1.0f / constrain_float(_air_density_ratio, 0.5f, 1.25f);
- }
- #endif
- return ret;
- }
- int16_t AP_MotorsMulticopter::output_to_pwm(float actuator)
- {
- float pwm_output;
- if (_spool_state == SpoolState::SHUT_DOWN) {
-
- if (_disarm_disable_pwm && _disarm_safety_timer == 0 && !armed()) {
- pwm_output = 0;
- } else {
- pwm_output = get_pwm_output_min();
- }
- } else {
-
- pwm_output = get_pwm_output_min() + (get_pwm_output_max() - get_pwm_output_min()) * actuator;
- }
- return pwm_output;
- }
- float AP_MotorsMulticopter::thrust_to_actuator(float thrust_in)
- {
- thrust_in = constrain_float(thrust_in, 0.0f, 1.0f);
- return _spin_min + (_spin_max - _spin_min) * apply_thrust_curve_and_volt_scaling(thrust_in);
- }
- void AP_MotorsMulticopter::set_actuator_with_slew(float& actuator_output, float input)
- {
-
-
- float output_slew_limit_up = 1.0f;
- float output_slew_limit_dn = 0.0f;
-
- if (is_positive(_slew_up_time)) {
- float output_delta_up_max = 1.0f / (constrain_float(_slew_up_time, 0.0f, 0.5f) * _loop_rate);
- output_slew_limit_up = constrain_float(actuator_output + output_delta_up_max, 0.0f, 1.0f);
- }
-
- if (is_positive(_slew_dn_time)) {
- float output_delta_dn_max = 1.0f / (constrain_float(_slew_dn_time, 0.0f, 0.5f) * _loop_rate);
- output_slew_limit_dn = constrain_float(actuator_output - output_delta_dn_max, 0.0f, 1.0f);
- }
-
- actuator_output = constrain_float(input, output_slew_limit_dn, output_slew_limit_up);
- }
- float AP_MotorsMulticopter::actuator_spin_up_to_ground_idle() const
- {
- return constrain_float(_spin_up_ratio, 0.0f, 1.0f) * _spin_min;
- }
- int16_t AP_MotorsMulticopter::get_pwm_output_min() const
- {
-
- if ((_pwm_min > 0) && (_pwm_max > 0) && (_pwm_max > _pwm_min)) {
- return _pwm_min;
- }
- return _throttle_radio_min;
- }
- int16_t AP_MotorsMulticopter::get_pwm_output_max() const
- {
-
- if ((_pwm_min > 0) && (_pwm_max > 0) && (_pwm_max > _pwm_min)) {
- return _pwm_max;
- }
- return _throttle_radio_max;
- }
- void AP_MotorsMulticopter::set_throttle_range(int16_t radio_min, int16_t radio_max)
- {
-
- if (radio_max <= radio_min) {
- return;
- }
- _throttle_radio_min = radio_min;
- _throttle_radio_max = radio_max;
- if (_pwm_type >= PWM_TYPE_DSHOT150 && _pwm_type <= PWM_TYPE_DSHOT1200) {
-
- _pwm_min.set(1000);
- _pwm_max.set(2000);
- }
- hal.rcout->set_esc_scaling(get_pwm_output_min(), get_pwm_output_max());
- }
- void AP_MotorsMulticopter::update_throttle_hover(float dt)
- {
- if (_throttle_hover_learn != HOVER_LEARN_DISABLED) {
-
- _throttle_hover = constrain_float(_throttle_hover + (dt / (dt + AP_MOTORS_THST_HOVER_TC)) * (get_throttle() - _throttle_hover), AP_MOTORS_THST_HOVER_MIN, AP_MOTORS_THST_HOVER_MAX);
- }
- }
- void AP_MotorsMulticopter::output_logic()
- {
- if (_flags.armed) {
- _disarm_safety_timer = 100;
- } else if (_disarm_safety_timer != 0) {
- _disarm_safety_timer--;
- }
-
- if (!_flags.armed || !_flags.interlock) {
- _spool_desired = DesiredSpoolState::SHUT_DOWN;
- _spool_state = SpoolState::SHUT_DOWN;
- }
- if (_spool_up_time < 0.05) {
-
- _spool_up_time.set(0.05);
- }
- switch (_spool_state) {
- case SpoolState::SHUT_DOWN:
-
-
-
- limit.roll = true;
- limit.pitch = true;
- limit.yaw = true;
- limit.throttle_lower = true;
- limit.throttle_upper = true;
-
- if (_spool_desired != DesiredSpoolState::SHUT_DOWN) {
- _spool_state = SpoolState::GROUND_IDLE;
- break;
- }
-
- _spin_up_ratio = 0.0f;
- _throttle_thrust_max = 0.0f;
-
- _thrust_boost = false;
- _thrust_boost_ratio = 0.0f;
- break;
- case SpoolState::GROUND_IDLE: {
-
-
-
- limit.roll = true;
- limit.pitch = true;
- limit.yaw = true;
- limit.throttle_lower = true;
- limit.throttle_upper = true;
-
- float spool_step = 1.0f / (_spool_up_time * _loop_rate);
- switch (_spool_desired) {
- case DesiredSpoolState::SHUT_DOWN:
- _spin_up_ratio -= spool_step;
-
- if (_spin_up_ratio <= 0.0f) {
- _spin_up_ratio = 0.0f;
- _spool_state = SpoolState::SHUT_DOWN;
- }
- break;
- case DesiredSpoolState::THROTTLE_UNLIMITED:
- _spin_up_ratio += spool_step;
-
- if (_spin_up_ratio >= 1.0f) {
- _spin_up_ratio = 1.0f;
- _spool_state = SpoolState::SPOOLING_UP;
- }
- break;
- case DesiredSpoolState::GROUND_IDLE:
- float spin_up_armed_ratio = 0.0f;
- if (_spin_min > 0.0f) {
- spin_up_armed_ratio = _spin_arm / _spin_min;
- }
- _spin_up_ratio += constrain_float(spin_up_armed_ratio - _spin_up_ratio, -spool_step, spool_step);
- break;
- }
- _throttle_thrust_max = 0.0f;
-
- _thrust_boost = false;
- _thrust_boost_ratio = 0.0f;
- break;
- }
- case SpoolState::SPOOLING_UP:
-
-
-
- limit.roll = false;
- limit.pitch = false;
- limit.yaw = false;
- limit.throttle_lower = false;
- limit.throttle_upper = false;
-
- if (_spool_desired != DesiredSpoolState::THROTTLE_UNLIMITED) {
- _spool_state = SpoolState::SPOOLING_DOWN;
- break;
- }
-
- _spin_up_ratio = 1.0f;
- _throttle_thrust_max += 1.0f / (_spool_up_time * _loop_rate);
-
- if (_throttle_thrust_max >= MIN(get_throttle(), get_current_limit_max_throttle())) {
- _throttle_thrust_max = get_current_limit_max_throttle();
- _spool_state = SpoolState::THROTTLE_UNLIMITED;
- } else if (_throttle_thrust_max < 0.0f) {
- _throttle_thrust_max = 0.0f;
- }
-
- _thrust_boost = false;
- _thrust_boost_ratio = MAX(0.0, _thrust_boost_ratio - 1.0 / (_spool_up_time * _loop_rate));
- break;
- case SpoolState::THROTTLE_UNLIMITED:
-
-
-
- limit.roll = false;
- limit.pitch = false;
- limit.yaw = false;
- limit.throttle_lower = false;
- limit.throttle_upper = false;
-
- if (_spool_desired != DesiredSpoolState::THROTTLE_UNLIMITED) {
- _spool_state = SpoolState::SPOOLING_DOWN;
- break;
- }
-
- _spin_up_ratio = 1.0f;
- _throttle_thrust_max = get_current_limit_max_throttle();
- if (_thrust_boost && !_thrust_balanced) {
- _thrust_boost_ratio = MIN(1.0, _thrust_boost_ratio + 1.0f / (_spool_up_time * _loop_rate));
- } else {
- _thrust_boost_ratio = MAX(0.0, _thrust_boost_ratio - 1.0f / (_spool_up_time * _loop_rate));
- }
- break;
- case SpoolState::SPOOLING_DOWN:
-
-
-
- limit.roll = false;
- limit.pitch = false;
- limit.yaw = false;
- limit.throttle_lower = false;
- limit.throttle_upper = false;
-
- if (_spool_desired == DesiredSpoolState::THROTTLE_UNLIMITED) {
- _spool_state = SpoolState::SPOOLING_UP;
- break;
- }
-
- _spin_up_ratio = 1.0f;
- _throttle_thrust_max -= 1.0f / (_spool_up_time * _loop_rate);
-
- if (_throttle_thrust_max <= 0.0f) {
- _throttle_thrust_max = 0.0f;
- }
- if (_throttle_thrust_max >= get_current_limit_max_throttle()) {
- _throttle_thrust_max = get_current_limit_max_throttle();
- } else if (is_zero(_throttle_thrust_max)) {
- _spool_state = SpoolState::GROUND_IDLE;
- }
- _thrust_boost_ratio = MAX(0.0, _thrust_boost_ratio - 1.0f / (_spool_up_time * _loop_rate));
- break;
- }
- }
- void AP_MotorsMulticopter::set_throttle_passthrough_for_esc_calibration(float throttle_input)
- {
- if (armed()) {
- uint16_t pwm_out = get_pwm_output_min() + constrain_float(throttle_input, 0.0f, 1.0f) * (get_pwm_output_max() - get_pwm_output_min());
-
- for (uint16_t i = 0; i < AP_MOTORS_MAX_NUM_MOTORS; i++) {
- if (motor_enabled[i]) {
- rc_write(i, pwm_out);
- }
- }
-
- SRV_Channels::set_output_pwm(SRV_Channel::k_throttleRight, pwm_out);
- SRV_Channels::set_output_pwm(SRV_Channel::k_throttleLeft, pwm_out);
- }
- }
- void AP_MotorsMulticopter::output_motor_mask(float thrust, uint8_t mask, float rudder_dt)
- {
- for (uint8_t i = 0; i < AP_MOTORS_MAX_NUM_MOTORS; i++) {
- if (motor_enabled[i]) {
- if (mask & (1U << i)) {
-
- float diff_thrust = get_roll_factor(i) * rudder_dt * 0.5f;
- set_actuator_with_slew(_actuator[i], thrust_to_actuator(thrust + diff_thrust));
- int16_t pwm_output = get_pwm_output_min() + (get_pwm_output_max() - get_pwm_output_min()) * _actuator[i];
- rc_write(i, pwm_output);
- } else {
- rc_write(i, get_pwm_output_min());
- }
- }
- }
- }
- uint16_t AP_MotorsMulticopter::get_motor_mask()
- {
- return SRV_Channels::get_output_channel_mask(SRV_Channel::k_boost_throttle);
- }
- void AP_MotorsMulticopter::save_params_on_disarm()
- {
-
- if (_throttle_hover_learn == HOVER_LEARN_AND_SAVE) {
- _throttle_hover.save();
- }
- }
|