int8_t Plane::test_failsafe(uint8_t argc, const Menu::arg *argv) { uint8_t fail_test; print_hit_enter(); for(int16_t i = 0; i < 50; i++) { hal.scheduler->delay(20); read_radio(); } // read the radio to set trims // --------------------------- trim_radio(); oldSwitchPosition = readSwitch(); cliSerial->printf_P(PSTR("Unplug battery, throttle in neutral, turn off radio.\n")); while(channel_throttle->control_in > 0) { hal.scheduler->delay(20); read_radio(); } while(1) { hal.scheduler->delay(20); read_radio(); if(channel_throttle->control_in > 0) { cliSerial->printf_P(PSTR("THROTTLE CHANGED %d \n"), (int)channel_throttle->control_in); fail_test++; } if(oldSwitchPosition != readSwitch()) { cliSerial->printf_P(PSTR("CONTROL MODE CHANGED: ")); print_flight_mode(cliSerial, readSwitch()); cliSerial->println(); fail_test++; } if(rc_failsafe_active()) { cliSerial->printf_P(PSTR("THROTTLE FAILSAFE ACTIVATED: %d, "), (int)channel_throttle->radio_in); print_flight_mode(cliSerial, readSwitch()); cliSerial->println(); fail_test++; } if(fail_test > 0) { return (0); } if(cliSerial->available() > 0) { cliSerial->printf_P(PSTR("LOS caused no change in APM.\n")); return (0); } } }
int8_t Rover::test_failsafe(uint8_t argc, const Menu::arg *argv) { uint8_t fail_test = 0; print_hit_enter(); for(int i = 0; i < 50; i++){ delay(20); read_radio(); } // read the radio to set trims // --------------------------- trim_radio(); oldSwitchPosition = readSwitch(); cliSerial->println("Unplug battery, throttle in neutral, turn off radio."); while(channel_throttle->get_control_in() > 0){ delay(20); read_radio(); } while(1){ delay(20); read_radio(); if(channel_throttle->get_control_in() > 0){ cliSerial->printf("THROTTLE CHANGED %d \n", channel_throttle->get_control_in()); fail_test++; } if (oldSwitchPosition != readSwitch()){ cliSerial->print("CONTROL MODE CHANGED: "); print_mode(cliSerial, readSwitch()); cliSerial->println(); fail_test++; } if(throttle_failsafe_active()) { cliSerial->printf("THROTTLE FAILSAFE ACTIVATED: %d, ", channel_throttle->get_radio_in()); print_mode(cliSerial, readSwitch()); cliSerial->println(); fail_test++; } if(fail_test > 0){ return (0); } if(cliSerial->available() > 0){ cliSerial->println("LOS caused no change in APM."); return (0); } } }
// rc_loops - reads user input from transmitter/receiver // called at 100hz void Copter::rc_loop() { // Read radio and 3-position switch on radio // ----------------------------------------- read_radio(); rc().read_mode_switch(); }
// esc_calibration_passthrough - pass through pilot throttle to escs void Copter::esc_calibration_passthrough() { #if FRAME_CONFIG != HELI_FRAME // clear esc flag for next time g.esc_calibrate.set_and_save(ESCCAL_NONE); // reduce update rate to motors to 50Hz motors.set_update_rate(50); // send message to GCS gcs_send_text_P(MAV_SEVERITY_CRITICAL,PSTR("ESC Calibration: passing pilot throttle to ESCs")); while(1) { // arm motors motors.armed(true); motors.enable(); // flash LEDS AP_Notify::flags.esc_calibration = true; // read pilot input read_radio(); delay(10); // pass through to motors motors.throttle_pass_through(channel_throttle->radio_in); } #endif // FRAME_CONFIG != HELI_FRAME }
void Rover::trim_radio() { for (uint8_t y = 0; y < 30; y++) { read_radio(); } trim_control_surfaces(); }
int8_t Plane::test_radio_pwm(uint8_t argc, const Menu::arg *argv) { print_hit_enter(); hal.scheduler->delay(1000); while(1) { hal.scheduler->delay(20); // Filters radio input - adjust filters in the radio.pde file // ---------------------------------------------------------- read_radio(); cliSerial->printf_P(PSTR("IN:\t1: %d\t2: %d\t3: %d\t4: %d\t5: %d\t6: %d\t7: %d\t8: %d\n"), (int)channel_roll->radio_in, (int)channel_pitch->radio_in, (int)channel_throttle->radio_in, (int)channel_rudder->radio_in, (int)g.rc_5.radio_in, (int)g.rc_6.radio_in, (int)g.rc_7.radio_in, (int)g.rc_8.radio_in); if(cliSerial->available() > 0) { return (0); } } }
// rc_loops - reads user input from transmitter/receiver // called at 100hz void Sub::rc_loop() { // Read radio // ----------------------------------------- read_radio(); failsafe_manual_control_check(); }
int8_t Rover::test_radio_pwm(uint8_t argc, const Menu::arg *argv) { print_hit_enter(); delay(1000); while(1){ delay(20); // Filters radio input - adjust filters in the radio.cpp file // ---------------------------------------------------------- read_radio(); cliSerial->printf("IN:\t1: %d\t2: %d\t3: %d\t4: %d\t5: %d\t6: %d\t7: %d\t8: %d\n", channel_steer->get_radio_in(), g.rc_2.get_radio_in(), channel_throttle->get_radio_in(), g.rc_4.get_radio_in(), g.rc_5.get_radio_in(), g.rc_6.get_radio_in(), g.rc_7.get_radio_in(), g.rc_8.get_radio_in()); if(cliSerial->available() > 0){ return (0); } } }
int8_t Rover::test_radio(uint8_t argc, const Menu::arg *argv) { print_hit_enter(); delay(1000); // read the radio to set trims // --------------------------- trim_radio(); while(1){ delay(20); read_radio(); channel_steer->calc_pwm(); channel_throttle->calc_pwm(); // write out the servo PWM values // ------------------------------ set_servos(); cliSerial->printf("IN 1: %d\t2: %d\t3: %d\t4: %d\t5: %d\t6: %d\t7: %d\t8: %d\n", channel_steer->get_control_in(), g.rc_2.get_control_in(), channel_throttle->get_control_in(), g.rc_4.get_control_in(), g.rc_5.get_control_in(), g.rc_6.get_control_in(), g.rc_7.get_control_in(), g.rc_8.get_control_in()); if(cliSerial->available() > 0){ return (0); } } }
// rc_loops - reads user input from transmitter/receiver // called at 100hz void Copter::rc_loop() { // Read radio and 3-position switch on radio // ----------------------------------------- read_radio(); read_control_switch(); }
// init_rc_out -- initialise motors and check if pilot wants to perform ESC calibration void Copter::init_rc_out() { motors.set_update_rate(g.rc_speed); motors.set_frame_orientation(g.frame_orientation); motors.set_loop_rate(scheduler.get_loop_rate_hz()); motors.Init(); // motor initialisation #if FRAME_CONFIG != HELI_FRAME motors.set_throttle_range(channel_throttle->get_radio_min(), channel_throttle->get_radio_max()); #endif for(uint8_t i = 0; i < 5; i++) { delay(20); read_radio(); } // we want the input to be scaled correctly channel_throttle->set_range_out(0,1000); // setup correct scaling for ESCs like the UAVCAN PX4ESC which // take a proportion of speed. hal.rcout->set_esc_scaling(channel_throttle->get_radio_min(), channel_throttle->get_radio_max()); // check if we should enter esc calibration mode esc_calibration_startup_check(); // enable output to motors pre_arm_rc_checks(); if (ap.pre_arm_rc_check) { enable_motor_output(); } // refresh auxiliary channel to function map RC_Channel_aux::update_aux_servo_function(); }
void Rover::trim_control_surfaces() { read_radio(); // Store control surface trim values // --------------------------------- if ((channel_steer->get_radio_in() > 1400) && (channel_steer->get_radio_in() < 1600)) { channel_steer->set_radio_trim(channel_steer->get_radio_in()); // save to eeprom channel_steer->save_eeprom(); } }
void Plane::trim_control_surfaces() { read_radio(); int16_t trim_roll_range = (channel_roll->radio_max - channel_roll->radio_min)/5; int16_t trim_pitch_range = (channel_pitch->radio_max - channel_pitch->radio_min)/5; if (channel_roll->radio_in < channel_roll->radio_min+trim_roll_range || channel_roll->radio_in > channel_roll->radio_max-trim_roll_range || channel_pitch->radio_in < channel_pitch->radio_min+trim_pitch_range || channel_pitch->radio_in > channel_pitch->radio_max-trim_pitch_range) { // don't trim for extreme values - if we attempt to trim so // there is less than 20 percent range left then assume the // sticks are not properly centered. This also prevents // problems with starting APM with the TX off return; } // Store control surface trim values // --------------------------------- if(g.mix_mode == 0) { if (channel_roll->radio_in != 0) { channel_roll->radio_trim = channel_roll->radio_in; } if (channel_pitch->radio_in != 0) { channel_pitch->radio_trim = channel_pitch->radio_in; } // the secondary aileron/elevator is trimmed only if it has a // corresponding transmitter input channel, which k_aileron // doesn't have RC_Channel_aux::set_radio_trim(RC_Channel_aux::k_aileron_with_input); RC_Channel_aux::set_radio_trim(RC_Channel_aux::k_elevator_with_input); } else{ if (elevon.ch1_temp != 0) { elevon.trim1 = elevon.ch1_temp; } if (elevon.ch2_temp != 0) { elevon.trim2 = elevon.ch2_temp; } //Recompute values here using new values for elevon1_trim and elevon2_trim //We cannot use radio_in[CH_ROLL] and radio_in[CH_PITCH] values from read_radio() because the elevon trim values have changed uint16_t center = 1500; channel_roll->radio_trim = center; channel_pitch->radio_trim = center; } if (channel_rudder->radio_in != 0) { channel_rudder->radio_trim = channel_rudder->radio_in; } // save to eeprom channel_roll->save_eeprom(); channel_pitch->save_eeprom(); channel_rudder->save_eeprom(); }
void Plane::trim_control_surfaces() { read_radio(); int16_t trim_roll_range = (channel_roll->get_radio_max() - channel_roll->get_radio_min())/5; int16_t trim_pitch_range = (channel_pitch->get_radio_max() - channel_pitch->get_radio_min())/5; if (channel_roll->get_radio_in() < channel_roll->get_radio_min()+trim_roll_range || channel_roll->get_radio_in() > channel_roll->get_radio_max()-trim_roll_range || channel_pitch->get_radio_in() < channel_pitch->get_radio_min()+trim_pitch_range || channel_pitch->get_radio_in() > channel_pitch->get_radio_max()-trim_pitch_range) { // don't trim for extreme values - if we attempt to trim so // there is less than 20 percent range left then assume the // sticks are not properly centered. This also prevents // problems with starting APM with the TX off return; } // trim main surfaces SRV_Channels::set_trim_to_servo_out_for(SRV_Channel::k_aileron); SRV_Channels::set_trim_to_servo_out_for(SRV_Channel::k_elevator); SRV_Channels::set_trim_to_servo_out_for(SRV_Channel::k_rudder); // trim elevons SRV_Channels::set_trim_to_servo_out_for(SRV_Channel::k_elevon_left); SRV_Channels::set_trim_to_servo_out_for(SRV_Channel::k_elevon_right); // trim vtail SRV_Channels::set_trim_to_servo_out_for(SRV_Channel::k_vtail_left); SRV_Channels::set_trim_to_servo_out_for(SRV_Channel::k_vtail_right); if (SRV_Channels::get_output_scaled(SRV_Channel::k_rudder) == 0) { // trim differential spoilers if no rudder input SRV_Channels::set_trim_to_servo_out_for(SRV_Channel::k_dspoilerLeft1); SRV_Channels::set_trim_to_servo_out_for(SRV_Channel::k_dspoilerLeft2); SRV_Channels::set_trim_to_servo_out_for(SRV_Channel::k_dspoilerRight1); SRV_Channels::set_trim_to_servo_out_for(SRV_Channel::k_dspoilerRight2); } if (SRV_Channels::get_output_scaled(SRV_Channel::k_flap_auto) == 0 && SRV_Channels::get_output_scaled(SRV_Channel::k_flap) == 0) { // trim flaperons if no flap input SRV_Channels::set_trim_to_servo_out_for(SRV_Channel::k_flaperon_left); SRV_Channels::set_trim_to_servo_out_for(SRV_Channel::k_flaperon_right); } // now save input trims, as these have been moved to the outputs channel_roll->set_and_save_trim(); channel_pitch->set_and_save_trim(); channel_rudder->set_and_save_trim(); }
// esc_calibration_passthrough - pass through pilot throttle to escs void Copter::esc_calibration_passthrough() { #if FRAME_CONFIG != HELI_FRAME // clear esc flag for next time g.esc_calibrate.set_and_save(ESCCAL_NONE); if (motors->get_pwm_type() >= AP_Motors::PWM_TYPE_ONESHOT) { // run at full speed for oneshot ESCs (actually done on push) motors->set_update_rate(g.rc_speed); } else { // reduce update rate to motors to 50Hz motors->set_update_rate(50); } // send message to GCS gcs().send_text(MAV_SEVERITY_INFO,"ESC calibration: Passing pilot throttle to ESCs"); // disable safety if requested BoardConfig.init_safety(); // arm motors motors->armed(true); SRV_Channels::enable_by_mask(motors->get_motor_mask()); hal.util->set_soft_armed(true); while(1) { // flash LEDs esc_calibration_notify(); // read pilot input read_radio(); // we run at high rate to make oneshot ESCs happy. Normal ESCs // will only see pulses at the RC_SPEED delay(3); // pass through to motors hal.rcout->cork(); motors->set_throttle_passthrough_for_esc_calibration(channel_throttle->get_control_in() / 1000.0f); hal.rcout->push(); } #endif // FRAME_CONFIG != HELI_FRAME }
// esc_calibration_passthrough - pass through pilot throttle to escs void Copter::esc_calibration_passthrough() { #if FRAME_CONFIG != HELI_FRAME // clear esc flag for next time g.esc_calibrate.set_and_save(ESCCAL_NONE); if (motors->get_pwm_type() >= AP_Motors::PWM_TYPE_ONESHOT) { // run at full speed for oneshot ESCs (actually done on push) motors->set_update_rate(g.rc_speed); } else { // reduce update rate to motors to 50Hz motors->set_update_rate(50); } // send message to GCS gcs_send_text(MAV_SEVERITY_INFO,"ESC calibration: Passing pilot throttle to ESCs"); // arm motors motors->armed(true); motors->enable(); uint32_t last_notify_update_ms = 0; while(1) { // flash LEDS AP_Notify::flags.esc_calibration = true; uint32_t now = AP_HAL::millis(); if (now - last_notify_update_ms > 20) { last_notify_update_ms = now; update_notify(); } // read pilot input read_radio(); // we run at high rate do make oneshot ESCs happy. Normal ESCs // will only see pulses at the RC_SPEED delay(3); // pass through to motors motors->set_throttle_passthrough_for_esc_calibration(channel_throttle->get_control_in() / 1000.0f); } #endif // FRAME_CONFIG != HELI_FRAME }
int8_t Plane::test_radio(uint8_t argc, const Menu::arg *argv) { print_hit_enter(); hal.scheduler->delay(1000); // read the radio to set trims // --------------------------- trim_radio(); while(1) { hal.scheduler->delay(20); read_radio(); channel_roll->calc_pwm(); channel_pitch->calc_pwm(); channel_throttle->calc_pwm(); channel_rudder->calc_pwm(); // write out the servo PWM values // ------------------------------ set_servos(); cliSerial->printf_P(PSTR("IN 1: %d\t2: %d\t3: %d\t4: %d\t5: %d\t6: %d\t7: %d\t8: %d\n"), (int)channel_roll->control_in, (int)channel_pitch->control_in, (int)channel_throttle->control_in, (int)channel_rudder->control_in, (int)g.rc_5.control_in, (int)g.rc_6.control_in, (int)g.rc_7.control_in, (int)g.rc_8.control_in); if(cliSerial->available() > 0) { return (0); } } }
void Copter::rc_loop() { // Read radio and 3-position switch on radio // ----------------------------------------- read_radio(); read_control_switch(); /******************************************* * 添加者:程志强 * 描述:首先向两个舵机发送指令,然后接受数据,并向日志中书写数据 * 修改日期:2016/5/5,2016/6/24 * 频率提高到400Hz ******************************************* */ /******************************************* * 添加者:程志强 * 描述:首先向两个舵机发送指令,然后接受数据,并向日志中书写数据 * 修改日期:2016/6/24 ******************************************* */ chuart.send_token(); chuart.readUart(); DataFlash.Log_Write_Act(chuart.sd[0],0); DataFlash.Log_Write_Act(chuart.sd[1],1); }
// check if we should enter esc calibration mode void Copter::esc_calibration_startup_check() { #if FRAME_CONFIG != HELI_FRAME // delay up to 2 second for first radio input uint8_t i = 0; while ((i++ < 100) && (last_radio_update_ms == 0)) { delay(20); read_radio(); } // exit immediately if pre-arm rc checks fail arming.pre_arm_rc_checks(true); if (!ap.pre_arm_rc_check) { // clear esc flag for next time if ((g.esc_calibrate != ESCCAL_NONE) && (g.esc_calibrate != ESCCAL_DISABLED)) { g.esc_calibrate.set_and_save(ESCCAL_NONE); } return; } // check ESC parameter switch (g.esc_calibrate) { case ESCCAL_NONE: // check if throttle is high if (channel_throttle->get_control_in() >= ESC_CALIBRATION_HIGH_THROTTLE) { // we will enter esc_calibrate mode on next reboot g.esc_calibrate.set_and_save(ESCCAL_PASSTHROUGH_IF_THROTTLE_HIGH); // send message to gcs gcs_send_text(MAV_SEVERITY_CRITICAL,"ESC calibration: Restart board"); // turn on esc calibration notification AP_Notify::flags.esc_calibration = true; // block until we restart while(1) { delay(5); } } break; case ESCCAL_PASSTHROUGH_IF_THROTTLE_HIGH: // check if throttle is high if (channel_throttle->get_control_in() >= ESC_CALIBRATION_HIGH_THROTTLE) { // pass through pilot throttle to escs esc_calibration_passthrough(); } break; case ESCCAL_PASSTHROUGH_ALWAYS: // pass through pilot throttle to escs esc_calibration_passthrough(); break; case ESCCAL_AUTO: // perform automatic ESC calibration esc_calibration_auto(); break; case ESCCAL_DISABLED: default: // do nothing break; } // clear esc flag for next time if (g.esc_calibrate != ESCCAL_DISABLED) { g.esc_calibrate.set_and_save(ESCCAL_NONE); } #endif // FRAME_CONFIG != HELI_FRAME }
// setup_compassmot - sets compass's motor interference parameters uint8_t Copter::mavlink_compassmot(mavlink_channel_t chan) { #if FRAME_CONFIG == HELI_FRAME // compassmot not implemented for tradheli return 1; #else int8_t comp_type; // throttle or current based compensation Vector3f compass_base[COMPASS_MAX_INSTANCES]; // compass vector when throttle is zero Vector3f motor_impact[COMPASS_MAX_INSTANCES]; // impact of motors on compass vector Vector3f motor_impact_scaled[COMPASS_MAX_INSTANCES]; // impact of motors on compass vector scaled with throttle Vector3f motor_compensation[COMPASS_MAX_INSTANCES]; // final compensation to be stored to eeprom float throttle_pct; // throttle as a percentage 0.0 ~ 1.0 float throttle_pct_max = 0.0f; // maximum throttle reached (as a percentage 0~1.0) float current_amps_max = 0.0f; // maximum current reached float interference_pct[COMPASS_MAX_INSTANCES]; // interference as a percentage of total mag field (for reporting purposes only) uint32_t last_run_time; uint32_t last_send_time; bool updated = false; // have we updated the compensation vector at least once uint8_t command_ack_start = command_ack_counter; // exit immediately if we are already in compassmot if (ap.compass_mot) { // ignore restart messages return 1; }else{ ap.compass_mot = true; } // initialise output for (uint8_t i=0; i<COMPASS_MAX_INSTANCES; i++) { interference_pct[i] = 0.0f; } // check compass is enabled if (!g.compass_enabled) { gcs[chan-MAVLINK_COMM_0].send_text(MAV_SEVERITY_CRITICAL, "Compass disabled"); ap.compass_mot = false; return 1; } // check compass health compass.read(); for (uint8_t i=0; i<compass.get_count(); i++) { if (!compass.healthy(i)) { gcs[chan-MAVLINK_COMM_0].send_text(MAV_SEVERITY_CRITICAL, "Check compass"); ap.compass_mot = false; return 1; } } // check if radio is calibrated pre_arm_rc_checks(); if (!ap.pre_arm_rc_check) { gcs[chan-MAVLINK_COMM_0].send_text(MAV_SEVERITY_CRITICAL, "RC not calibrated"); ap.compass_mot = false; return 1; } // check throttle is at zero read_radio(); if (channel_throttle->control_in != 0) { gcs[chan-MAVLINK_COMM_0].send_text(MAV_SEVERITY_CRITICAL, "Throttle not zero"); ap.compass_mot = false; return 1; } // check we are landed if (!ap.land_complete) { gcs[chan-MAVLINK_COMM_0].send_text(MAV_SEVERITY_CRITICAL, "Not landed"); ap.compass_mot = false; return 1; } // disable cpu failsafe failsafe_disable(); // initialise compass init_compass(); // default compensation type to use current if possible if (battery.has_current()) { comp_type = AP_COMPASS_MOT_COMP_CURRENT; }else{ comp_type = AP_COMPASS_MOT_COMP_THROTTLE; } // send back initial ACK mavlink_msg_command_ack_send(chan, MAV_CMD_PREFLIGHT_CALIBRATION,0); // flash leds AP_Notify::flags.esc_calibration = true; // warn user we are starting calibration gcs[chan-MAVLINK_COMM_0].send_text(MAV_SEVERITY_INFO, "Starting calibration"); // inform what type of compensation we are attempting if (comp_type == AP_COMPASS_MOT_COMP_CURRENT) { gcs[chan-MAVLINK_COMM_0].send_text(MAV_SEVERITY_INFO, "Current"); } else{ gcs[chan-MAVLINK_COMM_0].send_text(MAV_SEVERITY_INFO, "Throttle"); } // disable throttle and battery failsafe g.failsafe_throttle = FS_THR_DISABLED; g.failsafe_battery_enabled = FS_BATT_DISABLED; // disable motor compensation compass.motor_compensation_type(AP_COMPASS_MOT_COMP_DISABLED); for (uint8_t i=0; i<compass.get_count(); i++) { compass.set_motor_compensation(i, Vector3f(0,0,0)); } // get initial compass readings last_run_time = millis(); while ( millis() - last_run_time < 500 ) { compass.accumulate(); } compass.read(); // store initial x,y,z compass values // initialise interference percentage for (uint8_t i=0; i<compass.get_count(); i++) { compass_base[i] = compass.get_field(i); interference_pct[i] = 0.0f; } // enable motors and pass through throttle init_rc_out(); enable_motor_output(); motors.armed(true); // initialise run time last_run_time = millis(); last_send_time = millis(); // main run while there is no user input and the compass is healthy while (command_ack_start == command_ack_counter && compass.healthy(compass.get_primary()) && motors.armed()) { // 50hz loop if (millis() - last_run_time < 20) { // grab some compass values compass.accumulate(); hal.scheduler->delay(5); continue; } last_run_time = millis(); // read radio input read_radio(); // pass through throttle to motors motors.throttle_pass_through(channel_throttle->radio_in); // read some compass values compass.read(); // read current read_battery(); // calculate scaling for throttle throttle_pct = (float)channel_throttle->control_in / 1000.0f; throttle_pct = constrain_float(throttle_pct,0.0f,1.0f); // if throttle is near zero, update base x,y,z values if (throttle_pct <= 0.0f) { for (uint8_t i=0; i<compass.get_count(); i++) { compass_base[i] = compass_base[i] * 0.99f + compass.get_field(i) * 0.01f; } // causing printing to happen as soon as throttle is lifted } else { // calculate diff from compass base and scale with throttle for (uint8_t i=0; i<compass.get_count(); i++) { motor_impact[i] = compass.get_field(i) - compass_base[i]; } // throttle based compensation if (comp_type == AP_COMPASS_MOT_COMP_THROTTLE) { // for each compass for (uint8_t i=0; i<compass.get_count(); i++) { // scale by throttle motor_impact_scaled[i] = motor_impact[i] / throttle_pct; // adjust the motor compensation to negate the impact motor_compensation[i] = motor_compensation[i] * 0.99f - motor_impact_scaled[i] * 0.01f; } updated = true; } else { // for each compass for (uint8_t i=0; i<compass.get_count(); i++) { // current based compensation if more than 3amps being drawn motor_impact_scaled[i] = motor_impact[i] / battery.current_amps(); // adjust the motor compensation to negate the impact if drawing over 3amps if (battery.current_amps() >= 3.0f) { motor_compensation[i] = motor_compensation[i] * 0.99f - motor_impact_scaled[i] * 0.01f; updated = true; } } } // calculate interference percentage at full throttle as % of total mag field if (comp_type == AP_COMPASS_MOT_COMP_THROTTLE) { for (uint8_t i=0; i<compass.get_count(); i++) { // interference is impact@fullthrottle / mag field * 100 interference_pct[i] = motor_compensation[i].length() / (float)COMPASS_MAGFIELD_EXPECTED * 100.0f; } }else{ for (uint8_t i=0; i<compass.get_count(); i++) { // interference is impact/amp * (max current seen / max throttle seen) / mag field * 100 interference_pct[i] = motor_compensation[i].length() * (current_amps_max/throttle_pct_max) / (float)COMPASS_MAGFIELD_EXPECTED * 100.0f; } } // record maximum throttle and current throttle_pct_max = MAX(throttle_pct_max, throttle_pct); current_amps_max = MAX(current_amps_max, battery.current_amps()); } if (AP_HAL::millis() - last_send_time > 500) { last_send_time = AP_HAL::millis(); mavlink_msg_compassmot_status_send(chan, channel_throttle->control_in, battery.current_amps(), interference_pct[compass.get_primary()], motor_compensation[compass.get_primary()].x, motor_compensation[compass.get_primary()].y, motor_compensation[compass.get_primary()].z); } } // stop motors motors.output_min(); motors.armed(false); // set and save motor compensation if (updated) { compass.motor_compensation_type(comp_type); for (uint8_t i=0; i<compass.get_count(); i++) { compass.set_motor_compensation(i, motor_compensation[i]); } compass.save_motor_compensation(); // display success message gcs[chan-MAVLINK_COMM_0].send_text(MAV_SEVERITY_INFO, "Calibration successful"); } else { // compensation vector never updated, report failure gcs[chan-MAVLINK_COMM_0].send_text(MAV_SEVERITY_NOTICE, "Failed"); compass.motor_compensation_type(AP_COMPASS_MOT_COMP_DISABLED); } // display new motor offsets and save report_compass(); // turn off notify leds AP_Notify::flags.esc_calibration = false; // re-enable cpu failsafe failsafe_enable(); // re-enable failsafes g.failsafe_throttle.load(); g.failsafe_battery_enabled.load(); // flag we have completed ap.compass_mot = false; return 0; #endif // FRAME_CONFIG != HELI_FRAME }