mirror of
https://github.com/ArduPilot/ardupilot
synced 2025-01-03 06:28:27 -04:00
5f552a6ce3
These references were taken to make the breaking out of Modes in Copter. A lot of other code has already caused these sorts of things to go away, but these particular ones seem reasonable to fix by pointing the users at the copter object directly.
609 lines
19 KiB
C++
609 lines
19 KiB
C++
#include "Copter.h"
|
|
|
|
/*
|
|
* High level calls to set and update flight modes logic for individual
|
|
* flight modes is in control_acro.cpp, control_stabilize.cpp, etc
|
|
*/
|
|
|
|
/*
|
|
constructor for Mode object
|
|
*/
|
|
Copter::Mode::Mode(void) :
|
|
g(copter.g),
|
|
g2(copter.g2),
|
|
wp_nav(copter.wp_nav),
|
|
loiter_nav(copter.loiter_nav),
|
|
pos_control(copter.pos_control),
|
|
inertial_nav(copter.inertial_nav),
|
|
ahrs(copter.ahrs),
|
|
attitude_control(copter.attitude_control),
|
|
motors(copter.motors),
|
|
channel_roll(copter.channel_roll),
|
|
channel_pitch(copter.channel_pitch),
|
|
channel_throttle(copter.channel_throttle),
|
|
channel_yaw(copter.channel_yaw),
|
|
G_Dt(copter.G_Dt),
|
|
#if FRAME_CONFIG == HELI_FRAME
|
|
heli_flags(copter.heli_flags),
|
|
#endif
|
|
ap(copter.ap)
|
|
{ };
|
|
|
|
float Copter::Mode::auto_takeoff_no_nav_alt_cm = 0;
|
|
|
|
// return the static controller object corresponding to supplied mode
|
|
Copter::Mode *Copter::mode_from_mode_num(const uint8_t mode)
|
|
{
|
|
Copter::Mode *ret = nullptr;
|
|
|
|
switch (mode) {
|
|
#if MODE_ACRO_ENABLED == ENABLED
|
|
case ACRO:
|
|
ret = &mode_acro;
|
|
break;
|
|
#endif
|
|
|
|
case STABILIZE:
|
|
ret = &mode_stabilize;
|
|
break;
|
|
|
|
case ALT_HOLD:
|
|
ret = &mode_althold;
|
|
break;
|
|
|
|
#if MODE_AUTO_ENABLED == ENABLED
|
|
case AUTO:
|
|
ret = &mode_auto;
|
|
break;
|
|
#endif
|
|
|
|
#if MODE_CIRCLE_ENABLED == ENABLED
|
|
case CIRCLE:
|
|
ret = &mode_circle;
|
|
break;
|
|
#endif
|
|
|
|
#if MODE_LOITER_ENABLED == ENABLED
|
|
case LOITER:
|
|
ret = &mode_loiter;
|
|
break;
|
|
#endif
|
|
|
|
#if MODE_GUIDED_ENABLED == ENABLED
|
|
case GUIDED:
|
|
ret = &mode_guided;
|
|
break;
|
|
#endif
|
|
|
|
case LAND:
|
|
ret = &mode_land;
|
|
break;
|
|
|
|
#if MODE_RTL_ENABLED == ENABLED
|
|
case RTL:
|
|
ret = &mode_rtl;
|
|
break;
|
|
#endif
|
|
|
|
#if MODE_DRIFT_ENABLED == ENABLED
|
|
case DRIFT:
|
|
ret = &mode_drift;
|
|
break;
|
|
#endif
|
|
|
|
#if MODE_SPORT_ENABLED == ENABLED
|
|
case SPORT:
|
|
ret = &mode_sport;
|
|
break;
|
|
#endif
|
|
|
|
case FLIP:
|
|
ret = &mode_flip;
|
|
break;
|
|
|
|
#if AUTOTUNE_ENABLED == ENABLED
|
|
case AUTOTUNE:
|
|
ret = &mode_autotune;
|
|
break;
|
|
#endif
|
|
|
|
#if MODE_POSHOLD_ENABLED == ENABLED
|
|
case POSHOLD:
|
|
ret = &mode_poshold;
|
|
break;
|
|
#endif
|
|
|
|
#if MODE_BRAKE_ENABLED == ENABLED
|
|
case BRAKE:
|
|
ret = &mode_brake;
|
|
break;
|
|
#endif
|
|
|
|
#if MODE_THROW_ENABLED == ENABLED
|
|
case THROW:
|
|
ret = &mode_throw;
|
|
break;
|
|
#endif
|
|
|
|
#if ADSB_ENABLED == ENABLED
|
|
case AVOID_ADSB:
|
|
ret = &mode_avoid_adsb;
|
|
break;
|
|
#endif
|
|
|
|
#if MODE_GUIDED_NOGPS_ENABLED == ENABLED
|
|
case GUIDED_NOGPS:
|
|
ret = &mode_guided_nogps;
|
|
break;
|
|
#endif
|
|
|
|
#if MODE_SMARTRTL_ENABLED == ENABLED
|
|
case SMART_RTL:
|
|
ret = &mode_smartrtl;
|
|
break;
|
|
#endif
|
|
|
|
#if OPTFLOW == ENABLED
|
|
case FLOWHOLD:
|
|
ret = (Copter::Mode *)g2.mode_flowhold_ptr;
|
|
break;
|
|
#endif
|
|
|
|
#if MODE_FOLLOW_ENABLED == ENABLED
|
|
case FOLLOW:
|
|
ret = &mode_follow;
|
|
break;
|
|
#endif
|
|
|
|
#if MODE_ZIGZAG_ENABLED == ENABLED
|
|
case ZIGZAG:
|
|
ret = &mode_zigzag;
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
// set_mode - change flight mode and perform any necessary initialisation
|
|
// optional force parameter used to force the flight mode change (used only first time mode is set)
|
|
// returns true if mode was successfully set
|
|
// ACRO, STABILIZE, ALTHOLD, LAND, DRIFT and SPORT can always be set successfully but the return state of other flight modes should be checked and the caller should deal with failures appropriately
|
|
bool Copter::set_mode(control_mode_t mode, mode_reason_t reason)
|
|
{
|
|
|
|
// return immediately if we are already in the desired mode
|
|
if (mode == control_mode) {
|
|
control_mode_reason = reason;
|
|
return true;
|
|
}
|
|
|
|
Copter::Mode *new_flightmode = mode_from_mode_num(mode);
|
|
if (new_flightmode == nullptr) {
|
|
gcs().send_text(MAV_SEVERITY_WARNING,"No such mode");
|
|
Log_Write_Error(ERROR_SUBSYSTEM_FLIGHT_MODE,mode);
|
|
return false;
|
|
}
|
|
|
|
bool ignore_checks = !motors->armed(); // allow switching to any mode if disarmed. We rely on the arming check to perform
|
|
|
|
#if FRAME_CONFIG == HELI_FRAME
|
|
// do not allow helis to enter a non-manual throttle mode if the
|
|
// rotor runup is not complete
|
|
if (!ignore_checks && !new_flightmode->has_manual_throttle() && !motors->rotor_runup_complete()){
|
|
gcs().send_text(MAV_SEVERITY_WARNING,"Flight mode change failed");
|
|
Log_Write_Error(ERROR_SUBSYSTEM_FLIGHT_MODE,mode);
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
if (!new_flightmode->init(ignore_checks)) {
|
|
gcs().send_text(MAV_SEVERITY_WARNING,"Flight mode change failed");
|
|
Log_Write_Error(ERROR_SUBSYSTEM_FLIGHT_MODE,mode);
|
|
return false;
|
|
}
|
|
|
|
// perform any cleanup required by previous flight mode
|
|
exit_mode(flightmode, new_flightmode);
|
|
|
|
// update flight mode
|
|
flightmode = new_flightmode;
|
|
control_mode = mode;
|
|
control_mode_reason = reason;
|
|
DataFlash.Log_Write_Mode(control_mode, reason);
|
|
|
|
#if ADSB_ENABLED == ENABLED
|
|
adsb.set_is_auto_mode((mode == AUTO) || (mode == RTL) || (mode == GUIDED));
|
|
#endif
|
|
|
|
#if AC_FENCE == ENABLED
|
|
// pilot requested flight mode change during a fence breach indicates pilot is attempting to manually recover
|
|
// this flight mode change could be automatic (i.e. fence, battery, GPS or GCS failsafe)
|
|
// but it should be harmless to disable the fence temporarily in these situations as well
|
|
fence.manual_recovery_start();
|
|
#endif
|
|
|
|
#if FRSKY_TELEM_ENABLED == ENABLED
|
|
frsky_telemetry.update_control_mode(control_mode);
|
|
#endif
|
|
#if DEVO_TELEM_ENABLED == ENABLED
|
|
devo_telemetry.update_control_mode(control_mode);
|
|
#endif
|
|
|
|
#if CAMERA == ENABLED
|
|
camera.set_is_auto_mode(control_mode == AUTO);
|
|
#endif
|
|
|
|
// update notify object
|
|
notify_flight_mode();
|
|
|
|
// return success
|
|
return true;
|
|
}
|
|
|
|
// update_flight_mode - calls the appropriate attitude controllers based on flight mode
|
|
// called at 100hz or more
|
|
void Copter::update_flight_mode()
|
|
{
|
|
target_rangefinder_alt_used = false;
|
|
|
|
flightmode->run();
|
|
}
|
|
|
|
// exit_mode - high level call to organise cleanup as a flight mode is exited
|
|
void Copter::exit_mode(Copter::Mode *&old_flightmode,
|
|
Copter::Mode *&new_flightmode)
|
|
{
|
|
#if AUTOTUNE_ENABLED == ENABLED
|
|
if (old_flightmode == &mode_autotune) {
|
|
mode_autotune.stop();
|
|
}
|
|
#endif
|
|
|
|
// stop mission when we leave auto mode
|
|
#if MODE_AUTO_ENABLED == ENABLED
|
|
if (old_flightmode == &mode_auto) {
|
|
if (mission.state() == AP_Mission::MISSION_RUNNING) {
|
|
mission.stop();
|
|
}
|
|
#if MOUNT == ENABLED
|
|
camera_mount.set_mode_to_default();
|
|
#endif // MOUNT == ENABLED
|
|
}
|
|
#endif
|
|
|
|
// smooth throttle transition when switching from manual to automatic flight modes
|
|
if (old_flightmode->has_manual_throttle() && !new_flightmode->has_manual_throttle() && motors->armed() && !ap.land_complete) {
|
|
// this assumes all manual flight modes use get_pilot_desired_throttle to translate pilot input to output throttle
|
|
set_accel_throttle_I_from_pilot_throttle();
|
|
}
|
|
|
|
// cancel any takeoffs in progress
|
|
old_flightmode->takeoff_stop();
|
|
|
|
#if MODE_SMARTRTL_ENABLED == ENABLED
|
|
// call smart_rtl cleanup
|
|
if (old_flightmode == &mode_smartrtl) {
|
|
mode_smartrtl.exit();
|
|
}
|
|
#endif
|
|
|
|
#if FRAME_CONFIG == HELI_FRAME
|
|
// firmly reset the flybar passthrough to false when exiting acro mode.
|
|
if (old_flightmode == &mode_acro) {
|
|
attitude_control->use_flybar_passthrough(false, false);
|
|
motors->set_acro_tail(false);
|
|
}
|
|
|
|
// if we are changing from a mode that did not use manual throttle,
|
|
// stab col ramp value should be pre-loaded to the correct value to avoid a twitch
|
|
// heli_stab_col_ramp should really only be active switching between Stabilize and Acro modes
|
|
if (!old_flightmode->has_manual_throttle()){
|
|
if (new_flightmode == &mode_stabilize){
|
|
input_manager.set_stab_col_ramp(1.0);
|
|
} else if (new_flightmode == &mode_acro){
|
|
input_manager.set_stab_col_ramp(0.0);
|
|
}
|
|
}
|
|
#endif //HELI_FRAME
|
|
}
|
|
|
|
// notify_flight_mode - sets notify object based on current flight mode. Only used for OreoLED notify device
|
|
void Copter::notify_flight_mode() {
|
|
AP_Notify::flags.autopilot_mode = flightmode->is_autopilot();
|
|
AP_Notify::flags.flight_mode = control_mode;
|
|
notify.set_flight_mode_str(flightmode->name4());
|
|
}
|
|
|
|
void Copter::Mode::update_navigation()
|
|
{
|
|
// run autopilot to make high level decisions about control modes
|
|
run_autopilot();
|
|
}
|
|
|
|
// get_pilot_desired_angle - transform pilot's roll or pitch input into a desired lean angle
|
|
// returns desired angle in centi-degrees
|
|
void Copter::Mode::get_pilot_desired_lean_angles(float &roll_out, float &pitch_out, float angle_max, float angle_limit) const
|
|
{
|
|
// fetch roll and pitch inputs
|
|
roll_out = channel_roll->get_control_in();
|
|
pitch_out = channel_pitch->get_control_in();
|
|
|
|
// limit max lean angle
|
|
angle_limit = constrain_float(angle_limit, 1000.0f, angle_max);
|
|
|
|
// scale roll and pitch inputs to ANGLE_MAX parameter range
|
|
float scaler = angle_max/(float)ROLL_PITCH_YAW_INPUT_MAX;
|
|
roll_out *= scaler;
|
|
pitch_out *= scaler;
|
|
|
|
// do circular limit
|
|
float total_in = norm(pitch_out, roll_out);
|
|
if (total_in > angle_limit) {
|
|
float ratio = angle_limit / total_in;
|
|
roll_out *= ratio;
|
|
pitch_out *= ratio;
|
|
}
|
|
|
|
// do lateral tilt to euler roll conversion
|
|
roll_out = (18000/M_PI) * atanf(cosf(pitch_out*(M_PI/18000))*tanf(roll_out*(M_PI/18000)));
|
|
|
|
// roll_out and pitch_out are returned
|
|
}
|
|
|
|
bool Copter::Mode::_TakeOff::triggered(const float target_climb_rate) const
|
|
{
|
|
if (!copter.ap.land_complete) {
|
|
// can't take off if we're already flying
|
|
return false;
|
|
}
|
|
if (target_climb_rate <= 0.0f) {
|
|
// can't takeoff unless we want to go up...
|
|
return false;
|
|
}
|
|
#if FRAME_CONFIG == HELI_FRAME
|
|
if (!copter.motors->rotor_runup_complete()) {
|
|
// hold heli on the ground until rotor speed runup has finished
|
|
return false;
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
void Copter::Mode::zero_throttle_and_relax_ac()
|
|
{
|
|
#if FRAME_CONFIG == HELI_FRAME
|
|
// Helicopters always stabilize roll/pitch/yaw
|
|
attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(0.0f, 0.0f, 0.0f);
|
|
attitude_control->set_throttle_out(0.0f, false, copter.g.throttle_filt);
|
|
#else
|
|
motors->set_desired_spool_state(AP_Motors::DESIRED_SPIN_WHEN_ARMED);
|
|
// multicopters do not stabilize roll/pitch/yaw when disarmed
|
|
attitude_control->set_throttle_out_unstabilized(0.0f, true, copter.g.throttle_filt);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
get a height above ground estimate for landing
|
|
*/
|
|
int32_t Copter::Mode::get_alt_above_ground(void)
|
|
{
|
|
int32_t alt_above_ground;
|
|
if (copter.rangefinder_alt_ok()) {
|
|
alt_above_ground = copter.rangefinder_state.alt_cm_filt.get();
|
|
} else {
|
|
bool navigating = pos_control->is_active_xy();
|
|
if (!navigating || !copter.current_loc.get_alt_cm(Location_Class::ALT_FRAME_ABOVE_TERRAIN, alt_above_ground)) {
|
|
alt_above_ground = copter.current_loc.alt;
|
|
}
|
|
}
|
|
return alt_above_ground;
|
|
}
|
|
|
|
void Copter::Mode::land_run_vertical_control(bool pause_descent)
|
|
{
|
|
#if PRECISION_LANDING == ENABLED
|
|
const bool navigating = pos_control->is_active_xy();
|
|
bool doing_precision_landing = !ap.land_repo_active && copter.precland.target_acquired() && navigating;
|
|
#else
|
|
bool doing_precision_landing = false;
|
|
#endif
|
|
|
|
// compute desired velocity
|
|
const float precland_acceptable_error = 15.0f;
|
|
const float precland_min_descent_speed = 10.0f;
|
|
const int32_t alt_above_ground = get_alt_above_ground();
|
|
|
|
float cmb_rate = 0;
|
|
if (!pause_descent) {
|
|
float max_land_descent_velocity;
|
|
if (g.land_speed_high > 0) {
|
|
max_land_descent_velocity = -g.land_speed_high;
|
|
} else {
|
|
max_land_descent_velocity = pos_control->get_max_speed_down();
|
|
}
|
|
|
|
// Don't speed up for landing.
|
|
max_land_descent_velocity = MIN(max_land_descent_velocity, -abs(g.land_speed));
|
|
|
|
// Compute a vertical velocity demand such that the vehicle approaches g2.land_alt_low. Without the below constraint, this would cause the vehicle to hover at g2.land_alt_low.
|
|
cmb_rate = AC_AttitudeControl::sqrt_controller(MAX(g2.land_alt_low,100)-alt_above_ground, pos_control->get_pos_z_p().kP(), pos_control->get_max_accel_z(), G_Dt);
|
|
|
|
// Constrain the demanded vertical velocity so that it is between the configured maximum descent speed and the configured minimum descent speed.
|
|
cmb_rate = constrain_float(cmb_rate, max_land_descent_velocity, -abs(g.land_speed));
|
|
|
|
if (doing_precision_landing && copter.rangefinder_alt_ok() && copter.rangefinder_state.alt_cm > 35.0f && copter.rangefinder_state.alt_cm < 200.0f) {
|
|
float max_descent_speed = abs(g.land_speed)/2.0f;
|
|
float land_slowdown = MAX(0.0f, pos_control->get_horizontal_error()*(max_descent_speed/precland_acceptable_error));
|
|
cmb_rate = MIN(-precland_min_descent_speed, -max_descent_speed+land_slowdown);
|
|
}
|
|
}
|
|
|
|
// update altitude target and call position controller
|
|
pos_control->set_alt_target_from_climb_rate_ff(cmb_rate, G_Dt, true);
|
|
pos_control->update_z_controller();
|
|
}
|
|
|
|
void Copter::Mode::land_run_horizontal_control()
|
|
{
|
|
float target_roll = 0.0f;
|
|
float target_pitch = 0.0f;
|
|
float target_yaw_rate = 0;
|
|
|
|
// relax loiter target if we might be landed
|
|
if (ap.land_complete_maybe) {
|
|
loiter_nav->soften_for_landing();
|
|
}
|
|
|
|
// process pilot inputs
|
|
if (!copter.failsafe.radio) {
|
|
if ((g.throttle_behavior & THR_BEHAVE_HIGH_THROTTLE_CANCELS_LAND) != 0 && copter.rc_throttle_control_in_filter.get() > LAND_CANCEL_TRIGGER_THR){
|
|
copter.Log_Write_Event(DATA_LAND_CANCELLED_BY_PILOT);
|
|
// exit land if throttle is high
|
|
if (!set_mode(LOITER, MODE_REASON_THROTTLE_LAND_ESCAPE)) {
|
|
set_mode(ALT_HOLD, MODE_REASON_THROTTLE_LAND_ESCAPE);
|
|
}
|
|
}
|
|
|
|
if (g.land_repositioning) {
|
|
// apply SIMPLE mode transform to pilot inputs
|
|
update_simple_mode();
|
|
|
|
// convert pilot input to lean angles
|
|
get_pilot_desired_lean_angles(target_roll, target_pitch, loiter_nav->get_angle_max_cd(), attitude_control->get_althold_lean_angle_max());
|
|
|
|
// record if pilot has overriden roll or pitch
|
|
if (!is_zero(target_roll) || !is_zero(target_pitch)) {
|
|
ap.land_repo_active = true;
|
|
}
|
|
}
|
|
|
|
// get pilot's desired yaw rate
|
|
target_yaw_rate = get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
|
|
}
|
|
|
|
#if PRECISION_LANDING == ENABLED
|
|
bool doing_precision_landing = !ap.land_repo_active && copter.precland.target_acquired();
|
|
// run precision landing
|
|
if (doing_precision_landing) {
|
|
Vector2f target_pos, target_vel_rel;
|
|
if (!copter.precland.get_target_position_cm(target_pos)) {
|
|
target_pos.x = inertial_nav.get_position().x;
|
|
target_pos.y = inertial_nav.get_position().y;
|
|
}
|
|
if (!copter.precland.get_target_velocity_relative_cms(target_vel_rel)) {
|
|
target_vel_rel.x = -inertial_nav.get_velocity().x;
|
|
target_vel_rel.y = -inertial_nav.get_velocity().y;
|
|
}
|
|
pos_control->set_xy_target(target_pos.x, target_pos.y);
|
|
pos_control->override_vehicle_velocity_xy(-target_vel_rel);
|
|
}
|
|
#endif
|
|
|
|
// process roll, pitch inputs
|
|
loiter_nav->set_pilot_desired_acceleration(target_roll, target_pitch, G_Dt);
|
|
|
|
// run loiter controller
|
|
loiter_nav->update();
|
|
|
|
int32_t nav_roll = loiter_nav->get_roll();
|
|
int32_t nav_pitch = loiter_nav->get_pitch();
|
|
|
|
if (g2.wp_navalt_min > 0) {
|
|
// user has requested an altitude below which navigation
|
|
// attitude is limited. This is used to prevent commanded roll
|
|
// over on landing, which particularly affects helicopters if
|
|
// there is any position estimate drift after touchdown. We
|
|
// limit attitude to 7 degrees below this limit and linearly
|
|
// interpolate for 1m above that
|
|
const int alt_above_ground = get_alt_above_ground();
|
|
float attitude_limit_cd = linear_interpolate(700, copter.aparm.angle_max, alt_above_ground,
|
|
g2.wp_navalt_min*100U, (g2.wp_navalt_min+1)*100U);
|
|
float total_angle_cd = norm(nav_roll, nav_pitch);
|
|
if (total_angle_cd > attitude_limit_cd) {
|
|
float ratio = attitude_limit_cd / total_angle_cd;
|
|
nav_roll *= ratio;
|
|
nav_pitch *= ratio;
|
|
|
|
// tell position controller we are applying an external limit
|
|
pos_control->set_limit_accel_xy();
|
|
}
|
|
}
|
|
|
|
|
|
// call attitude controller
|
|
attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(nav_roll, nav_pitch, target_yaw_rate);
|
|
}
|
|
|
|
// pass-through functions to reduce code churn on conversion;
|
|
// these are candidates for moving into the Mode base
|
|
// class.
|
|
|
|
float Copter::Mode::get_surface_tracking_climb_rate(int16_t target_rate, float current_alt_target, float dt)
|
|
{
|
|
return copter.get_surface_tracking_climb_rate(target_rate, current_alt_target, dt);
|
|
}
|
|
|
|
float Copter::Mode::get_pilot_desired_yaw_rate(int16_t stick_angle)
|
|
{
|
|
return copter.get_pilot_desired_yaw_rate(stick_angle);
|
|
}
|
|
|
|
float Copter::Mode::get_pilot_desired_climb_rate(float throttle_control)
|
|
{
|
|
return copter.get_pilot_desired_climb_rate(throttle_control);
|
|
}
|
|
|
|
float Copter::Mode::get_pilot_desired_throttle(int16_t throttle_control, float thr_mid)
|
|
{
|
|
return copter.get_pilot_desired_throttle(throttle_control, thr_mid);
|
|
}
|
|
|
|
float Copter::Mode::get_non_takeoff_throttle()
|
|
{
|
|
return copter.get_non_takeoff_throttle();
|
|
}
|
|
|
|
void Copter::Mode::update_simple_mode(void) {
|
|
copter.update_simple_mode();
|
|
}
|
|
|
|
bool Copter::Mode::set_mode(control_mode_t mode, mode_reason_t reason)
|
|
{
|
|
return copter.set_mode(mode, reason);
|
|
}
|
|
|
|
void Copter::Mode::set_land_complete(bool b)
|
|
{
|
|
return copter.set_land_complete(b);
|
|
}
|
|
|
|
GCS_Copter &Copter::Mode::gcs()
|
|
{
|
|
return copter.gcs();
|
|
}
|
|
|
|
void Copter::Mode::Log_Write_Event(uint8_t id)
|
|
{
|
|
return copter.Log_Write_Event(id);
|
|
}
|
|
|
|
void Copter::Mode::set_throttle_takeoff()
|
|
{
|
|
return copter.set_throttle_takeoff();
|
|
}
|
|
|
|
float Copter::Mode::get_avoidance_adjusted_climbrate(float target_rate)
|
|
{
|
|
return copter.get_avoidance_adjusted_climbrate(target_rate);
|
|
}
|
|
|
|
uint16_t Copter::Mode::get_pilot_speed_dn()
|
|
{
|
|
return copter.get_pilot_speed_dn();
|
|
}
|