2013-10-29 10:11:48 -03:00
/// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
// Code to detect a crash main ArduCopter code
#ifndef CRASH_CHECK_ITERATIONS_MAX
2013-10-30 01:27:06 -03:00
# define CRASH_CHECK_ITERATIONS_MAX 20 // 2 second (ie. 10 iterations at 10hz) inverted indicates a crash
2013-10-29 10:11:48 -03:00
#endif
#ifndef CRASH_CHECK_ANGLE_DEVIATION_CD
2013-10-30 01:27:06 -03:00
# define CRASH_CHECK_ANGLE_DEVIATION_CD 2000 // 20 degrees beyond angle max is signal we are inverted
#endif
#ifndef CRASH_CHECK_ALT_CHANGE_LIMIT_CM
# define CRASH_CHECK_ALT_CHANGE_LIMIT_CM 50 // baro altitude must not change by more than 50cm
2013-10-29 10:11:48 -03:00
#endif
// 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
// should be called at 10hz
void crash_check()
{
static uint8_t inverted_count; // number of iterations we have been inverted
2013-10-30 01:27:06 -03:00
static int32_t baro_alt_prev;
2013-10-29 10:11:48 -03:00
2014-04-02 12:20:20 -03:00
#if PARACHUTE == ENABLED
// check parachute
parachute_check();
#endif
2013-10-30 01:27:06 -03:00
// return immediately if motors are not armed or pilot's throttle is above zero
if (!motors.armed() || (g.rc_3.control_in != 0 && !failsafe.radio)) {
2013-10-29 10:11:48 -03:00
inverted_count = 0;
return;
}
// return immediately if we are not in an angle stabilize flight mode or we are flipping
2014-02-03 03:25:11 -04:00
if (control_mode == ACRO || control_mode == FLIP) {
2013-10-29 10:11:48 -03:00
inverted_count = 0;
return;
}
// check angles
2013-10-18 05:03:31 -03:00
int32_t lean_max = aparm.angle_max + CRASH_CHECK_ANGLE_DEVIATION_CD;
2013-10-29 10:11:48 -03:00
if (labs(ahrs.roll_sensor) > lean_max || labs(ahrs.pitch_sensor) > lean_max) {
inverted_count++;
2013-10-30 01:27:06 -03:00
// if we have just become inverted record the baro altitude
if (inverted_count == 1) {
baro_alt_prev = baro_alt;
// exit if baro altitude change indicates we are moving (probably falling)
}else if (labs(baro_alt - baro_alt_prev) > CRASH_CHECK_ALT_CHANGE_LIMIT_CM) {
inverted_count = 0;
return;
// check if inverted for 2 seconds
}else if (inverted_count >= CRASH_CHECK_ITERATIONS_MAX) {
2013-10-29 10:11:48 -03:00
// log an error in the dataflash
Log_Write_Error(ERROR_SUBSYSTEM_CRASH_CHECK, ERROR_CODE_CRASH_CHECK_CRASH);
// send message to gcs
2013-10-30 01:27:06 -03:00
gcs_send_text_P(SEVERITY_HIGH,PSTR("Crash: Disarming"));
2013-10-29 10:11:48 -03:00
// disarm motors
init_disarm_motors();
}
2013-10-30 01:27:06 -03:00
}else{
// we are not inverted so reset counter
inverted_count = 0;
2013-10-29 10:11:48 -03:00
}
}
2014-04-02 12:20:20 -03:00
#if PARACHUTE == ENABLED
// Code to detect a crash main ArduCopter code
#ifndef PARACHUTE_CHECK_ITERATIONS_MAX
# define PARACHUTE_CHECK_ITERATIONS_MAX 10 // 1 second (ie. 10 iterations at 10hz) of loss of control triggers the parachute
#endif
#ifndef PARACHUTE_CHECK_ANGLE_DEVIATION_CD
# define PARACHUTE_CHECK_ANGLE_DEVIATION_CD 3000 // 30 degrees off from target indicates a loss of control
#endif
// 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
// should be called at 10hz
void parachute_check()
{
static uint8_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;
}
2014-04-02 21:56:30 -03:00
// call update to give parachute a chance to move servo or relay back to off position
parachute.update();
2014-04-02 12:20:20 -03:00
// 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;
}
2014-04-03 05:55:34 -03:00
// ensure we are flying
if (ap.land_complete) {
2014-04-02 21:56:30 -03:00
control_loss_count = 0;
return;
}
2014-04-03 05:55:34 -03:00
// ensure the first control_loss event is from above the min altitude
2014-04-06 23:18:54 -03:00
if (control_loss_count == 0 && parachute.alt_min() != 0 && (baro_alt < (uint32_t)parachute.alt_min() * 100)) {
2014-04-03 05:55:34 -03:00
return;
}
2014-04-02 12:20:20 -03:00
// get desired lean angles
const Vector3f& target_angle = attitude_control.angle_ef_targets();
// check roll and pitch angles
if (labs(ahrs.roll_sensor - target_angle.x) > CRASH_CHECK_ANGLE_DEVIATION_CD ||
labs(ahrs.pitch_sensor - target_angle.y) > CRASH_CHECK_ANGLE_DEVIATION_CD) {
control_loss_count++;
2014-04-02 21:56:30 -03:00
// don't let control_loss_count get too high
if (control_loss_count > PARACHUTE_CHECK_ITERATIONS_MAX) {
control_loss_count = PARACHUTE_CHECK_ITERATIONS_MAX;
}
2014-04-03 05:55:34 -03:00
// record baro alt if we have just started losing control
2014-04-02 12:20:20 -03:00
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_ITERATIONS_MAX) {
2014-04-02 21:56:30 -03:00
// reset control loss counter
control_loss_count = 0;
2014-04-03 05:55:34 -03:00
// log an error in the dataflash
Log_Write_Error(ERROR_SUBSYSTEM_CRASH_CHECK, ERROR_CODE_CRASH_CHECK_LOSS_OF_CONTROL);
2014-04-02 21:56:30 -03:00
// release parachute
2014-04-02 12:20:20 -03:00
parachute_release();
}
}else{
// we are not inverted so reset counter
control_loss_count = 0;
}
}
// parachute_release - trigger the release of the parachute, disarm the motors and notify the user
static void parachute_release()
{
2014-04-03 05:55:34 -03:00
// send message to gcs and dataflash
2014-04-02 12:20:20 -03:00
gcs_send_text_P(SEVERITY_HIGH,PSTR("Parachute: Released!"));
2014-04-03 05:55:34 -03:00
Log_Write_Event(DATA_PARACHUTE_RELEASED);
2014-04-02 12:20:20 -03:00
// disarm motors
init_disarm_motors();
// release parachute
parachute.release();
}
2014-04-02 21:56:30 -03:00
// parachute_manual_release - trigger the release of the parachute, after performing some checks for pilot error
// checks if the vehicle is landed
static void parachute_manual_release()
{
2014-04-07 00:16:57 -03:00
// exit immediately if parachute is not enabled
if (!parachute.enabled()) {
return;
}
2014-04-02 21:56:30 -03:00
// do not release if we are landed or below the minimum altitude above home
2014-04-06 23:18:54 -03:00
if (ap.land_complete || (parachute.alt_min() != 0 && (baro_alt < (uint32_t)parachute.alt_min() * 100))) {
2014-04-02 21:56:30 -03:00
// warn user of reason for failure
2014-04-03 05:55:34 -03:00
gcs_send_text_P(SEVERITY_HIGH,PSTR("Parachute: Too Low"));
// log an error in the dataflash
Log_Write_Error(ERROR_SUBSYSTEM_PARACHUTE, ERROR_CODE_PARACHUTE_TOO_LOW);
2014-04-02 21:56:30 -03:00
return;
}
// if we get this far release parachute
parachute_release();
}
2014-04-03 05:55:34 -03:00
2014-04-06 23:18:54 -03:00
#endif // PARACHUTE == ENABLED