mirror of
https://github.com/ArduPilot/ardupilot
synced 2025-01-03 06:28:27 -04:00
1f2d17e8e7
Previously a single moment where the vehicle was within 30deg of the target could cause the parachute release counter to reset to zero. This change makes the parachute release if it is spending at least half it's time with more than a 30degree angle error.
187 lines
6.5 KiB
C++
187 lines
6.5 KiB
C++
/// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
|
|
#include "Copter.h"
|
|
|
|
// Code to detect a crash main ArduCopter code
|
|
#define CRASH_CHECK_TRIGGER_SEC 2 // 2 seconds inverted indicates a crash
|
|
#define CRASH_CHECK_ANGLE_DEVIATION_DEG 30.0f // 30 degrees beyond angle max is signal we are inverted
|
|
#define CRASH_CHECK_ACCEL_MAX 3.0f // vehicle must be accelerating less than 3m/s/s to be considered crashed
|
|
|
|
// 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 float angle_error = attitude_control.get_att_error_angle_deg();
|
|
if (angle_error <= CRASH_CHECK_ANGLE_DEVIATION_DEG) {
|
|
crash_counter = 0;
|
|
return;
|
|
}
|
|
|
|
// we may be crashing
|
|
crash_counter++;
|
|
|
|
// check if crashing for 2 seconds
|
|
if (crash_counter >= (CRASH_CHECK_TRIGGER_SEC * scheduler.get_loop_rate_hz())) {
|
|
// 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();
|
|
}
|
|
}
|
|
|
|
#if PARACHUTE == ENABLED
|
|
|
|
// Code to detect a crash main ArduCopter code
|
|
#define PARACHUTE_CHECK_TRIGGER_SEC 1 // 1 second of loss of control triggers the parachute
|
|
#define PARACHUTE_CHECK_ANGLE_DEVIATION_CD 3000 // 30 degrees off from target indicates a loss of control
|
|
|
|
// parachute_check - disarms motors and triggers the parachute if serious loss of control has been detected
|
|
// vehicle is considered to have a "serious loss of control" by the vehicle being more than 30 degrees off from the target roll and pitch angles continuously for 1 second
|
|
// called at MAIN_LOOP_RATE
|
|
void Copter::parachute_check()
|
|
{
|
|
static uint16_t control_loss_count; // number of iterations we have been out of control
|
|
static int32_t baro_alt_start;
|
|
|
|
// exit immediately if parachute is not enabled
|
|
if (!parachute.enabled()) {
|
|
return;
|
|
}
|
|
|
|
// call update to give parachute a chance to move servo or relay back to off position
|
|
parachute.update();
|
|
|
|
// return immediately if motors are not armed or pilot's throttle is above zero
|
|
if (!motors.armed()) {
|
|
control_loss_count = 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) {
|
|
control_loss_count = 0;
|
|
return;
|
|
}
|
|
|
|
// ensure we are flying
|
|
if (ap.land_complete) {
|
|
control_loss_count = 0;
|
|
return;
|
|
}
|
|
|
|
// ensure the first control_loss event is from above the min altitude
|
|
if (control_loss_count == 0 && parachute.alt_min() != 0 && (current_loc.alt < (int32_t)parachute.alt_min() * 100)) {
|
|
return;
|
|
}
|
|
|
|
// check for angle error over 30 degrees
|
|
const float angle_error = attitude_control.get_att_error_angle_deg();
|
|
if (angle_error <= CRASH_CHECK_ANGLE_DEVIATION_DEG) {
|
|
if (control_loss_count > 0) {
|
|
control_loss_count--;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// increment counter
|
|
if (control_loss_count < (PARACHUTE_CHECK_TRIGGER_SEC*scheduler.get_loop_rate_hz())) {
|
|
control_loss_count++;
|
|
}
|
|
|
|
// record baro alt if we have just started losing control
|
|
if (control_loss_count == 1) {
|
|
baro_alt_start = baro_alt;
|
|
|
|
// exit if baro altitude change indicates we are not falling
|
|
} else if (baro_alt >= baro_alt_start) {
|
|
control_loss_count = 0;
|
|
return;
|
|
|
|
// To-Do: add check that the vehicle is actually falling
|
|
|
|
// check if loss of control for at least 1 second
|
|
} else if (control_loss_count >= (PARACHUTE_CHECK_TRIGGER_SEC*scheduler.get_loop_rate_hz())) {
|
|
// reset control loss counter
|
|
control_loss_count = 0;
|
|
// log an error in the dataflash
|
|
Log_Write_Error(ERROR_SUBSYSTEM_CRASH_CHECK, ERROR_CODE_CRASH_CHECK_LOSS_OF_CONTROL);
|
|
// release parachute
|
|
parachute_release();
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
// parachute_manual_release - trigger the release of the parachute, after performing some checks for pilot error
|
|
// checks if the vehicle is landed
|
|
void Copter::parachute_manual_release()
|
|
{
|
|
// exit immediately if parachute is not enabled
|
|
if (!parachute.enabled()) {
|
|
return;
|
|
}
|
|
|
|
// do not release if vehicle is landed
|
|
// do not release if we are landed or below the minimum altitude above home
|
|
if (ap.land_complete) {
|
|
// warn user of reason for failure
|
|
gcs_send_text(MAV_SEVERITY_INFO,"Parachute: Landed");
|
|
// log an error in the dataflash
|
|
Log_Write_Error(ERROR_SUBSYSTEM_PARACHUTE, ERROR_CODE_PARACHUTE_LANDED);
|
|
return;
|
|
}
|
|
|
|
// do not release if we are landed or below the minimum altitude above home
|
|
if ((parachute.alt_min() != 0 && (current_loc.alt < (int32_t)parachute.alt_min() * 100))) {
|
|
// warn user of reason for failure
|
|
gcs_send_text(MAV_SEVERITY_ALERT,"Parachute: Too low");
|
|
// log an error in the dataflash
|
|
Log_Write_Error(ERROR_SUBSYSTEM_PARACHUTE, ERROR_CODE_PARACHUTE_TOO_LOW);
|
|
return;
|
|
}
|
|
|
|
// if we get this far release parachute
|
|
parachute_release();
|
|
}
|
|
|
|
#endif // PARACHUTE == ENABLED
|