diff --git a/libraries/AP_Motors/AP_MotorsHeli.cpp b/libraries/AP_Motors/AP_MotorsHeli.cpp index 94b08030c9..b37fe011c3 100644 --- a/libraries/AP_Motors/AP_MotorsHeli.cpp +++ b/libraries/AP_Motors/AP_MotorsHeli.cpp @@ -200,7 +200,7 @@ bool AP_MotorsHeli::parameter_check() const } // returns false if RSC Mode is not set to a valid control mode - if (_rsc_mode <= AP_MOTORS_HELI_RSC_MODE_NONE || _rsc_mode > AP_MOTORS_HELI_RSC_MODE_SETPOINT) { + if (_rsc_mode <= AP_MOTORS_HELI_RSC_MODE_DISABLED || _rsc_mode > AP_MOTORS_HELI_RSC_MODE_SETPOINT) { return false; } diff --git a/libraries/AP_Motors/AP_MotorsHeli.h b/libraries/AP_Motors/AP_MotorsHeli.h index c143d8f557..f9cb8055b1 100644 --- a/libraries/AP_Motors/AP_MotorsHeli.h +++ b/libraries/AP_Motors/AP_MotorsHeli.h @@ -37,7 +37,7 @@ #define AP_MOTORS_HELI_LAND_COLLECTIVE_MIN 0 // main rotor speed control types (ch8 out) -#define AP_MOTORS_HELI_RSC_MODE_NONE 0 // not a valid RSC Mode +#define AP_MOTORS_HELI_RSC_MODE_DISABLED 0 // not a valid RSC Mode #define AP_MOTORS_HELI_RSC_MODE_CH8_PASSTHROUGH 1 // main rotor ESC is connected to RC8 (out), pilot desired rotor speed provided by CH8 input #define AP_MOTORS_HELI_RSC_MODE_SETPOINT 2 // main rotor ESC is connected to RC8 (out), desired speed is held in RSC_SETPOINT parameter @@ -120,7 +120,7 @@ public: // set_collective_for_landing - limits collective from going too low if we know we are landed void set_collective_for_landing(bool landing) { _heliflags.landing_collective = landing; } - // get_rsc_mode - gets the rotor speed control method (AP_MOTORS_HELI_RSC_MODE_NONE, AP_MOTORS_HELI_RSC_MODE_CH8_PASSTHROUGH or AP_MOTORS_HELI_RSC_MODE_SETPOINT) + // get_rsc_mode - gets the rotor speed control method (AP_MOTORS_HELI_RSC_MODE_CH8_PASSTHROUGH or AP_MOTORS_HELI_RSC_MODE_SETPOINT) uint8_t get_rsc_mode() const { return _rsc_mode; } // get_rsc_setpoint - gets contents of _rsc_setpoint parameter (0~1000) @@ -132,8 +132,8 @@ public: // get_desired_rotor_speed - gets target rotor speed as a number from 0 ~ 1000 virtual int16_t get_desired_rotor_speed() const = 0; - // get_estimated_rotor_speed - gets estimated rotor speed as a number from 0 ~ 1000 - virtual int16_t get_estimated_rotor_speed() const = 0; + // get_main_rotor_speed - gets estimated or measured main rotor speed + virtual int16_t get_main_rotor_speed() const = 0; // return true if the main rotor is up to speed bool rotor_runup_complete() const { return _heliflags.rotor_runup_complete; } diff --git a/libraries/AP_Motors/AP_MotorsHeli_RSC.cpp b/libraries/AP_Motors/AP_MotorsHeli_RSC.cpp index 20f3de3715..552a6acb4e 100644 --- a/libraries/AP_Motors/AP_MotorsHeli_RSC.cpp +++ b/libraries/AP_Motors/AP_MotorsHeli_RSC.cpp @@ -36,7 +36,7 @@ void AP_MotorsHeli_RSC::recalc_scalers() _ramp_time = 1; } - _ramp_increment = 1000.0f / (_ramp_time * _loop_rate); + _ramp_increment = 1.0f / (_ramp_time * _loop_rate); // recalculate rotor runup increment if (_runup_time <= 0 ) { @@ -47,7 +47,7 @@ void AP_MotorsHeli_RSC::recalc_scalers() _runup_time = _ramp_time; } - _runup_increment = 1000.0f / (_runup_time * _loop_rate); + _runup_increment = 1.0f / (_runup_time * _loop_rate); } // output - update value to send to ESC/Servo @@ -55,89 +55,113 @@ void AP_MotorsHeli_RSC::output(uint8_t state) { switch (state){ case ROTOR_CONTROL_STOP: - _control_speed = 0; // ramp input to zero - _control_out = 0; // force ramp output to zero - _estimated_speed = 0; // force speed estimate to zero + // set rotor ramp to decrease speed to zero, this happens instantly inside update_rotor_ramp() + update_rotor_ramp(0.0f); + + // control output forced to zero + _control_speed = 0; break; case ROTOR_CONTROL_IDLE: - _control_speed = _idle_speed; // set control speed to idle speed - if (_control_out < _idle_speed){ - _control_out = _idle_speed; // if control output is less than idle speed, force ramp function to jump to idle speed - } + // set rotor ramp to decrease speed to zero + update_rotor_ramp(0.0f); + + // set rotor control speed to idle speed parameter, this happens instantly and ignore ramping + _control_speed = _idle_speed; break; case ROTOR_CONTROL_ACTIVE: - _control_speed = _desired_speed; // set control speed to desired speed + // set main rotor ramp to increase to full speed + update_rotor_ramp(1.0f); + + if ((_control_mode == ROTOR_CONTROL_MODE_PASSTHROUGH) || (_control_mode == ROTOR_CONTROL_MODE_SETPOINT)) { + // set control rotor speed to ramp slewed value between idle and desired speed + _control_speed = _idle_speed + (_rotor_ramp_output * (_desired_speed - _idle_speed)); + } break; } - // run speed ramp function to slew output smoothly - speed_ramp(_control_speed); - - // update rotor speed estimate - update_speed_estimate(); + // update rotor speed run-up estimate + update_rotor_runup(); // output to rsc servo - write_rsc(_control_out); + write_rsc(_control_speed); } -// speed_ramp - ramps speed towards target, result put in _control_out -void AP_MotorsHeli_RSC::speed_ramp(int16_t speed_target) +// update_rotor_ramp - slews rotor output scalar between 0 and 1, outputs float scalar to _rotor_ramp_output +void AP_MotorsHeli_RSC::update_rotor_ramp(float rotor_ramp_input) { - // range check speed_target - speed_target = constrain_int16(speed_target,0,1000); - // ramp output upwards towards target - if (_control_out < speed_target) { + if (_rotor_ramp_output < rotor_ramp_input) { // allow control output to jump to estimated speed - if (_control_out < _estimated_speed) { - _control_out = _estimated_speed; + if (_rotor_ramp_output < _rotor_runup_output) { + _rotor_ramp_output = _rotor_runup_output; } // ramp up slowly to target - _control_out += _ramp_increment; - if (_control_out > speed_target) { - _control_out = speed_target; + _rotor_ramp_output += _ramp_increment; + if (_rotor_ramp_output > rotor_ramp_input) { + _rotor_ramp_output = rotor_ramp_input; } }else{ // ramping down happens instantly - _control_out = speed_target; + _rotor_ramp_output = rotor_ramp_input; } - - } -// update_speed_estimate - function to estimate speed -void AP_MotorsHeli_RSC::update_speed_estimate() +// update_rotor_runup - function to slew rotor runup scalar, outputs float scalar to _rotor_runup_ouptut +void AP_MotorsHeli_RSC::update_rotor_runup() { // ramp speed estimate towards control out - if (_estimated_speed < _control_out) { - _estimated_speed += _runup_increment; - if (_estimated_speed > _control_out) { - _estimated_speed = _control_out; + if (_rotor_runup_output < _rotor_ramp_output) { + _rotor_runup_output += _runup_increment; + if (_rotor_runup_output > _rotor_ramp_output) { + _rotor_runup_output = _rotor_ramp_output; } }else{ - _estimated_speed -= _runup_increment; - if (_estimated_speed < _control_out) { - _estimated_speed = _control_out; + _rotor_runup_output -= _runup_increment; + if (_rotor_runup_output < _rotor_ramp_output) { + _rotor_runup_output = _rotor_ramp_output; } } // update run-up complete flag - if (!_runup_complete && _control_out > _idle_speed && _estimated_speed >= _control_out) { + + // if control mode is disabled, then run-up complete always returns true + if ( _control_mode == ROTOR_CONTROL_MODE_DISABLED ){ + _runup_complete = true; + return; + } + + // if rotor ramp and runup are both at full speed, then run-up has been completed + if (!_runup_complete && (_rotor_ramp_output >= 1.0f) && (_rotor_runup_output >= 1.0f)) { _runup_complete = true; } - if (_runup_complete && _estimated_speed <= _critical_speed) { + // if rotor speed is less than critical speed, then run-up is not complete + // this will prevent the case where the target rotor speed is less than critical speed + if (_runup_complete && (get_rotor_speed() <= _critical_speed)) { _runup_complete = false; } } +// get_rotor_speed - gets rotor speed either as an estimate, or (ToDO) a measured value +int16_t AP_MotorsHeli_RSC::get_rotor_speed() const +{ + // if no actual measured rotor speed is available, estimate speed based on rotor runup scalar. + return (_rotor_runup_output * _max_speed); +} + // write_rsc - outputs pwm onto output rsc channel // servo_out parameter is of the range 0 ~ 1000 void AP_MotorsHeli_RSC::write_rsc(int16_t servo_out) { - _servo_output.servo_out = servo_out; - _servo_output.calc_pwm(); + if (_control_mode == ROTOR_CONTROL_MODE_DISABLED){ + // do not do servo output to avoid conflicting with other output on the channel + // ToDo: We should probably use RC_Channel_Aux to avoid this problem + return; + } else { + _servo_output.servo_out = servo_out; + _servo_output.calc_pwm(); - hal.rcout->write(_servo_output_channel, _servo_output.radio_out); + hal.rcout->write(_servo_output_channel, _servo_output.radio_out); + } } \ No newline at end of file diff --git a/libraries/AP_Motors/AP_MotorsHeli_RSC.h b/libraries/AP_Motors/AP_MotorsHeli_RSC.h index f06c4eddf2..fab3e6fc23 100644 --- a/libraries/AP_Motors/AP_MotorsHeli_RSC.h +++ b/libraries/AP_Motors/AP_MotorsHeli_RSC.h @@ -12,6 +12,11 @@ #define ROTOR_CONTROL_IDLE 1 #define ROTOR_CONTROL_ACTIVE 2 +// rotor control modes +#define ROTOR_CONTROL_MODE_DISABLED 0 +#define ROTOR_CONTROL_MODE_PASSTHROUGH 1 +#define ROTOR_CONTROL_MODE_SETPOINT 2 + class AP_MotorsHeli_RSC { public: AP_MotorsHeli_RSC(RC_Channel& servo_output, @@ -25,6 +30,9 @@ public: // init_servo - servo initialization on start-up void init_servo(); + // set_control_mode - sets control mode + void set_control_mode(int8_t mode) { _control_mode = mode; } + // set_critical_speed void set_critical_speed(int16_t critical_speed) { _critical_speed = critical_speed; } @@ -43,8 +51,8 @@ public: // get_control_speed int16_t get_control_speed() const { return _control_speed; } - // get_estimated_speed - int16_t get_estimated_speed() const { return _estimated_speed; } + // get_rotor_speed - return estimated or measured rotor speed + int16_t get_rotor_speed() const; // is_runup_complete bool is_runup_complete() const { return _runup_complete; } @@ -69,23 +77,25 @@ private: float _loop_rate; // main loop rate // internal variables + int8_t _control_mode = 0; // motor control mode, Passthrough or Setpoint int16_t _critical_speed = 0; // rotor speed below which flight is not possible int16_t _idle_speed = 0; // motor output idle speed + int16_t _max_speed = 1000; // rotor maximum speed. Placeholder value until we have measured speed input (ToDo) int16_t _desired_speed = 0; // latest desired rotor speed from pilot int16_t _control_speed = 0; // latest logic controlled rotor speed - float _control_out = 0; // latest output sent to the main rotor or an estimate of the rotors actual speed (whichever is higher) (0 ~ 1000) - float _estimated_speed = 0; // estimated speed of the main rotor (0~1000) - float _ramp_increment = 0; // the amount we can increase the rotor output during each 100hz iteration + float _rotor_ramp_output = 0; // scalar used to ramp rotor speed between _rsc_idle and full speed (0.0-1.0f) + float _rotor_runup_output = 0; // scalar used to store status of rotor run-up time (0.0-1.0f) + float _ramp_increment = 0; // the amount to increase/decrease the rotor ramp scalar during each iteration int8_t _ramp_time = 0; // time in seconds for the output to the main rotor's ESC to reach full speed int8_t _runup_time = 0; // time in seconds for the main rotor to reach full speed. Must be longer than _rsc_ramp_time - float _runup_increment = 0; // the amount we can increase the rotor's estimated speed during each 100hz iteration + float _runup_increment = 0; // the amount to increase/decrease the rotor run-up scalar during each iteration bool _runup_complete = false; // flag for determining if runup is complete - // speed_ramp - ramps speed towards target, result put in _control_out - void speed_ramp(int16_t rotor_target); + // update_rotor_ramp - slews rotor output scalar between 0 and 1, outputs float scalar to _rotor_ramp_output + void update_rotor_ramp(float rotor_ramp_input); - // update_speed_estimate - function to estimate speed - void update_speed_estimate(); + // update_rotor_runup - function to slew rotor runup scalar, outputs float scalar to _rotor_runup_ouptut + void update_rotor_runup(); // write_rsc - outputs pwm onto output rsc channel. servo_out parameter is of the range 0 ~ 1000 void write_rsc(int16_t servo_out); diff --git a/libraries/AP_Motors/AP_MotorsHeli_Single.cpp b/libraries/AP_Motors/AP_MotorsHeli_Single.cpp index 241d851a70..7d79bd095e 100644 --- a/libraries/AP_Motors/AP_MotorsHeli_Single.cpp +++ b/libraries/AP_Motors/AP_MotorsHeli_Single.cpp @@ -195,7 +195,7 @@ void AP_MotorsHeli_Single::output_test(uint8_t motor_seq, int16_t pwm) bool AP_MotorsHeli_Single::allow_arming() const { // returns false if main rotor speed is not zero - if (_main_rotor.get_estimated_speed() > 0) { + if (_main_rotor.get_rotor_speed() > 0) { return false; } @@ -209,40 +209,39 @@ void AP_MotorsHeli_Single::set_desired_rotor_speed(int16_t desired_speed) { _main_rotor.set_desired_speed(desired_speed); - if (desired_speed > 0 && _tail_type == AP_MOTORS_HELI_SINGLE_TAILTYPE_DIRECTDRIVE_VARPITCH) { + if (_tail_type == AP_MOTORS_HELI_SINGLE_TAILTYPE_DIRECTDRIVE_VARPITCH) { _tail_rotor.set_desired_speed(_direct_drive_tailspeed); } else { _tail_rotor.set_desired_speed(0); } } - -// recalc_scalers - recalculates various scalers used. Should be called at about 1hz to allow users to see effect of changing parameters +// recalc_scalers - recalculates various scalers used. void AP_MotorsHeli_Single::recalc_scalers() { - + _main_rotor.set_control_mode(_rsc_mode); _main_rotor.set_ramp_time(_rsc_ramp_time); _main_rotor.set_runup_time(_rsc_runup_time); _main_rotor.set_critical_speed(_rsc_critical); _main_rotor.set_idle_speed(_rsc_idle); _main_rotor.recalc_scalers(); - if (_rsc_mode != AP_MOTORS_HELI_SINGLE_TAILTYPE_DIRECTDRIVE_VARPITCH) { - _tail_rotor.set_ramp_time(0); - _tail_rotor.set_runup_time(0); - _tail_rotor.set_critical_speed(0); - _tail_rotor.set_idle_speed(0); - } else { + if (_rsc_mode == AP_MOTORS_HELI_SINGLE_TAILTYPE_DIRECTDRIVE_VARPITCH) { + _tail_rotor.set_control_mode(AP_MOTORS_HELI_RSC_MODE_SETPOINT); _tail_rotor.set_ramp_time(_rsc_ramp_time); _tail_rotor.set_runup_time(_rsc_runup_time); _tail_rotor.set_critical_speed(_rsc_critical); _tail_rotor.set_idle_speed(_rsc_idle); + } else { + _tail_rotor.set_control_mode(AP_MOTORS_HELI_RSC_MODE_DISABLED); + _tail_rotor.set_ramp_time(0); + _tail_rotor.set_runup_time(0); + _tail_rotor.set_critical_speed(0); + _tail_rotor.set_idle_speed(0); } - _tail_rotor.recalc_scalers(); } - // get_motor_mask - returns a bitmask of which outputs are being used for motors or servos (1 means being used) // this can be used to ensure other pwm outputs (i.e. for servos) do not conflict uint16_t AP_MotorsHeli_Single::get_motor_mask() diff --git a/libraries/AP_Motors/AP_MotorsHeli_Single.h b/libraries/AP_Motors/AP_MotorsHeli_Single.h index 57d1daa3aa..645ddecc7a 100644 --- a/libraries/AP_Motors/AP_MotorsHeli_Single.h +++ b/libraries/AP_Motors/AP_MotorsHeli_Single.h @@ -87,16 +87,16 @@ public: // set_desired_rotor_speed - sets target rotor speed as a number from 0 ~ 1000 void set_desired_rotor_speed(int16_t desired_speed); - // get_estimated_rotor_speed - gets estimated rotor speed as a number from 0 ~ 1000 - int16_t get_estimated_rotor_speed() const { return _main_rotor.get_estimated_speed(); } + // get_main_rotor_speed - gets estimated or measured main rotor speed + int16_t get_main_rotor_speed() const { return _main_rotor.get_rotor_speed(); } // get_desired_rotor_speed - gets target rotor speed as a number from 0 ~ 1000 int16_t get_desired_rotor_speed() const { return _main_rotor.get_desired_speed(); } // rotor_speed_above_critical - return true if rotor speed is above that critical for flight - bool rotor_speed_above_critical() const { return _main_rotor.get_estimated_speed() > _main_rotor.get_critical_speed(); } + bool rotor_speed_above_critical() const { return _main_rotor.get_rotor_speed() > _main_rotor.get_critical_speed(); } - // recalc_scalers - recalculates various scalers used. Should be called at about 1hz to allow users to see effect of changing parameters + // recalc_scalers - recalculates various scalers used. void recalc_scalers(); // get_motor_mask - returns a bitmask of which outputs are being used for motors or servos (1 means being used)