void Plane::demo_servos(uint8_t i) { while(i > 0) { gcs_send_text(MAV_SEVERITY_INFO,"Demo servos"); demoing_servos = true; servo_write(1, 1400); hal.scheduler->delay(400); servo_write(1, 1600); hal.scheduler->delay(200); servo_write(1, 1500); demoing_servos = false; hal.scheduler->delay(400); i--; } }
/* If land_DisarmDelay is enabled (non-zero), check for a landing then auto-disarm after time expires */ void Plane::disarm_if_autoland_complete() { if (g.land_disarm_delay > 0 && auto_state.land_complete && !is_flying() && arming.arming_required() != AP_Arming::NO && arming.is_armed()) { /* we have auto disarm enabled. See if enough time has passed */ if (millis() - auto_state.last_flying_ms >= g.land_disarm_delay*1000UL) { if (disarm_motors()) { gcs_send_text(MAV_SEVERITY_INFO,"Auto disarmed"); } } } }
// parachute_release - trigger the release of the parachute, disarm the motors and notify the user void Copter::parachute_release() { // send message to gcs and dataflash gcs_send_text(MAV_SEVERITY_INFO,"Parachute: Released"); Log_Write_Event(DATA_PARACHUTE_RELEASED); // disarm motors init_disarm_motors(); // release parachute parachute.release(); // deploy landing gear landinggear.set_cmd_mode(LandingGear_Deploy); }
// init_disarm_motors - disarm motors void Sub::init_disarm_motors() { // return immediately if we are already disarmed if (!motors.armed()) { return; } #if HIL_MODE != HIL_MODE_DISABLED || CONFIG_HAL_BOARD == HAL_BOARD_SITL gcs_send_text(MAV_SEVERITY_INFO, "Disarming motors"); #endif // save compass offsets learned by the EKF if enabled if (ahrs.use_compass() && compass.get_learn_type() == Compass::LEARN_EKF) { for(uint8_t i=0; i<COMPASS_MAX_INSTANCES; i++) { Vector3f magOffsets; if (ahrs.getMagOffsets(i, magOffsets)) { compass.set_and_save_offsets(i, magOffsets); } } } #if AUTOTUNE_ENABLED == ENABLED // save auto tuned parameters autotune_save_tuning_gains(); #endif // we are not in the air // set_land_complete(true);// We will let the land detector decide this in sub // set_land_complete_maybe(true); // log disarm to the dataflash Log_Write_Event(DATA_DISARMED); // send disarm command to motors motors.armed(false); // reset the mission mission.reset(); // suspend logging if (!DataFlash.log_while_disarmed()) { DataFlash.EnableWrites(false); } // disable gps velocity based centrefugal force compensation ahrs.set_correct_centrifugal(false); hal.util->set_soft_armed(false); }
bool Plane::verify_RTL() { if (g.rtl_radius < 0) { loiter.direction = -1; } else { loiter.direction = 1; } update_loiter(abs(g.rtl_radius)); if (auto_state.wp_distance <= (uint32_t)MAX(g.waypoint_radius,0) || reached_loiter_target()) { gcs_send_text(MAV_SEVERITY_INFO,"Reached RTL location"); return true; } else { return false; } }
void Plane::failsafe_short_on_event(enum failsafe_state fstype) { // This is how to handle a short loss of control signal failsafe. failsafe.state = fstype; failsafe.ch3_timer_ms = millis(); gcs_send_text(MAV_SEVERITY_WARNING, "Failsafe - Short event on, "); switch(control_mode) { case MANUAL: case STABILIZE: case ACRO: case FLY_BY_WIRE_A: case AUTOTUNE: case FLY_BY_WIRE_B: case CRUISE: case TRAINING: failsafe.saved_mode = control_mode; failsafe.saved_mode_set = 1; if(g.short_fs_action == 2) { set_mode(FLY_BY_WIRE_A); } else { set_mode(CIRCLE); } break; case AUTO: case GUIDED: case LOITER: if(g.short_fs_action != 0) { failsafe.saved_mode = control_mode; failsafe.saved_mode_set = 1; if(g.short_fs_action == 2) { set_mode(FLY_BY_WIRE_A); } else { set_mode(CIRCLE); } } break; case CIRCLE: case RTL: default: break; } gcs_send_text_fmt("flight mode = %u", (unsigned)control_mode); }
// run this at setup on the ground // ------------------------------- void Plane::init_home() { gcs_send_text(MAV_SEVERITY_INFO, "Init HOME"); ahrs.set_home(gps.location()); home_is_set = HOME_SET_NOT_LOCKED; Log_Write_Home_And_Origin(); GCS_MAVLINK::send_home_all(gps.location()); gcs_send_text_fmt(MAV_SEVERITY_INFO, "GPS alt: %lu", (unsigned long)home.alt); // Save Home to EEPROM mission.write_home_to_storage(); // Save prev loc // ------------- next_WP_loc = prev_WP_loc = home; }
bool Rover::verify_RTL() { if (wp_distance <= g.waypoint_radius) { gcs_send_text(MAV_SEVERITY_INFO,"Reached destination"); rtl_complete = true; return true; } // have we gone past the waypoint? if (location_passed_point(current_loc, prev_WP, next_WP)) { gcs_send_text_fmt(MAV_SEVERITY_INFO, "Reached destination. Distance away %um", (unsigned)get_distance(current_loc, next_WP)); rtl_complete = true; return true; } return false; }
// executes terrain failsafe if data is missing for longer than a few seconds // missing_data should be set to true if the vehicle failed to navigate because of missing data, false if navigation is proceeding successfully void Sub::failsafe_terrain_check() { // trigger with 5 seconds of failures while in AUTO mode bool valid_mode = (control_mode == AUTO || control_mode == GUIDED); bool timeout = (failsafe.terrain_last_failure_ms - failsafe.terrain_first_failure_ms) > FS_TERRAIN_TIMEOUT_MS; bool trigger_event = valid_mode && timeout; // check for clearing of event if (trigger_event != failsafe.terrain) { if (trigger_event) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Failsafe terrain triggered"); failsafe_terrain_on_event(); } else { Log_Write_Error(ERROR_SUBSYSTEM_FAILSAFE_TERRAIN, ERROR_CODE_ERROR_RESOLVED); failsafe.terrain = false; } } }
// init_disarm_motors - disarm motors void Copter::init_disarm_motors() { // return immediately if we are already disarmed if (!motors.armed()) { return; } #if HIL_MODE != HIL_MODE_DISABLED || CONFIG_HAL_BOARD == HAL_BOARD_SITL gcs_send_text(MAV_SEVERITY_INFO, "DISARMING MOTORS"); #endif // save compass offsets learned by the EKF Vector3f magOffsets; if (ahrs.use_compass() && ahrs.getMagOffsets(magOffsets)) { compass.set_and_save_offsets(compass.get_primary(), magOffsets); } #if AUTOTUNE_ENABLED == ENABLED // save auto tuned parameters autotune_save_tuning_gains(); #endif // we are not in the air set_land_complete(true); set_land_complete_maybe(true); // log disarm to the dataflash Log_Write_Event(DATA_DISARMED); // send disarm command to motors motors.armed(false); // reset the mission mission.reset(); // suspend logging if (!(g.log_bitmask & MASK_LOG_WHEN_DISARMED)) { DataFlash.EnableWrites(false); } // disable gps velocity based centrefugal force compensation ahrs.set_correct_centrifugal(false); hal.util->set_soft_armed(false); }
// crash_check - disarms motors if a crash has been detected // crashes are detected by the vehicle being more than 20 degrees beyond it's angle limits continuously for more than 1 second // called at MAIN_LOOP_RATE void Copter::crash_check() { static uint16_t crash_counter; // number of iterations vehicle may have been crashed // return immediately if disarmed, or crash checking disabled if (!motors.armed() || ap.land_complete || g.fs_crash_check == 0) { crash_counter = 0; return; } // return immediately if we are not in an angle stabilize flight mode or we are flipping if (control_mode == ACRO || control_mode == FLIP) { crash_counter = 0; return; } // vehicle not crashed if 1hz filtered acceleration is more than 3m/s (1G on Z-axis has been subtracted) if (land_accel_ef_filter.get().length() >= CRASH_CHECK_ACCEL_MAX) { crash_counter = 0; return; } // check for angle error over 30 degrees const Vector3f angle_error = attitude_control.get_att_error_rot_vec_cd(); if (pythagorous2(angle_error.x, angle_error.y) <= CRASH_CHECK_ANGLE_DEVIATION_CD) { crash_counter = 0; return; } // we may be crashing crash_counter++; // check if crashing for 2 seconds if (crash_counter >= (CRASH_CHECK_TRIGGER_SEC * MAIN_LOOP_RATE)) { // log an error in the dataflash Log_Write_Error(ERROR_SUBSYSTEM_CRASH_CHECK, ERROR_CODE_CRASH_CHECK_CRASH); // send message to gcs gcs_send_text(MAV_SEVERITY_EMERGENCY,"Crash: Disarming"); // disarm motors init_disarm_motors(); hal.uartA->printf("CRASH!"); } }
// Battery failsafe check // Check the battery voltage and remaining capacity void Sub::failsafe_battery_check(void) { // Do nothing if the failsafe is disabled, or if we are disarmed if (g.failsafe_battery_enabled == FS_BATT_DISABLED || !motors.armed()) { failsafe.battery = false; AP_Notify::flags.failsafe_battery = false; return; // Failsafe disabled, nothing to do } if (!battery.exhausted(g.fs_batt_voltage, g.fs_batt_mah)) { failsafe.battery = false; AP_Notify::flags.failsafe_battery = false; return; // Battery is doing well } // Always warn when failsafe condition is met if (AP_HAL::millis() > failsafe.last_battery_warn_ms + 20000) { failsafe.last_battery_warn_ms = AP_HAL::millis(); gcs_send_text(MAV_SEVERITY_WARNING, "Low battery"); } // Don't do anything if failsafe has already been set if (failsafe.battery) { return; } failsafe.battery = true; AP_Notify::flags.failsafe_battery = true; // Log failsafe Log_Write_Error(ERROR_SUBSYSTEM_FAILSAFE_BATT, ERROR_CODE_FAILSAFE_OCCURRED); switch(g.failsafe_battery_enabled) { case FS_BATT_SURFACE: set_mode(SURFACE, MODE_REASON_BATTERY_FAILSAFE); break; case FS_BATT_DISARM: init_disarm_motors(); break; default: break; } }
// 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 }
// althold_init - initialise althold controller bool Sub::althold_init(bool ignore_checks) { if (!ap.depth_sensor_present) { // can't hold depth without a depth sensor, exit immediately. gcs_send_text(MAV_SEVERITY_WARNING, "Depth hold requires external pressure sensor."); return false; } // initialize vertical speeds and leash lengths // sets the maximum speed up and down returned by position controller pos_control.set_speed_z(-g.pilot_velocity_z_max, g.pilot_velocity_z_max); pos_control.set_accel_z(g.pilot_accel_z); // initialise position and desired velocity pos_control.set_alt_target(inertial_nav.get_altitude()); pos_control.set_desired_velocity_z(inertial_nav.get_velocity_z()); last_pilot_heading = ahrs.yaw_sensor; return true; }
bool Sub::surface_init() { #if CONFIG_HAL_BOARD != HAL_BOARD_SITL if (!ap.depth_sensor_present || failsafe.sensor_health) { // can't hold depth without a depth sensor, exit immediately. gcs_send_text(MAV_SEVERITY_WARNING, "BAD DEPTH"); return false; } #endif // initialize vertical speeds and leash lengths pos_control.set_speed_z(wp_nav.get_speed_down(), wp_nav.get_speed_up()); pos_control.set_accel_z(wp_nav.get_accel_z()); // initialise position and desired velocity pos_control.set_alt_target(inertial_nav.get_altitude()); pos_control.set_desired_velocity_z(inertial_nav.get_velocity_z()); return true; }
void Rover::nav_set_yaw_speed() { // if we haven't received a MAV_CMD_NAV_SET_YAW_SPEED message within the last 3 seconds bring the rover to a halt if ((millis() - guided_yaw_speed.msg_time_ms) > 3000) { gcs_send_text(MAV_SEVERITY_WARNING, "NAV_SET_YAW_SPEED not recvd last 3secs, stopping"); channel_throttle->set_servo_out(g.throttle_min.get()); channel_steer->set_servo_out(0); lateral_acceleration = 0; return; } channel_steer->set_servo_out(steerController.get_steering_out_angle_error(guided_yaw_speed.turn_angle)); // speed param in the message gives speed as a proportion of cruise speed. // 0.5 would set speed to the cruise speed // 1 is double the cruise speed. float target_speed = g.speed_cruise * guided_yaw_speed.target_speed * 2; calc_throttle(target_speed); return; }
void Rover::nav_set_yaw_speed() { // if we haven't received a MAV_CMD_NAV_SET_YAW_SPEED message within the last 3 seconds bring the rover to a halt if ((millis() - guided_control.msg_time_ms) > 3000) { gcs_send_text(MAV_SEVERITY_WARNING, "NAV_SET_YAW_SPEED not recvd last 3secs, stopping"); SRV_Channels::set_output_scaled(SRV_Channel::k_throttle, g.throttle_min.get()); SRV_Channels::set_output_scaled(SRV_Channel::k_steering, 0); lateral_acceleration = 0.0f; return; } const int32_t steering = steerController.get_steering_out_angle_error(guided_control.turn_angle); SRV_Channels::set_output_scaled(SRV_Channel::k_steering, steering); // speed param in the message gives speed as a proportion of cruise speed. // 0.5 would set speed to the cruise speed // 1 is double the cruise speed. const float target_speed = g.speed_cruise * guided_control.target_speed * 2.0f; calc_throttle(target_speed); Log_Write_GuidedTarget(guided_mode, Vector3f(steering, 0.0f, 0.0f), Vector3f(target_speed, 0.0f, 0.0f)); }
// Check if we are leaking and perform appropiate action void Sub::failsafe_leak_check() { bool status = leak_detector.get_status(); // Do nothing if we are dry, or if leak failsafe action is disabled if (status == false || g.failsafe_leak == FS_LEAK_DISABLED) { if (failsafe.leak) { Log_Write_Error(ERROR_SUBSYSTEM_FAILSAFE_LEAK, ERROR_CODE_FAILSAFE_RESOLVED); } failsafe.leak = false; return; } AP_Notify::flags.leak_detected = status; uint32_t tnow = AP_HAL::millis(); // We have a leak // Always send a warning every 20 seconds if (tnow > failsafe.last_leak_warn_ms + 20000) { failsafe.last_leak_warn_ms = tnow; gcs_send_text(MAV_SEVERITY_CRITICAL, "Leak Detected"); } // Do nothing if we have already triggered the failsafe action, or if the motors are disarmed if (failsafe.leak) { return; } failsafe.leak = true; Log_Write_Error(ERROR_SUBSYSTEM_FAILSAFE_LEAK, ERROR_CODE_FAILSAFE_OCCURRED); // Handle failsafe action if (failsafe.leak && g.failsafe_leak == FS_LEAK_SURFACE && motors.armed()) { set_mode(SURFACE, MODE_REASON_LEAK_FAILSAFE); } }
/* * set_next_WP - sets the target location the vehicle should fly to */ void Rover::set_next_WP(const struct Location& loc) { // copy the current WP into the OldWP slot // --------------------------------------- prev_WP = next_WP; // Load the next_WP slot // --------------------- next_WP = loc; // are we already past the waypoint? This happens when we jump // waypoints, and it can cause us to skip a waypoint. If we are // past the waypoint when we start on a leg, then use the current // location as the previous waypoint, to prevent immediately // considering the waypoint complete if (location_passed_point(current_loc, prev_WP, next_WP)) { gcs_send_text(MAV_SEVERITY_NOTICE, "Resetting prev_WP"); prev_WP = current_loc; } // this is handy for the groundstation wp_totalDistance = get_distance(current_loc, next_WP); wp_distance = wp_totalDistance; }
/* see if we have reached altitude or descent speed */ bool Plane::verify_altitude_wait(const AP_Mission::Mission_Command &cmd) { if (current_loc.alt > cmd.content.altitude_wait.altitude*100.0f) { gcs_send_text(MAV_SEVERITY_INFO,"Reached altitude"); return true; } if (auto_state.sink_rate > cmd.content.altitude_wait.descent_rate) { gcs_send_text_fmt(MAV_SEVERITY_INFO, "Reached descent rate %.1f m/s", (double)auto_state.sink_rate); return true; } // if requested, wiggle servos if (cmd.content.altitude_wait.wiggle_time != 0) { static uint32_t last_wiggle_ms; if (auto_state.idle_wiggle_stage == 0 && AP_HAL::millis() - last_wiggle_ms > cmd.content.altitude_wait.wiggle_time*1000) { auto_state.idle_wiggle_stage = 1; last_wiggle_ms = AP_HAL::millis(); } // idle_wiggle_stage is updated in set_servos_idle() } return false; }
// crash_check - disarms motors if a crash or block has been detected // crashes are detected by the vehicle being static (no speed) for more than CRASH_CHECK_TRIGGER_SEC and motor are running // called at 10Hz void Rover::crash_check() { static uint16_t crash_counter; // number of iterations vehicle may have been crashed // return immediately if disarmed, or crash checking disabled or in HOLD mode if (!arming.is_armed() || g.fs_crash_check == FS_CRASH_DISABLE || (control_mode != GUIDED && control_mode != AUTO)) { crash_counter = 0; return; } // TODO : Check if min vel can be calculated // min_vel = ( CRASH_CHECK_THROTTLE_MIN * g.speed_cruise) / g.throttle_cruise; if ((ahrs.groundspeed() >= CRASH_CHECK_VEL_MIN) || // Check velocity (fabsf(ahrs.get_gyro().z) >= CRASH_CHECK_VEL_MIN) || // Check turn speed ((100 * fabsf(SRV_Channels::get_output_norm(SRV_Channel::k_throttle))) < CRASH_CHECK_THROTTLE_MIN)) { crash_counter = 0; return; } // we may be crashing crash_counter++; // check if crashing for 2 seconds if (crash_counter >= (CRASH_CHECK_TRIGGER_SEC * 10)) { // log an error in the dataflash Log_Write_Error(ERROR_SUBSYSTEM_CRASH_CHECK, ERROR_CODE_CRASH_CHECK_CRASH); // send message to gcs gcs_send_text(MAV_SEVERITY_EMERGENCY, "Crash: Going to HOLD"); // change mode to hold and disarm set_mode(HOLD); if (g.fs_crash_check == FS_CRASH_HOLD_AND_DISARM) { disarm_motors(); } } }
// arm_checks - perform final checks before arming // always called just before arming. Return true if ok to arm // has side-effect that logging is started bool Copter::arm_checks(bool display_failure, bool arming_from_gcs) { #if LOGGING_ENABLED == ENABLED // start dataflash start_logging(); #endif // check accels and gyro are healthy if ((g.arming_check == ARMING_CHECK_ALL) || (g.arming_check & ARMING_CHECK_INS)) { //check if accelerometers have calibrated and require reboot if (ins.accel_cal_requires_reboot()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL, "PreArm: Accelerometers calibrated requires reboot"); } return false; } if (!ins.get_accel_health_all()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Accelerometers not healthy"); } return false; } if (!ins.get_gyro_health_all()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Gyros not healthy"); } return false; } // get ekf attitude (if bad, it's usually the gyro biases) if (!pre_arm_ekf_attitude_check()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: gyros still settling"); } return false; } } // always check if inertial nav has started and is ready if (!ahrs.healthy()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Waiting for Nav Checks"); } return false; } if (compass.is_calibrating()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Compass calibration running"); } return false; } //check if compass has calibrated and requires reboot if (compass.compass_cal_requires_reboot()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL, "PreArm: Compass calibrated requires reboot"); } return false; } // always check if the current mode allows arming if (!mode_allows_arming(control_mode, arming_from_gcs)) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Mode not armable"); } return false; } // always check gps if (!pre_arm_gps_checks(display_failure)) { return false; } // if we are using motor interlock switch and it's enabled, fail to arm // skip check in Throw mode which takes control of the motor interlock if (ap.using_interlock && motors.get_interlock()) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Motor Interlock Enabled"); return false; } // if we are not using Emergency Stop switch option, force Estop false to ensure motors // can run normally if (!check_if_auxsw_mode_used(AUXSW_MOTOR_ESTOP)){ set_motor_emergency_stop(false); // if we are using motor Estop switch, it must not be in Estop position } else if (check_if_auxsw_mode_used(AUXSW_MOTOR_ESTOP) && ap.motor_emergency_stop){ gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Motor Emergency Stopped"); return false; } // succeed if arming checks are disabled if (g.arming_check == ARMING_CHECK_NONE) { return true; } // baro checks if ((g.arming_check == ARMING_CHECK_ALL) || (g.arming_check & ARMING_CHECK_BARO)) { // baro health check if (!barometer.all_healthy()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Barometer not healthy"); } return false; } // Check baro & inav alt are within 1m if EKF is operating in an absolute position mode. // Do not check if intending to operate in a ground relative height mode as EKF will output a ground relative height // that may differ from the baro height due to baro drift. nav_filter_status filt_status = inertial_nav.get_filter_status(); bool using_baro_ref = (!filt_status.flags.pred_horiz_pos_rel && filt_status.flags.pred_horiz_pos_abs); if (using_baro_ref && (fabsf(inertial_nav.get_altitude() - baro_alt) > PREARM_MAX_ALT_DISPARITY_CM)) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Altitude disparity"); } return false; } } #if AC_FENCE == ENABLED // check vehicle is within fence if (!fence.pre_arm_check()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: check fence"); } return false; } #endif // check lean angle if ((g.arming_check == ARMING_CHECK_ALL) || (g.arming_check & ARMING_CHECK_INS)) { if (degrees(acosf(ahrs.cos_roll()*ahrs.cos_pitch()))*100.0f > aparm.angle_max) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Leaning"); } return false; } } // check battery voltage if ((g.arming_check == ARMING_CHECK_ALL) || (g.arming_check & ARMING_CHECK_VOLTAGE)) { if (failsafe.battery || (!ap.usb_connected && battery.exhausted(g.fs_batt_voltage, g.fs_batt_mah))) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Check Battery"); } return false; } } // check for missing terrain data if ((g.arming_check == ARMING_CHECK_ALL) || (g.arming_check & ARMING_CHECK_PARAMETERS)) { if (!pre_arm_terrain_check(display_failure)) { return false; } } // check adsb if ((g.arming_check == ARMING_CHECK_ALL) || (g.arming_check & ARMING_CHECK_PARAMETERS)) { if (failsafe.adsb) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: ADSB threat detected"); } return false; } } // check throttle if ((g.arming_check == ARMING_CHECK_ALL) || (g.arming_check & ARMING_CHECK_RC)) { // check throttle is not too low - must be above failsafe throttle if (g.failsafe_throttle != FS_THR_DISABLED && channel_throttle->get_radio_in() < g.failsafe_throttle_value) { if (display_failure) { #if FRAME_CONFIG == HELI_FRAME gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Collective below Failsafe"); #else gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Throttle below Failsafe"); #endif } return false; } // check throttle is not too high - skips checks if arming from GCS in Guided if (!(arming_from_gcs && (control_mode == GUIDED || control_mode == GUIDED_NOGPS))) { // above top of deadband is too always high if (get_pilot_desired_climb_rate(channel_throttle->get_control_in()) > 0.0f) { if (display_failure) { #if FRAME_CONFIG == HELI_FRAME gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Collective too high"); #else gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Throttle too high"); #endif } return false; } // in manual modes throttle must be at zero if ((mode_has_manual_throttle(control_mode) || control_mode == DRIFT) && channel_throttle->get_control_in() > 0) { if (display_failure) { #if FRAME_CONFIG == HELI_FRAME gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Collective too high"); #else gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Throttle too high"); #endif } return false; } } } // check if safety switch has been pushed if (hal.util->safety_switch_state() == AP_HAL::Util::SAFETY_DISARMED) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: Safety Switch"); } return false; } // if we've gotten this far all is ok return true; }
// performs pre_arm gps related checks and returns true if passed bool Copter::pre_arm_gps_checks(bool display_failure) { // always check if inertial nav has started and is ready if (!ahrs.healthy()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Waiting for Nav Checks"); } return false; } // check if flight mode requires GPS bool gps_required = mode_requires_GPS(control_mode); #if AC_FENCE == ENABLED // if circular fence is enabled we need GPS if ((fence.get_enabled_fences() & AC_FENCE_TYPE_CIRCLE) != 0) { gps_required = true; } #endif // return true if GPS is not required if (!gps_required) { AP_Notify::flags.pre_arm_gps_check = true; return true; } // ensure GPS is ok if (!position_ok()) { if (display_failure) { const char *reason = ahrs.prearm_failure_reason(); if (reason) { GCS_MAVLINK::send_statustext_all(MAV_SEVERITY_CRITICAL, "PreArm: %s", reason); } else { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Need 3D Fix"); } } AP_Notify::flags.pre_arm_gps_check = false; return false; } // check EKF compass variance is below failsafe threshold float vel_variance, pos_variance, hgt_variance, tas_variance; Vector3f mag_variance; Vector2f offset; ahrs.get_variances(vel_variance, pos_variance, hgt_variance, mag_variance, tas_variance, offset); if (mag_variance.length() >= g.fs_ekf_thresh) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: EKF compass variance"); } return false; } // check home and EKF origin are not too far if (far_from_EKF_origin(ahrs.get_home())) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: EKF-home variance"); } AP_Notify::flags.pre_arm_gps_check = false; return false; } // return true immediately if gps check is disabled if (!(g.arming_check == ARMING_CHECK_ALL || g.arming_check & ARMING_CHECK_GPS)) { AP_Notify::flags.pre_arm_gps_check = true; return true; } // warn about hdop separately - to prevent user confusion with no gps lock if (gps.get_hdop() > g.gps_hdop_good) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: High GPS HDOP"); } AP_Notify::flags.pre_arm_gps_check = false; return false; } // if we got here all must be ok AP_Notify::flags.pre_arm_gps_check = true; return true; }
// perform pre-arm checks and set ap.pre_arm_check flag // return true if the checks pass successfully bool Copter::pre_arm_checks(bool display_failure) { // exit immediately if already armed if (motors.armed()) { return true; } // check if motor interlock and Emergency Stop aux switches are used // at the same time. This cannot be allowed. if (check_if_auxsw_mode_used(AUXSW_MOTOR_INTERLOCK) && check_if_auxsw_mode_used(AUXSW_MOTOR_ESTOP)){ if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Interlock/E-Stop Conflict"); } return false; } // check if motor interlock aux switch is in use // if it is, switch needs to be in disabled position to arm // otherwise exit immediately. This check to be repeated, // as state can change at any time. if (ap.using_interlock && ap.motor_interlock_switch) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Motor Interlock Enabled"); } return false; } // exit immediately if we've already successfully performed the pre-arm check if (ap.pre_arm_check) { // run gps checks because results may change and affect LED colour // no need to display failures because arm_checks will do that if the pilot tries to arm pre_arm_gps_checks(false); return true; } // succeed if pre arm checks are disabled if (g.arming_check == ARMING_CHECK_NONE) { set_pre_arm_check(true); set_pre_arm_rc_check(true); return true; } // pre-arm rc checks a prerequisite pre_arm_rc_checks(); if (!ap.pre_arm_rc_check) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: RC not calibrated"); } return false; } // check Baro if ((g.arming_check == ARMING_CHECK_ALL) || (g.arming_check & ARMING_CHECK_BARO)) { // barometer health check if (!barometer.all_healthy()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Barometer not healthy"); } return false; } // Check baro & inav alt are within 1m if EKF is operating in an absolute position mode. // Do not check if intending to operate in a ground relative height mode as EKF will output a ground relative height // that may differ from the baro height due to baro drift. nav_filter_status filt_status = inertial_nav.get_filter_status(); bool using_baro_ref = (!filt_status.flags.pred_horiz_pos_rel && filt_status.flags.pred_horiz_pos_abs); if (using_baro_ref) { if (fabsf(inertial_nav.get_altitude() - baro_alt) > PREARM_MAX_ALT_DISPARITY_CM) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Altitude disparity"); } return false; } } } // check Compass if ((g.arming_check == ARMING_CHECK_ALL) || (g.arming_check & ARMING_CHECK_COMPASS)) { //check if compass has calibrated and requires reboot if (compass.compass_cal_requires_reboot()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL, "PreArm: Compass calibrated requires reboot"); } return false; } // check the primary compass is healthy if (!compass.healthy()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Compass not healthy"); } return false; } // check compass learning is on or offsets have been set if (!compass.configured()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Compass not calibrated"); } return false; } // check for unreasonable compass offsets Vector3f offsets = compass.get_offsets(); if (offsets.length() > COMPASS_OFFSETS_MAX) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Compass offsets too high"); } return false; } // check for unreasonable mag field length float mag_field = compass.get_field().length(); if (mag_field > COMPASS_MAGFIELD_EXPECTED*1.65f || mag_field < COMPASS_MAGFIELD_EXPECTED*0.35f) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Check mag field"); } return false; } // check all compasses point in roughly same direction if (!compass.consistent()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: inconsistent compasses"); } return false; } } // check GPS if (!pre_arm_gps_checks(display_failure)) { return false; } #if AC_FENCE == ENABLED // check fence is initialised if (!fence.pre_arm_check()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: check fence"); } return false; } #endif // check INS if ((g.arming_check == ARMING_CHECK_ALL) || (g.arming_check & ARMING_CHECK_INS)) { // check accelerometers have been calibrated if (!ins.accel_calibrated_ok_all()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Accels not calibrated"); } return false; } // check accels are healthy if (!ins.get_accel_health_all()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Accelerometers not healthy"); } return false; } //check if accelerometers have calibrated and require reboot if (ins.accel_cal_requires_reboot()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL, "PreArm: Accelerometers calibrated requires reboot"); } return false; } // check all accelerometers point in roughly same direction if (ins.get_accel_count() > 1) { const Vector3f &prime_accel_vec = ins.get_accel(); for(uint8_t i=0; i<ins.get_accel_count(); i++) { // get next accel vector const Vector3f &accel_vec = ins.get_accel(i); Vector3f vec_diff = accel_vec - prime_accel_vec; float threshold = PREARM_MAX_ACCEL_VECTOR_DIFF; if (i >= 2) { /* * for boards with 3 IMUs we only use the first two * in the EKF. Allow for larger accel discrepancy * for IMU3 as it may be running at a different temperature */ threshold *= 2; } // EKF is less sensitive to Z-axis error vec_diff.z *= 0.5f; if (vec_diff.length() > threshold) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: inconsistent Accelerometers"); } return false; } } } // check gyros are healthy if (!ins.get_gyro_health_all()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Gyros not healthy"); } return false; } // check all gyros are consistent if (ins.get_gyro_count() > 1) { for(uint8_t i=0; i<ins.get_gyro_count(); i++) { // get rotation rate difference between gyro #i and primary gyro Vector3f vec_diff = ins.get_gyro(i) - ins.get_gyro(); if (vec_diff.length() > PREARM_MAX_GYRO_VECTOR_DIFF) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: inconsistent Gyros"); } return false; } } } // get ekf attitude (if bad, it's usually the gyro biases) if (!pre_arm_ekf_attitude_check()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: gyros still settling"); } return false; } } #if CONFIG_HAL_BOARD != HAL_BOARD_VRBRAIN #ifndef CONFIG_ARCH_BOARD_PX4FMU_V1 // check board voltage if ((g.arming_check == ARMING_CHECK_ALL) || (g.arming_check & ARMING_CHECK_VOLTAGE)) { if (hal.analogin->board_voltage() < BOARD_VOLTAGE_MIN || hal.analogin->board_voltage() > BOARD_VOLTAGE_MAX) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Check Board Voltage"); } return false; } } #endif #endif // check battery voltage if ((g.arming_check == ARMING_CHECK_ALL) || (g.arming_check & ARMING_CHECK_VOLTAGE)) { if (failsafe.battery || (!ap.usb_connected && battery.exhausted(g.fs_batt_voltage, g.fs_batt_mah))) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Check Battery"); } return false; } } // check various parameter values if ((g.arming_check == ARMING_CHECK_ALL) || (g.arming_check & ARMING_CHECK_PARAMETERS)) { // ensure ch7 and ch8 have different functions if (check_duplicate_auxsw()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Duplicate Aux Switch Options"); } return false; } // failsafe parameter checks if (g.failsafe_throttle) { // check throttle min is above throttle failsafe trigger and that the trigger is above ppm encoder's loss-of-signal value of 900 if (channel_throttle->get_radio_min() <= g.failsafe_throttle_value+10 || g.failsafe_throttle_value < 910) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Check FS_THR_VALUE"); } return false; } } // lean angle parameter check if (aparm.angle_max < 1000 || aparm.angle_max > 8000) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Check ANGLE_MAX"); } return false; } // acro balance parameter check if ((g.acro_balance_roll > attitude_control.get_angle_roll_p().kP()) || (g.acro_balance_pitch > attitude_control.get_angle_pitch_p().kP())) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: ACRO_BAL_ROLL/PITCH"); } return false; } #if RANGEFINDER_ENABLED == ENABLED && OPTFLOW == ENABLED // check range finder if optflow enabled if (optflow.enabled() && !rangefinder.pre_arm_check()) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: check range finder"); } return false; } #endif #if FRAME_CONFIG == HELI_FRAME // check helicopter parameters if (!motors.parameter_check(display_failure)) { return false; } #endif // HELI_FRAME // check for missing terrain data if (!pre_arm_terrain_check(display_failure)) { return false; } // check adsb avoidance failsafe if (failsafe.adsb) { if (display_failure) { gcs_send_text(MAV_SEVERITY_CRITICAL,"Arm: ADSB threat detected"); } return false; } } // check throttle is above failsafe throttle // this is near the bottom to allow other failures to be displayed before checking pilot throttle if ((g.arming_check == ARMING_CHECK_ALL) || (g.arming_check & ARMING_CHECK_RC)) { if (g.failsafe_throttle != FS_THR_DISABLED && channel_throttle->get_radio_in() < g.failsafe_throttle_value) { if (display_failure) { #if FRAME_CONFIG == HELI_FRAME gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Collective below Failsafe"); #else gcs_send_text(MAV_SEVERITY_CRITICAL,"PreArm: Throttle below Failsafe"); #endif } return false; } } return true; }
void Plane::read_control_switch() { static bool switch_debouncer; uint8_t switchPosition = readSwitch(); // If switchPosition = 255 this indicates that the mode control channel input was out of range // If we get this value we do not want to change modes. if(switchPosition == 255) return; if (failsafe.ch3_failsafe || failsafe.ch3_counter > 0) { // when we are in ch3_failsafe mode then RC input is not // working, and we need to ignore the mode switch channel return; } if (millis() - failsafe.last_valid_rc_ms > 100) { // only use signals that are less than 0.1s old. return; } // we look for changes in the switch position. If the // RST_SWITCH_CH parameter is set, then it is a switch that can be // used to force re-reading of the control switch. This is useful // when returning to the previous mode after a failsafe or fence // breach. This channel is best used on a momentary switch (such // as a spring loaded trainer switch). if (oldSwitchPosition != switchPosition || (g.reset_switch_chan != 0 && hal.rcin->read(g.reset_switch_chan-1) > RESET_SWITCH_CHAN_PWM)) { if (switch_debouncer == false) { // this ensures that mode switches only happen if the // switch changes for 2 reads. This prevents momentary // spikes in the mode control channel from causing a mode // switch switch_debouncer = true; return; } set_mode((enum FlightMode)(flight_modes[switchPosition].get())); oldSwitchPosition = switchPosition; } if (g.reset_mission_chan != 0 && hal.rcin->read(g.reset_mission_chan-1) > RESET_SWITCH_CHAN_PWM) { mission.start(); prev_WP_loc = current_loc; } switch_debouncer = false; if (g.inverted_flight_ch != 0) { // if the user has configured an inverted flight channel, then // fly upside down when that channel goes above INVERTED_FLIGHT_PWM inverted_flight = (control_mode != MANUAL && hal.rcin->read(g.inverted_flight_ch-1) > INVERTED_FLIGHT_PWM); } #if PARACHUTE == ENABLED if (g.parachute_channel > 0) { if (hal.rcin->read(g.parachute_channel-1) >= 1700) { parachute_manual_release(); } } #endif #if CONFIG_HAL_BOARD == HAL_BOARD_PX4 if (g.override_channel > 0) { // if the user has configured an override channel then check it bool override_requested = (hal.rcin->read(g.override_channel-1) >= PX4IO_OVERRIDE_PWM); if (override_requested && !px4io_override_enabled) { if (hal.util->get_soft_armed() || (last_mixer_crc != -1)) { px4io_override_enabled = true; // disable output channels to force PX4IO override gcs_send_text(MAV_SEVERITY_WARNING, "PX4IO override enabled"); } else { // we'll let the one second loop reconfigure the mixer. The // PX4IO code sometimes rejects a mixer, probably due to it // being busy in some way? gcs_send_text(MAV_SEVERITY_WARNING, "PX4IO override enable failed"); } } else if (!override_requested && px4io_override_enabled) { px4io_override_enabled = false; RC_Channel_aux::enable_aux_servos(); gcs_send_text(MAV_SEVERITY_WARNING, "PX4IO override disabled"); } if (px4io_override_enabled && hal.util->safety_switch_state() != AP_HAL::Util::SAFETY_ARMED && g.override_safety == 1) { // we force safety off, so that if this override is used // with a in-flight reboot it gives a way for the pilot to // re-arm and take manual control hal.rcout->force_safety_off(); } } #endif // CONFIG_HAL_BOARD }
// init_arm_motors - performs arming process including initialisation of barometer and gyros // returns false if arming failed because of pre-arm checks, arming checks or a gyro calibration failure bool Copter::init_arm_motors(bool arming_from_gcs) { static bool in_arm_motors = false; // exit immediately if already in this function if (in_arm_motors) { return false; } in_arm_motors = true; // run pre-arm-checks and display failures if(!pre_arm_checks(true) || !arm_checks(true, arming_from_gcs)) { AP_Notify::events.arming_failed = true; in_arm_motors = false; return false; } // disable cpu failsafe because initialising everything takes a while failsafe_disable(); // reset battery failsafe set_failsafe_battery(false); // notify that arming will occur (we do this early to give plenty of warning) AP_Notify::flags.armed = true; // call update_notify a few times to ensure the message gets out for (uint8_t i=0; i<=10; i++) { update_notify(); } #if HIL_MODE != HIL_MODE_DISABLED || CONFIG_HAL_BOARD == HAL_BOARD_SITL gcs_send_text(MAV_SEVERITY_INFO, "ARMING MOTORS"); #endif // Remember Orientation // -------------------- init_simple_bearing(); initial_armed_bearing = ahrs.yaw_sensor; if (ap.home_state == HOME_UNSET) { // Reset EKF altitude if home hasn't been set yet (we use EKF altitude as substitute for alt above home) ahrs.resetHeightDatum(); Log_Write_Event(DATA_EKF_ALT_RESET); } else if (ap.home_state == HOME_SET_NOT_LOCKED) { // Reset home position if it has already been set before (but not locked) set_home_to_current_location(); } calc_distance_and_bearing(); // enable gps velocity based centrefugal force compensation ahrs.set_correct_centrifugal(true); hal.util->set_soft_armed(true); #if SPRAYER == ENABLED // turn off sprayer's test if on sprayer.test_pump(false); #endif // short delay to allow reading of rc inputs delay(30); // enable output to motors enable_motor_output(); // finally actually arm the motors motors.armed(true); // log arming to dataflash Log_Write_Event(DATA_ARMED); // log flight mode in case it was changed while vehicle was disarmed DataFlash.Log_Write_Mode(control_mode); // reenable failsafe failsafe_enable(); // perf monitor ignores delay due to arming perf_ignore_this_loop(); // flag exiting this function in_arm_motors = false; // return success return true; }
void Rover::init_barometer(void) { gcs_send_text(MAV_SEVERITY_INFO, "Calibrating barometer"); barometer.calibrate(); gcs_send_text(MAV_SEVERITY_INFO, "barometer calibration complete"); }
/* * Determine if we have crashed */ void Plane::crash_detection_update(void) { if (control_mode != AUTO || !g.crash_detection_enable) { // crash detection is only available in AUTO mode crash_state.debounce_timer_ms = 0; crash_state.is_crashed = false; return; } uint32_t now_ms = AP_HAL::millis(); bool crashed_near_land_waypoint = false; bool crashed = false; bool been_auto_flying = (auto_state.started_flying_in_auto_ms > 0) && (now_ms - auto_state.started_flying_in_auto_ms >= 2500); if (!is_flying() && been_auto_flying) { switch (flight_stage) { case AP_SpdHgtControl::FLIGHT_TAKEOFF: case AP_SpdHgtControl::FLIGHT_NORMAL: if (!in_preLaunch_flight_stage()) { crashed = true; } // TODO: handle auto missions without NAV_TAKEOFF mission cmd break; case AP_SpdHgtControl::FLIGHT_VTOL: // we need a totally new method for this crashed = false; break; case AP_SpdHgtControl::FLIGHT_LAND_APPROACH: crashed = true; // when altitude gets low, we automatically progress to FLIGHT_LAND_FINAL // so ground crashes most likely can not be triggered from here. However, // a crash into a tree would be caught here. break; case AP_SpdHgtControl::FLIGHT_LAND_PREFLARE: case AP_SpdHgtControl::FLIGHT_LAND_FINAL: // We should be nice and level-ish in this flight stage. If not, we most // likely had a crazy landing. Throttle is inhibited already at the flare // but go ahead and notify GCS and perform any additional post-crash actions. // Declare a crash if we are oriented more that 60deg in pitch or roll if (!crash_state.checkedHardLanding && // only check once (fabsf(ahrs.roll_sensor) > 6000 || fabsf(ahrs.pitch_sensor) > 6000)) { crashed = true; // did we "crash" within 75m of the landing location? Probably just a hard landing crashed_near_land_waypoint = get_distance(current_loc, mission.get_current_nav_cmd().content.location) < 75; // trigger hard landing event right away, or never again. This inhibits a false hard landing // event when, for example, a minute after a good landing you pick the plane up and // this logic is still running and detects the plane is on its side as you carry it. crash_state.debounce_timer_ms = now_ms + CRASH_DETECTION_DELAY_MS; } crash_state.checkedHardLanding = true; break; default: break; } // switch } else { crash_state.checkedHardLanding = false; } if (!crashed) { // reset timer crash_state.debounce_timer_ms = 0; } else if (crash_state.debounce_timer_ms == 0) { // start timer crash_state.debounce_timer_ms = now_ms; } else if ((now_ms - crash_state.debounce_timer_ms >= CRASH_DETECTION_DELAY_MS) && !crash_state.is_crashed) { crash_state.is_crashed = true; if (g.crash_detection_enable == CRASH_DETECT_ACTION_BITMASK_DISABLED) { if (crashed_near_land_waypoint) { gcs_send_text(MAV_SEVERITY_CRITICAL, "Hard landing detected. No action taken"); } else { gcs_send_text(MAV_SEVERITY_EMERGENCY, "Crash detected. No action taken"); } } else { if (g.crash_detection_enable & CRASH_DETECT_ACTION_BITMASK_DISARM) { disarm_motors(); } auto_state.land_complete = true; if (crashed_near_land_waypoint) { gcs_send_text(MAV_SEVERITY_CRITICAL, "Hard landing detected"); } else { gcs_send_text(MAV_SEVERITY_EMERGENCY, "Crash detected"); } } } }
void Copter::init_ardupilot() { if (!hal.gpio->usb_connected()) { // USB is not connected, this means UART0 may be a Xbee, with // its darned bricking problem. We can't write to it for at // least one second after powering up. Simplest solution for // now is to delay for 1 second. Something more elegant may be // added later delay(1000); } // initialise serial port serial_manager.init_console(); // init vehicle capabilties init_capabilities(); cliSerial->printf("\n\nInit " FIRMWARE_STRING "\n\nFree RAM: %u\n", (unsigned)hal.util->available_memory()); // // Report firmware version code expect on console (check of actual EEPROM format version is done in load_parameters function) // report_version(); // load parameters from EEPROM load_parameters(); BoardConfig.init(); // initialise serial port serial_manager.init(); // init EPM cargo gripper #if EPM_ENABLED == ENABLED epm.init(); #endif // initialise notify system // disable external leds if epm is enabled because of pin conflict on the APM notify.init(true); // initialise battery monitor battery.init(); // Init RSSI rssi.init(); barometer.init(); // Register the mavlink service callback. This will run // anytime there are more than 5ms remaining in a call to // hal.scheduler->delay. hal.scheduler->register_delay_callback(mavlink_delay_cb_static, 5); // we start by assuming USB connected, as we initialed the serial // port with SERIAL0_BAUD. check_usb_mux() fixes this if need be. ap.usb_connected = true; check_usb_mux(); // init the GCS connected to the console gcs[0].setup_uart(serial_manager, AP_SerialManager::SerialProtocol_Console, 0); // init telemetry port gcs[1].setup_uart(serial_manager, AP_SerialManager::SerialProtocol_MAVLink, 0); // setup serial port for telem2 gcs[2].setup_uart(serial_manager, AP_SerialManager::SerialProtocol_MAVLink, 1); // setup serial port for fourth telemetry port (not used by default) gcs[3].setup_uart(serial_manager, AP_SerialManager::SerialProtocol_MAVLink, 2); #if FRSKY_TELEM_ENABLED == ENABLED // setup frsky frsky_telemetry.init(serial_manager); #endif // identify ourselves correctly with the ground station mavlink_system.sysid = g.sysid_this_mav; #if LOGGING_ENABLED == ENABLED log_init(); #endif GCS_MAVLINK::set_dataflash(&DataFlash); // update motor interlock state update_using_interlock(); #if FRAME_CONFIG == HELI_FRAME // trad heli specific initialisation heli_init(); #endif init_rc_in(); // sets up rc channels from radio init_rc_out(); // sets up motors and output to escs // initialise which outputs Servo and Relay events can use ServoRelayEvents.set_channel_mask(~motors.get_motor_mask()); relay.init(); /* * setup the 'main loop is dead' check. Note that this relies on * the RC library being initialised. */ hal.scheduler->register_timer_failsafe(failsafe_check_static, 1000); // Do GPS init gps.init(&DataFlash, serial_manager); if(g.compass_enabled) init_compass(); #if OPTFLOW == ENABLED // make optflow available to AHRS ahrs.set_optflow(&optflow); #endif // init Location class Location_Class::set_ahrs(&ahrs); #if AP_TERRAIN_AVAILABLE && AC_TERRAIN Location_Class::set_terrain(&terrain); wp_nav.set_terrain(&terrain); #endif pos_control.set_dt(MAIN_LOOP_SECONDS); // init the optical flow sensor init_optflow(); #if MOUNT == ENABLED // initialise camera mount camera_mount.init(&DataFlash, serial_manager); #endif #if PRECISION_LANDING == ENABLED // initialise precision landing init_precland(); #endif #ifdef USERHOOK_INIT USERHOOK_INIT #endif #if CLI_ENABLED == ENABLED if (g.cli_enabled) { const char *msg = "\nPress ENTER 3 times to start interactive setup\n"; cliSerial->println(msg); if (gcs[1].initialised && (gcs[1].get_uart() != NULL)) { gcs[1].get_uart()->println(msg); } if (num_gcs > 2 && gcs[2].initialised && (gcs[2].get_uart() != NULL)) { gcs[2].get_uart()->println(msg); } } #endif // CLI_ENABLED #if HIL_MODE != HIL_MODE_DISABLED while (barometer.get_last_update() == 0) { // the barometer begins updating when we get the first // HIL_STATE message gcs_send_text(MAV_SEVERITY_WARNING, "Waiting for first HIL_STATE message"); delay(1000); } // set INS to HIL mode ins.set_hil_mode(); #endif // read Baro pressure at ground //----------------------------- init_barometer(true); // initialise sonar #if CONFIG_SONAR == ENABLED init_sonar(); #endif // initialise AP_RPM library rpm_sensor.init(); // initialise mission library mission.init(); // initialise the flight mode and aux switch // --------------------------- reset_control_switch(); init_aux_switches(); startup_INS_ground(); // set landed flags set_land_complete(true); set_land_complete_maybe(true); // we don't want writes to the serial port to cause us to pause // mid-flight, so set the serial ports non-blocking once we are // ready to fly serial_manager.set_blocking_writes_all(false); // enable CPU failsafe failsafe_enable(); ins.set_raw_logging(should_log(MASK_LOG_IMU_RAW)); ins.set_dataflash(&DataFlash); cliSerial->print("\nReady to FLY "); // flag that initialisation has completed ap.initialised = true; }
/* main flight mode dependent update code */ void Plane::update_flight_mode(void) { enum FlightMode effective_mode = control_mode; if (control_mode == AUTO && g.auto_fbw_steer == 42) { effective_mode = FLY_BY_WIRE_A; } if (effective_mode != AUTO) { // hold_course is only used in takeoff and landing steer_state.hold_course_cd = -1; } // ensure we are fly-forward if (quadplane.in_vtol_mode()) { ahrs.set_fly_forward(false); } else { ahrs.set_fly_forward(true); } switch (effective_mode) { case AUTO: handle_auto_mode(); break; case GUIDED: if (auto_state.vtol_loiter && quadplane.available()) { quadplane.guided_update(); break; } // fall through case RTL: case LOITER: calc_nav_roll(); calc_nav_pitch(); calc_throttle(); break; case TRAINING: { training_manual_roll = false; training_manual_pitch = false; update_load_factor(); // if the roll is past the set roll limit, then // we set target roll to the limit if (ahrs.roll_sensor >= roll_limit_cd) { nav_roll_cd = roll_limit_cd; } else if (ahrs.roll_sensor <= -roll_limit_cd) { nav_roll_cd = -roll_limit_cd; } else { training_manual_roll = true; nav_roll_cd = 0; } // if the pitch is past the set pitch limits, then // we set target pitch to the limit if (ahrs.pitch_sensor >= aparm.pitch_limit_max_cd) { nav_pitch_cd = aparm.pitch_limit_max_cd; } else if (ahrs.pitch_sensor <= pitch_limit_min_cd) { nav_pitch_cd = pitch_limit_min_cd; } else { training_manual_pitch = true; nav_pitch_cd = 0; } if (fly_inverted()) { nav_pitch_cd = -nav_pitch_cd; } break; } case ACRO: { // handle locked/unlocked control if (acro_state.locked_roll) { nav_roll_cd = acro_state.locked_roll_err; } else { nav_roll_cd = ahrs.roll_sensor; } if (acro_state.locked_pitch) { nav_pitch_cd = acro_state.locked_pitch_cd; } else { nav_pitch_cd = ahrs.pitch_sensor; } break; } case AUTOTUNE: case FLY_BY_WIRE_A: { // set nav_roll and nav_pitch using sticks nav_roll_cd = channel_roll->norm_input() * roll_limit_cd; nav_roll_cd = constrain_int32(nav_roll_cd, -roll_limit_cd, roll_limit_cd); update_load_factor(); float pitch_input = channel_pitch->norm_input(); if (pitch_input > 0) { nav_pitch_cd = pitch_input * aparm.pitch_limit_max_cd; } else { nav_pitch_cd = -(pitch_input * pitch_limit_min_cd); } adjust_nav_pitch_throttle(); nav_pitch_cd = constrain_int32(nav_pitch_cd, pitch_limit_min_cd, aparm.pitch_limit_max_cd.get()); if (fly_inverted()) { nav_pitch_cd = -nav_pitch_cd; } if (failsafe.ch3_failsafe && g.short_fs_action == 2) { // FBWA failsafe glide nav_roll_cd = 0; nav_pitch_cd = 0; channel_throttle->set_servo_out(0); } if (g.fbwa_tdrag_chan > 0) { // check for the user enabling FBWA taildrag takeoff mode bool tdrag_mode = (hal.rcin->read(g.fbwa_tdrag_chan-1) > 1700); if (tdrag_mode && !auto_state.fbwa_tdrag_takeoff_mode) { if (auto_state.highest_airspeed < g.takeoff_tdrag_speed1) { auto_state.fbwa_tdrag_takeoff_mode = true; gcs_send_text(MAV_SEVERITY_WARNING, "FBWA tdrag mode"); } } } break; } case FLY_BY_WIRE_B: // Thanks to Yury MonZon for the altitude limit code! nav_roll_cd = channel_roll->norm_input() * roll_limit_cd; nav_roll_cd = constrain_int32(nav_roll_cd, -roll_limit_cd, roll_limit_cd); update_load_factor(); update_fbwb_speed_height(); break; case CRUISE: /* in CRUISE mode we use the navigation code to control roll when heading is locked. Heading becomes unlocked on any aileron or rudder input */ if ((channel_roll->get_control_in() != 0 || rudder_input != 0)) { cruise_state.locked_heading = false; cruise_state.lock_timer_ms = 0; } if (!cruise_state.locked_heading) { nav_roll_cd = channel_roll->norm_input() * roll_limit_cd; nav_roll_cd = constrain_int32(nav_roll_cd, -roll_limit_cd, roll_limit_cd); update_load_factor(); } else { calc_nav_roll(); } update_fbwb_speed_height(); break; case STABILIZE: nav_roll_cd = 0; nav_pitch_cd = 0; // throttle is passthrough break; case CIRCLE: // we have no GPS installed and have lost radio contact // or we just want to fly around in a gentle circle w/o GPS, // holding altitude at the altitude we set when we // switched into the mode nav_roll_cd = roll_limit_cd / 3; update_load_factor(); calc_nav_pitch(); calc_throttle(); break; case MANUAL: // servo_out is for Sim control only // --------------------------------- channel_roll->set_servo_out(channel_roll->pwm_to_angle()); channel_pitch->set_servo_out(channel_pitch->pwm_to_angle()); steering_control.steering = steering_control.rudder = channel_rudder->pwm_to_angle(); break; //roll: -13788.000, pitch: -13698.000, thr: 0.000, rud: -13742.000 case QSTABILIZE: case QHOVER: case QLOITER: case QLAND: case QRTL: { // set nav_roll and nav_pitch using sticks int16_t roll_limit = MIN(roll_limit_cd, quadplane.aparm.angle_max); nav_roll_cd = channel_roll->norm_input() * roll_limit; nav_roll_cd = constrain_int32(nav_roll_cd, -roll_limit, roll_limit); float pitch_input = channel_pitch->norm_input(); if (pitch_input > 0) { nav_pitch_cd = pitch_input * MIN(aparm.pitch_limit_max_cd, quadplane.aparm.angle_max); } else { nav_pitch_cd = pitch_input * MIN(-pitch_limit_min_cd, quadplane.aparm.angle_max); } nav_pitch_cd = constrain_int32(nav_pitch_cd, pitch_limit_min_cd, aparm.pitch_limit_max_cd.get()); break; } case INITIALISING: // handled elsewhere break; } }