Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/ArduCopter/RC_Channel_Copter.cpp
Views: 1798
#include "Copter.h"12#include "RC_Channel_Copter.h"345// defining these two macros and including the RC_Channels_VarInfo header defines the parameter information common to all vehicle types6#define RC_CHANNELS_SUBCLASS RC_Channels_Copter7#define RC_CHANNEL_SUBCLASS RC_Channel_Copter89#include <RC_Channel/RC_Channels_VarInfo.h>1011int8_t RC_Channels_Copter::flight_mode_channel_number() const12{13return copter.g.flight_mode_chan.get();14}1516void RC_Channel_Copter::mode_switch_changed(modeswitch_pos_t new_pos)17{18if (new_pos < 0 || (uint8_t)new_pos > copter.num_flight_modes) {19// should not have been called20return;21}2223if (!copter.set_mode((Mode::Number)copter.flight_modes[new_pos].get(), ModeReason::RC_COMMAND)) {24return;25}2627if (!rc().find_channel_for_option(AUX_FUNC::SIMPLE_MODE) &&28!rc().find_channel_for_option(AUX_FUNC::SUPERSIMPLE_MODE)) {29// if none of the Aux Switches are set to Simple or Super Simple Mode then30// set Simple Mode using stored parameters from EEPROM31if (BIT_IS_SET(copter.g.super_simple, new_pos)) {32copter.set_simple_mode(Copter::SimpleMode::SUPERSIMPLE);33} else {34copter.set_simple_mode(BIT_IS_SET(copter.g.simple_modes, new_pos) ? Copter::SimpleMode::SIMPLE : Copter::SimpleMode::NONE);35}36}37}3839bool RC_Channels_Copter::in_rc_failsafe() const40{41return copter.failsafe.radio;42}4344bool RC_Channels_Copter::has_valid_input() const45{46if (in_rc_failsafe()) {47return false;48}49if (copter.failsafe.radio_counter != 0) {50return false;51}52return true;53}5455// returns true if throttle arming checks should be run56bool RC_Channels_Copter::arming_check_throttle() const {57if ((copter.g.throttle_behavior & THR_BEHAVE_FEEDBACK_FROM_MID_STICK) != 0) {58// center sprung throttle configured, dont run AP_Arming check59// Copter already checks this case in its own arming checks60return false;61}62return RC_Channels::arming_check_throttle();63}6465RC_Channel * RC_Channels_Copter::get_arming_channel(void) const66{67return copter.channel_yaw;68}6970// init_aux_switch_function - initialize aux functions71void RC_Channel_Copter::init_aux_function(const AUX_FUNC ch_option, const AuxSwitchPos ch_flag)72{73// init channel options74switch(ch_option) {75// the following functions do not need to be initialised:76case AUX_FUNC::ALTHOLD:77case AUX_FUNC::AUTO:78case AUX_FUNC::AUTOTUNE_MODE:79case AUX_FUNC::AUTOTUNE_TEST_GAINS:80case AUX_FUNC::BRAKE:81case AUX_FUNC::CIRCLE:82case AUX_FUNC::DRIFT:83case AUX_FUNC::FLIP:84case AUX_FUNC::FLOWHOLD:85case AUX_FUNC::FOLLOW:86case AUX_FUNC::GUIDED:87case AUX_FUNC::LAND:88case AUX_FUNC::LOITER:89#if HAL_PARACHUTE_ENABLED90case AUX_FUNC::PARACHUTE_RELEASE:91#endif92case AUX_FUNC::POSHOLD:93case AUX_FUNC::RESETTOARMEDYAW:94case AUX_FUNC::RTL:95case AUX_FUNC::SAVE_TRIM:96case AUX_FUNC::SAVE_WP:97case AUX_FUNC::SMART_RTL:98case AUX_FUNC::STABILIZE:99case AUX_FUNC::THROW:100case AUX_FUNC::USER_FUNC1:101case AUX_FUNC::USER_FUNC2:102case AUX_FUNC::USER_FUNC3:103#if AP_WINCH_ENABLED104case AUX_FUNC::WINCH_CONTROL:105#endif106case AUX_FUNC::ZIGZAG:107case AUX_FUNC::ZIGZAG_Auto:108case AUX_FUNC::ZIGZAG_SaveWP:109case AUX_FUNC::ACRO:110case AUX_FUNC::AUTO_RTL:111case AUX_FUNC::TURTLE:112case AUX_FUNC::SIMPLE_HEADING_RESET:113case AUX_FUNC::ARMDISARM_AIRMODE:114case AUX_FUNC::TURBINE_START:115case AUX_FUNC::FLIGHTMODE_PAUSE:116break;117case AUX_FUNC::ACRO_TRAINER:118case AUX_FUNC::ATTCON_ACCEL_LIM:119case AUX_FUNC::ATTCON_FEEDFWD:120case AUX_FUNC::INVERTED:121case AUX_FUNC::MOTOR_INTERLOCK:122#if HAL_PARACHUTE_ENABLED123case AUX_FUNC::PARACHUTE_3POS: // we trust the vehicle will be disarmed so even if switch is in release position the chute will not release124case AUX_FUNC::PARACHUTE_ENABLE:125#endif126case AUX_FUNC::PRECISION_LOITER:127#if AP_RANGEFINDER_ENABLED128case AUX_FUNC::RANGEFINDER:129#endif130case AUX_FUNC::SIMPLE_MODE:131case AUX_FUNC::STANDBY:132case AUX_FUNC::SUPERSIMPLE_MODE:133case AUX_FUNC::SURFACE_TRACKING:134#if AP_WINCH_ENABLED135case AUX_FUNC::WINCH_ENABLE:136#endif137case AUX_FUNC::AIRMODE:138case AUX_FUNC::FORCEFLYING:139case AUX_FUNC::CUSTOM_CONTROLLER:140case AUX_FUNC::WEATHER_VANE_ENABLE:141case AUX_FUNC::TRANSMITTER_TUNING:142run_aux_function(ch_option, ch_flag, AuxFuncTrigger::Source::INIT, ch_in);143break;144default:145RC_Channel::init_aux_function(ch_option, ch_flag);146break;147}148}149150// do_aux_function_change_mode - change mode based on an aux switch151// being moved152void RC_Channel_Copter::do_aux_function_change_mode(const Mode::Number mode,153const AuxSwitchPos ch_flag)154{155switch(ch_flag) {156case AuxSwitchPos::HIGH: {157// engage mode (if not possible we remain in current flight mode)158copter.set_mode(mode, ModeReason::AUX_FUNCTION);159break;160}161default:162// return to flight mode switch's flight mode if we are currently163// in this mode164if (copter.flightmode->mode_number() == mode) {165rc().reset_mode_switch();166}167}168}169170// do_aux_function - implement the function invoked by auxiliary switches171bool RC_Channel_Copter::do_aux_function(const AuxFuncTrigger &trigger)172{173const AUX_FUNC &ch_option = trigger.func;174const AuxSwitchPos &ch_flag = trigger.pos;175176switch(ch_option) {177case AUX_FUNC::FLIP:178// flip if switch is on, positive throttle and we're actually flying179if (ch_flag == AuxSwitchPos::HIGH) {180copter.set_mode(Mode::Number::FLIP, ModeReason::AUX_FUNCTION);181}182break;183184case AUX_FUNC::SIMPLE_MODE:185// low = simple mode off, middle or high position turns simple mode on186copter.set_simple_mode((ch_flag == AuxSwitchPos::LOW) ? Copter::SimpleMode::NONE : Copter::SimpleMode::SIMPLE);187break;188189case AUX_FUNC::SUPERSIMPLE_MODE: {190Copter::SimpleMode newmode = Copter::SimpleMode::NONE;191switch (ch_flag) {192case AuxSwitchPos::LOW:193break;194case AuxSwitchPos::MIDDLE:195newmode = Copter::SimpleMode::SIMPLE;196break;197case AuxSwitchPos::HIGH:198newmode = Copter::SimpleMode::SUPERSIMPLE;199break;200}201copter.set_simple_mode(newmode);202break;203}204205#if MODE_RTL_ENABLED206case AUX_FUNC::RTL:207do_aux_function_change_mode(Mode::Number::RTL, ch_flag);208break;209#endif210211case AUX_FUNC::SAVE_TRIM:212if ((ch_flag == AuxSwitchPos::HIGH) &&213(copter.flightmode->allows_save_trim()) &&214(copter.channel_throttle->get_control_in() == 0)) {215copter.save_trim();216}217break;218219#if MODE_AUTO_ENABLED220case AUX_FUNC::SAVE_WP:221// save waypoint when switch is brought high222if (ch_flag == RC_Channel::AuxSwitchPos::HIGH) {223224// do not allow saving new waypoints while we're in auto or disarmed225if (copter.flightmode == &copter.mode_auto || !copter.motors->armed()) {226break;227}228229// do not allow saving the first waypoint with zero throttle230if ((copter.mode_auto.mission.num_commands() == 0) && (copter.channel_throttle->get_control_in() == 0)) {231break;232}233234// create new mission command235AP_Mission::Mission_Command cmd = {};236237// if the mission is empty save a takeoff command238if (copter.mode_auto.mission.num_commands() == 0) {239// set our location ID to 16, MAV_CMD_NAV_WAYPOINT240cmd.id = MAV_CMD_NAV_TAKEOFF;241cmd.content.location.alt = MAX(copter.current_loc.alt,100);242243// use the current altitude for the target alt for takeoff.244// only altitude will matter to the AP mission script for takeoff.245if (copter.mode_auto.mission.add_cmd(cmd)) {246// log event247LOGGER_WRITE_EVENT(LogEvent::SAVEWP_ADD_WP);248}249}250251// set new waypoint to current location252cmd.content.location = copter.current_loc;253254// if throttle is above zero, create waypoint command255if (copter.channel_throttle->get_control_in() > 0) {256cmd.id = MAV_CMD_NAV_WAYPOINT;257} else {258// with zero throttle, create LAND command259cmd.id = MAV_CMD_NAV_LAND;260}261262// save command263if (copter.mode_auto.mission.add_cmd(cmd)) {264// log event265LOGGER_WRITE_EVENT(LogEvent::SAVEWP_ADD_WP);266}267}268break;269270case AUX_FUNC::AUTO:271do_aux_function_change_mode(Mode::Number::AUTO, ch_flag);272break;273#endif274275#if AP_RANGEFINDER_ENABLED276case AUX_FUNC::RANGEFINDER:277// enable or disable the rangefinder278if ((ch_flag == AuxSwitchPos::HIGH) &&279copter.rangefinder.has_orientation(ROTATION_PITCH_270)) {280copter.rangefinder_state.enabled = true;281} else {282copter.rangefinder_state.enabled = false;283}284break;285#endif // AP_RANGEFINDER_ENABLED286287#if MODE_ACRO_ENABLED288case AUX_FUNC::ACRO_TRAINER:289switch(ch_flag) {290case AuxSwitchPos::LOW:291copter.g.acro_trainer.set((uint8_t)ModeAcro::Trainer::OFF);292LOGGER_WRITE_EVENT(LogEvent::ACRO_TRAINER_OFF);293break;294case AuxSwitchPos::MIDDLE:295copter.g.acro_trainer.set((uint8_t)ModeAcro::Trainer::LEVELING);296LOGGER_WRITE_EVENT(LogEvent::ACRO_TRAINER_LEVELING);297break;298case AuxSwitchPos::HIGH:299copter.g.acro_trainer.set((uint8_t)ModeAcro::Trainer::LIMITED);300LOGGER_WRITE_EVENT(LogEvent::ACRO_TRAINER_LIMITED);301break;302}303break;304#endif305306#if AUTOTUNE_ENABLED307case AUX_FUNC::AUTOTUNE_MODE:308do_aux_function_change_mode(Mode::Number::AUTOTUNE, ch_flag);309break;310case AUX_FUNC::AUTOTUNE_TEST_GAINS:311copter.mode_autotune.autotune.do_aux_function(ch_flag);312break;313#endif314315case AUX_FUNC::LAND:316do_aux_function_change_mode(Mode::Number::LAND, ch_flag);317break;318319case AUX_FUNC::GUIDED:320do_aux_function_change_mode(Mode::Number::GUIDED, ch_flag);321break;322323case AUX_FUNC::LOITER:324do_aux_function_change_mode(Mode::Number::LOITER, ch_flag);325break;326327case AUX_FUNC::FOLLOW:328do_aux_function_change_mode(Mode::Number::FOLLOW, ch_flag);329break;330331#if HAL_PARACHUTE_ENABLED332case AUX_FUNC::PARACHUTE_ENABLE:333// Parachute enable/disable334copter.parachute.enabled(ch_flag == AuxSwitchPos::HIGH);335break;336337case AUX_FUNC::PARACHUTE_RELEASE:338if (ch_flag == AuxSwitchPos::HIGH) {339copter.parachute_manual_release();340}341break;342343case AUX_FUNC::PARACHUTE_3POS:344// Parachute disable, enable, release with 3 position switch345switch (ch_flag) {346case AuxSwitchPos::LOW:347copter.parachute.enabled(false);348break;349case AuxSwitchPos::MIDDLE:350copter.parachute.enabled(true);351break;352case AuxSwitchPos::HIGH:353copter.parachute.enabled(true);354copter.parachute_manual_release();355break;356}357break;358#endif // HAL_PARACHUTE_ENABLED359360case AUX_FUNC::ATTCON_FEEDFWD:361// enable or disable feed forward362copter.attitude_control->bf_feedforward(ch_flag == AuxSwitchPos::HIGH);363break;364365case AUX_FUNC::ATTCON_ACCEL_LIM:366// enable or disable accel limiting by restoring defaults367copter.attitude_control->accel_limiting(ch_flag == AuxSwitchPos::HIGH);368break;369370case AUX_FUNC::MOTOR_INTERLOCK:371#if FRAME_CONFIG == HELI_FRAME372// The interlock logic for ROTOR_CONTROL_MODE_PASSTHROUGH is handled373// in heli_update_rotor_speed_targets. Otherwise turn on when above low.374if (copter.motors->get_rsc_mode() != ROTOR_CONTROL_MODE_PASSTHROUGH) {375copter.ap.motor_interlock_switch = (ch_flag == AuxSwitchPos::HIGH || ch_flag == AuxSwitchPos::MIDDLE);376}377#else378copter.ap.motor_interlock_switch = (ch_flag == AuxSwitchPos::HIGH || ch_flag == AuxSwitchPos::MIDDLE);379#endif380break;381382#if FRAME_CONFIG == HELI_FRAME383case AUX_FUNC::TURBINE_START:384switch (ch_flag) {385case AuxSwitchPos::HIGH:386copter.motors->set_turb_start(true);387break;388case AuxSwitchPos::MIDDLE:389// nothing390break;391case AuxSwitchPos::LOW:392copter.motors->set_turb_start(false);393break;394}395break;396#endif397398#if MODE_BRAKE_ENABLED399case AUX_FUNC::BRAKE:400do_aux_function_change_mode(Mode::Number::BRAKE, ch_flag);401break;402#endif403404#if MODE_THROW_ENABLED405case AUX_FUNC::THROW:406do_aux_function_change_mode(Mode::Number::THROW, ch_flag);407break;408#endif409410#if AC_PRECLAND_ENABLED && MODE_LOITER_ENABLED411case AUX_FUNC::PRECISION_LOITER:412switch (ch_flag) {413case AuxSwitchPos::HIGH:414copter.mode_loiter.set_precision_loiter_enabled(true);415break;416case AuxSwitchPos::MIDDLE:417// nothing418break;419case AuxSwitchPos::LOW:420copter.mode_loiter.set_precision_loiter_enabled(false);421break;422}423break;424#endif425426#if MODE_SMARTRTL_ENABLED427case AUX_FUNC::SMART_RTL:428do_aux_function_change_mode(Mode::Number::SMART_RTL, ch_flag);429break;430#endif431432#if FRAME_CONFIG == HELI_FRAME433case AUX_FUNC::INVERTED:434switch (ch_flag) {435case AuxSwitchPos::HIGH:436if (copter.flightmode->allows_inverted()) {437copter.attitude_control->set_inverted_flight(true);438} else {439gcs().send_text(MAV_SEVERITY_WARNING, "Inverted flight not available in %s mode", copter.flightmode->name());440}441break;442case AuxSwitchPos::MIDDLE:443// nothing444break;445case AuxSwitchPos::LOW:446copter.attitude_control->set_inverted_flight(false);447break;448}449break;450#endif451452#if AP_WINCH_ENABLED453case AUX_FUNC::WINCH_ENABLE:454switch (ch_flag) {455case AuxSwitchPos::HIGH:456// high switch position stops winch using rate control457copter.g2.winch.set_desired_rate(0.0f);458break;459case AuxSwitchPos::MIDDLE:460case AuxSwitchPos::LOW:461// all other position relax winch462copter.g2.winch.relax();463break;464}465break;466467case AUX_FUNC::WINCH_CONTROL:468// do nothing, used to control the rate of the winch and is processed within AP_Winch469break;470#endif // AP_WINCH_ENABLED471472#ifdef USERHOOK_AUXSWITCH473case AUX_FUNC::USER_FUNC1:474copter.userhook_auxSwitch1(ch_flag);475break;476477case AUX_FUNC::USER_FUNC2:478copter.userhook_auxSwitch2(ch_flag);479break;480481case AUX_FUNC::USER_FUNC3:482copter.userhook_auxSwitch3(ch_flag);483break;484#endif485486#if MODE_ZIGZAG_ENABLED487case AUX_FUNC::ZIGZAG:488do_aux_function_change_mode(Mode::Number::ZIGZAG, ch_flag);489break;490491case AUX_FUNC::ZIGZAG_SaveWP:492if (copter.flightmode == &copter.mode_zigzag) {493// initialize zigzag auto494copter.mode_zigzag.init_auto();495switch (ch_flag) {496case AuxSwitchPos::LOW:497copter.mode_zigzag.save_or_move_to_destination(ModeZigZag::Destination::A);498break;499case AuxSwitchPos::MIDDLE:500copter.mode_zigzag.return_to_manual_control(false);501break;502case AuxSwitchPos::HIGH:503copter.mode_zigzag.save_or_move_to_destination(ModeZigZag::Destination::B);504break;505}506}507break;508#endif509510case AUX_FUNC::STABILIZE:511do_aux_function_change_mode(Mode::Number::STABILIZE, ch_flag);512break;513514#if MODE_POSHOLD_ENABLED515case AUX_FUNC::POSHOLD:516do_aux_function_change_mode(Mode::Number::POSHOLD, ch_flag);517break;518#endif519520case AUX_FUNC::ALTHOLD:521do_aux_function_change_mode(Mode::Number::ALT_HOLD, ch_flag);522break;523524#if MODE_ACRO_ENABLED525case AUX_FUNC::ACRO:526do_aux_function_change_mode(Mode::Number::ACRO, ch_flag);527break;528#endif529530#if MODE_FLOWHOLD_ENABLED531case AUX_FUNC::FLOWHOLD:532do_aux_function_change_mode(Mode::Number::FLOWHOLD, ch_flag);533break;534#endif535536#if MODE_CIRCLE_ENABLED537case AUX_FUNC::CIRCLE:538do_aux_function_change_mode(Mode::Number::CIRCLE, ch_flag);539break;540#endif541542#if MODE_DRIFT_ENABLED543case AUX_FUNC::DRIFT:544do_aux_function_change_mode(Mode::Number::DRIFT, ch_flag);545break;546#endif547548case AUX_FUNC::STANDBY: {549switch (ch_flag) {550case AuxSwitchPos::HIGH:551copter.standby_active = true;552LOGGER_WRITE_EVENT(LogEvent::STANDBY_ENABLE);553gcs().send_text(MAV_SEVERITY_INFO, "Stand By Enabled");554break;555default:556copter.standby_active = false;557LOGGER_WRITE_EVENT(LogEvent::STANDBY_DISABLE);558gcs().send_text(MAV_SEVERITY_INFO, "Stand By Disabled");559break;560}561break;562}563564#if AP_RANGEFINDER_ENABLED565case AUX_FUNC::SURFACE_TRACKING:566switch (ch_flag) {567case AuxSwitchPos::LOW:568copter.surface_tracking.set_surface(Copter::SurfaceTracking::Surface::GROUND);569break;570case AuxSwitchPos::MIDDLE:571copter.surface_tracking.set_surface(Copter::SurfaceTracking::Surface::NONE);572break;573case AuxSwitchPos::HIGH:574copter.surface_tracking.set_surface(Copter::SurfaceTracking::Surface::CEILING);575break;576}577break;578#endif579580case AUX_FUNC::FLIGHTMODE_PAUSE:581switch (ch_flag) {582case AuxSwitchPos::HIGH:583if (!copter.flightmode->pause()) {584GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "Flight Mode Pause failed");585}586break;587case AuxSwitchPos::MIDDLE:588break;589case AuxSwitchPos::LOW:590copter.flightmode->resume();591break;592}593break;594595#if MODE_ZIGZAG_ENABLED596case AUX_FUNC::ZIGZAG_Auto:597if (copter.flightmode == &copter.mode_zigzag) {598switch (ch_flag) {599case AuxSwitchPos::HIGH:600copter.mode_zigzag.run_auto();601break;602default:603copter.mode_zigzag.suspend_auto();604break;605}606}607break;608#endif609610case AUX_FUNC::AIRMODE:611do_aux_function_change_air_mode(ch_flag);612#if MODE_ACRO_ENABLED && FRAME_CONFIG != HELI_FRAME613copter.mode_acro.air_mode_aux_changed();614#endif615break;616617case AUX_FUNC::FORCEFLYING:618do_aux_function_change_force_flying(ch_flag);619break;620621#if MODE_AUTO_ENABLED622case AUX_FUNC::AUTO_RTL:623do_aux_function_change_mode(Mode::Number::AUTO_RTL, ch_flag);624break;625#endif626627#if MODE_TURTLE_ENABLED628case AUX_FUNC::TURTLE:629do_aux_function_change_mode(Mode::Number::TURTLE, ch_flag);630break;631#endif632633case AUX_FUNC::SIMPLE_HEADING_RESET:634if (ch_flag == AuxSwitchPos::HIGH) {635copter.init_simple_bearing();636gcs().send_text(MAV_SEVERITY_INFO, "Simple heading reset");637}638break;639640case AUX_FUNC::ARMDISARM_AIRMODE:641RC_Channel::do_aux_function_armdisarm(ch_flag);642if (copter.arming.is_armed()) {643copter.ap.armed_with_airmode_switch = true;644}645break;646647#if AC_CUSTOMCONTROL_MULTI_ENABLED648case AUX_FUNC::CUSTOM_CONTROLLER:649copter.custom_control.set_custom_controller(ch_flag == AuxSwitchPos::HIGH);650break;651#endif652653#if WEATHERVANE_ENABLED654case AUX_FUNC::WEATHER_VANE_ENABLE: {655switch (ch_flag) {656case AuxSwitchPos::HIGH:657copter.g2.weathervane.allow_weathervaning(true);658break;659case AuxSwitchPos::MIDDLE:660break;661case AuxSwitchPos::LOW:662copter.g2.weathervane.allow_weathervaning(false);663break;664}665break;666}667#endif668case AUX_FUNC::TRANSMITTER_TUNING:669// do nothing, used in tuning.cpp for transmitter based tuning670break;671672default:673return RC_Channel::do_aux_function(trigger);674}675return true;676}677678// change air-mode status679void RC_Channel_Copter::do_aux_function_change_air_mode(const AuxSwitchPos ch_flag)680{681switch (ch_flag) {682case AuxSwitchPos::HIGH:683copter.air_mode = AirMode::AIRMODE_ENABLED;684break;685case AuxSwitchPos::MIDDLE:686break;687case AuxSwitchPos::LOW:688copter.air_mode = AirMode::AIRMODE_DISABLED;689break;690}691}692693// change force flying status694void RC_Channel_Copter::do_aux_function_change_force_flying(const AuxSwitchPos ch_flag)695{696switch (ch_flag) {697case AuxSwitchPos::HIGH:698copter.force_flying = true;699break;700case AuxSwitchPos::MIDDLE:701break;702case AuxSwitchPos::LOW:703copter.force_flying = false;704break;705}706}707708// save_trim - adds roll and pitch trims from the radio to ahrs709void Copter::save_trim()710{711// save roll and pitch trim712float roll_trim = ToRad((float)channel_roll->get_control_in()*0.01f);713float pitch_trim = ToRad((float)channel_pitch->get_control_in()*0.01f);714ahrs.add_trim(roll_trim, pitch_trim);715LOGGER_WRITE_EVENT(LogEvent::SAVE_TRIM);716gcs().send_text(MAV_SEVERITY_INFO, "Trim saved");717}718719// auto_trim - slightly adjusts the ahrs.roll_trim and ahrs.pitch_trim towards the current stick positions720// meant to be called continuously while the pilot attempts to keep the copter level721void Copter::auto_trim_cancel()722{723auto_trim_counter = 0;724AP_Notify::flags.save_trim = false;725gcs().send_text(MAV_SEVERITY_INFO, "AutoTrim cancelled");726}727728void Copter::auto_trim()729{730if (auto_trim_counter > 0) {731if (copter.flightmode != &copter.mode_stabilize ||732!copter.motors->armed()) {733auto_trim_cancel();734return;735}736737// flash the leds738AP_Notify::flags.save_trim = true;739740if (!auto_trim_started) {741if (ap.land_complete) {742// haven't taken off yet743return;744}745auto_trim_started = true;746}747748if (ap.land_complete) {749// landed again.750auto_trim_cancel();751return;752}753754auto_trim_counter--;755756// calculate roll trim adjustment757float roll_trim_adjustment = ToRad((float)channel_roll->get_control_in() / 4000.0f);758759// calculate pitch trim adjustment760float pitch_trim_adjustment = ToRad((float)channel_pitch->get_control_in() / 4000.0f);761762// add trim to ahrs object763// save to eeprom on last iteration764ahrs.add_trim(roll_trim_adjustment, pitch_trim_adjustment, (auto_trim_counter == 0));765766// on last iteration restore leds and accel gains to normal767if (auto_trim_counter == 0) {768AP_Notify::flags.save_trim = false;769gcs().send_text(MAV_SEVERITY_INFO, "AutoTrim: Trims saved");770}771}772}773774775