mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-06-13 15:40:05 +08:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f29f7bb1e3 | |||
| 82b28bc72f | |||
| 7ca16cd504 | |||
| 1080855f4d | |||
| ba1b6f4d2c | |||
| 3398380262 | |||
| 3dffa5e6df |
@@ -36,5 +36,5 @@
|
||||
constexpr px4_i2c_bus_t px4_i2c_buses[I2C_BUS_MAX_BUS_ITEMS] = {
|
||||
initI2CBusExternal(1),
|
||||
initI2CBusExternal(2),
|
||||
initI2CBusExternal(4),
|
||||
initI2CBusInternal(4),
|
||||
};
|
||||
|
||||
@@ -113,12 +113,6 @@ uint8 reset_count_quat # number of quaternion reset events (allow to wrap if c
|
||||
|
||||
float32 time_slip # cumulative amount of time in seconds that the EKF inertial calculation has slipped relative to system time
|
||||
|
||||
bool pre_flt_fail_innov_heading
|
||||
bool pre_flt_fail_innov_vel_horiz
|
||||
bool pre_flt_fail_innov_vel_vert
|
||||
bool pre_flt_fail_innov_height
|
||||
bool pre_flt_fail_mag_field_disturbed
|
||||
|
||||
uint32 accel_device_id
|
||||
uint32 gyro_device_id
|
||||
uint32 baro_device_id
|
||||
|
||||
@@ -73,3 +73,10 @@ bool reject_sideslip # 9 - true if the synthetic sideslip
|
||||
bool reject_hagl # 10 - true if the height above ground observation has been rejected
|
||||
bool reject_optflow_x # 11 - true if the X optical flow observation has been rejected
|
||||
bool reject_optflow_y # 12 - true if the Y optical flow observation has been rejected
|
||||
|
||||
|
||||
# preflight failure flags
|
||||
bool pre_flt_fail_innov_heading
|
||||
bool pre_flt_fail_innov_vel_horiz
|
||||
bool pre_flt_fail_innov_vel_vert
|
||||
bool pre_flt_fail_innov_height
|
||||
|
||||
@@ -68,11 +68,19 @@ BMP388::init()
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (_interface->get_reg(BMP3_CHIP_ID_ADDR) != BMP3_CHIP_ID) {
|
||||
PX4_WARN("id of your baro is not: 0x%02x", BMP3_CHIP_ID);
|
||||
_chip_id = _interface->get_reg(BMP3_CHIP_ID_ADDR);
|
||||
|
||||
if (_chip_id != BMP388_CHIP_ID && _chip_id != BMP390_CHIP_ID) {
|
||||
PX4_WARN("id of your baro is not: 0x%02x or 0x%02x", BMP388_CHIP_ID, BMP390_CHIP_ID);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (_chip_id == BMP390_CHIP_ID) {
|
||||
_interface->set_device_type(DRV_BARO_DEVTYPE_BMP390);
|
||||
}
|
||||
|
||||
_chip_rev_id = _interface->get_reg(BMP3_REV_ID_ADDR);
|
||||
|
||||
_cal = _interface->get_calibration(BMP3_CALIB_DATA_ADDR);
|
||||
|
||||
if (!_cal) {
|
||||
@@ -99,6 +107,7 @@ void
|
||||
BMP388::print_status()
|
||||
{
|
||||
I2CSPIDriverBase::print_status();
|
||||
printf("chip id: 0x%02x rev id: 0x%02x\n", _chip_id, _chip_rev_id);
|
||||
perf_print_counter(_sample_perf);
|
||||
perf_print_counter(_measure_perf);
|
||||
perf_print_counter(_comms_errors);
|
||||
|
||||
@@ -51,7 +51,8 @@
|
||||
|
||||
// From https://github.com/BoschSensortec/BMP3-Sensor-API/blob/master/bmp3_defs.h
|
||||
|
||||
#define BMP3_CHIP_ID (0x50)
|
||||
#define BMP388_CHIP_ID (0x50)
|
||||
#define BMP390_CHIP_ID (0x60)
|
||||
|
||||
/* Over sampling macros */
|
||||
#define BMP3_NO_OVERSAMPLING (0x00)
|
||||
@@ -79,6 +80,7 @@
|
||||
|
||||
/* Register Address */
|
||||
#define BMP3_CHIP_ID_ADDR (0x00)
|
||||
#define BMP3_REV_ID_ADDR (0x01)
|
||||
#define BMP3_ERR_REG_ADDR (0x02)
|
||||
#define BMP3_SENS_STATUS_REG_ADDR (0x03)
|
||||
#define BMP3_DATA_ADDR (0x04)
|
||||
@@ -304,6 +306,8 @@ public:
|
||||
virtual uint32_t get_device_id() const = 0;
|
||||
|
||||
virtual uint8_t get_device_address() const = 0;
|
||||
|
||||
virtual void set_device_type(uint8_t devtype) = 0;
|
||||
};
|
||||
|
||||
class BMP388 : public I2CSPIDriver<BMP388>
|
||||
@@ -339,6 +343,9 @@ private:
|
||||
|
||||
bool _collect_phase{false};
|
||||
|
||||
uint8_t _chip_id{0};
|
||||
uint8_t _chip_rev_id{0};
|
||||
|
||||
void start();
|
||||
int measure();
|
||||
int collect(); //get results and publish
|
||||
|
||||
@@ -58,6 +58,7 @@ public:
|
||||
|
||||
uint8_t get_device_address() const override { return device::I2C::get_device_address(); }
|
||||
|
||||
void set_device_type(uint8_t devtype);
|
||||
private:
|
||||
struct calibration_s _cal;
|
||||
};
|
||||
@@ -108,3 +109,8 @@ calibration_s *BMP388_I2C::get_calibration(uint8_t addr)
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void BMP388_I2C::set_device_type(uint8_t devtype)
|
||||
{
|
||||
device::Device::set_device_type(devtype);
|
||||
}
|
||||
|
||||
@@ -74,6 +74,8 @@ public:
|
||||
uint32_t get_device_id() const override { return device::SPI::get_device_id(); }
|
||||
|
||||
uint8_t get_device_address() const override { return device::SPI::get_device_address(); }
|
||||
|
||||
void set_device_type(uint8_t devtype);
|
||||
private:
|
||||
spi_calibration_s _cal;
|
||||
};
|
||||
@@ -124,3 +126,8 @@ calibration_s *BMP388_SPI::get_calibration(uint8_t addr)
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void BMP388_SPI::set_device_type(uint8_t devtype)
|
||||
{
|
||||
device::Device::set_device_type(devtype);
|
||||
}
|
||||
|
||||
@@ -234,7 +234,6 @@ void AFBRS50::Run()
|
||||
break;
|
||||
|
||||
case STATE::CONFIGURE: {
|
||||
//status_t status = Argus_SetConfigurationFrameTime(_hnd, _measure_interval);
|
||||
status_t status = set_rate(SHORT_RANGE_MODE_HZ);
|
||||
|
||||
if (status != STATUS_OK) {
|
||||
@@ -259,8 +258,6 @@ void AFBRS50::Run()
|
||||
_mode = ARGUS_MODE_B;
|
||||
set_mode(_mode);
|
||||
|
||||
status = Argus_StartMeasurementTimer(_hnd, measurement_ready_callback);
|
||||
|
||||
if (status != STATUS_OK) {
|
||||
PX4_ERR("CONFIGURE status not okay: %i", (int)status);
|
||||
ScheduleNow();
|
||||
@@ -273,7 +270,14 @@ void AFBRS50::Run()
|
||||
break;
|
||||
|
||||
case STATE::COLLECT: {
|
||||
// currently handeled by measurement_ready_callback
|
||||
// Only start a new measurement if one is not ongoing
|
||||
if (Argus_GetStatus(_hnd) == STATUS_IDLE) {
|
||||
status_t status = Argus_TriggerMeasurement(_hnd, measurement_ready_callback);
|
||||
|
||||
if (status != STATUS_OK) {
|
||||
PX4_ERR("Argus_TriggerMeasurement status not okay: %i", (int)status);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateMode();
|
||||
}
|
||||
@@ -290,8 +294,7 @@ void AFBRS50::Run()
|
||||
break;
|
||||
}
|
||||
|
||||
// backup schedule
|
||||
ScheduleDelayed(100_ms);
|
||||
ScheduleDelayed(_measure_interval);
|
||||
}
|
||||
|
||||
void AFBRS50::UpdateMode()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
static volatile irqstate_t irqstate_flags;
|
||||
static volatile size_t _lock_count = 0;
|
||||
|
||||
/*!***************************************************************************
|
||||
* @brief Enable IRQ Interrupts
|
||||
@@ -10,7 +11,13 @@ static volatile irqstate_t irqstate_flags;
|
||||
*****************************************************************************/
|
||||
void IRQ_UNLOCK(void)
|
||||
{
|
||||
leave_critical_section(irqstate_flags);
|
||||
if (_lock_count > 0) {
|
||||
_lock_count--;
|
||||
|
||||
if (_lock_count == 0) {
|
||||
leave_critical_section(irqstate_flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!***************************************************************************
|
||||
@@ -20,5 +27,9 @@ void IRQ_UNLOCK(void)
|
||||
*****************************************************************************/
|
||||
void IRQ_LOCK(void)
|
||||
{
|
||||
irqstate_flags = enter_critical_section();
|
||||
if (_lock_count == 0) {
|
||||
irqstate_flags = enter_critical_section();
|
||||
}
|
||||
|
||||
_lock_count++;
|
||||
}
|
||||
|
||||
@@ -138,22 +138,23 @@ status_t S2PI_SetBaudRate(uint32_t baudRate_Bps)
|
||||
status_t S2PI_CaptureGpioControl(void)
|
||||
{
|
||||
/* Check if something is ongoing. */
|
||||
irqstate_t irqstate_flags = px4_enter_critical_section();
|
||||
IRQ_LOCK();
|
||||
status_t status = s2pi_.Status;
|
||||
|
||||
if (status != STATUS_IDLE) {
|
||||
px4_leave_critical_section(irqstate_flags);
|
||||
IRQ_UNLOCK();
|
||||
return status;
|
||||
}
|
||||
|
||||
s2pi_.Status = STATUS_S2PI_GPIO_MODE;
|
||||
px4_leave_critical_section(irqstate_flags);
|
||||
|
||||
// GPIO mode (output push pull)
|
||||
px4_arch_configgpio(PX4_MAKE_GPIO_OUTPUT_SET(s2pi_.GPIOs[S2PI_CLK]));
|
||||
px4_arch_configgpio(PX4_MAKE_GPIO_OUTPUT_SET(s2pi_.GPIOs[S2PI_MISO]));
|
||||
px4_arch_configgpio(PX4_MAKE_GPIO_INPUT(s2pi_.GPIOs[S2PI_MISO]));
|
||||
px4_arch_configgpio(PX4_MAKE_GPIO_OUTPUT_SET(s2pi_.GPIOs[S2PI_MOSI]));
|
||||
|
||||
IRQ_UNLOCK();
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
@@ -167,16 +168,15 @@ status_t S2PI_CaptureGpioControl(void)
|
||||
status_t S2PI_ReleaseGpioControl(void)
|
||||
{
|
||||
/* Check if something is ongoing. */
|
||||
irqstate_t irqstate_flags = px4_enter_critical_section();
|
||||
IRQ_LOCK();
|
||||
status_t status = s2pi_.Status;
|
||||
|
||||
if (status != STATUS_S2PI_GPIO_MODE) {
|
||||
px4_leave_critical_section(irqstate_flags);
|
||||
IRQ_UNLOCK();
|
||||
return status;
|
||||
}
|
||||
|
||||
s2pi_.Status = STATUS_IDLE;
|
||||
px4_leave_critical_section(irqstate_flags);
|
||||
|
||||
// SPI alternate
|
||||
stm32_configgpio(s2pi_.GPIOs[S2PI_CLK]);
|
||||
@@ -186,6 +186,8 @@ status_t S2PI_ReleaseGpioControl(void)
|
||||
// probably not necessary
|
||||
stm32_spibus_initialize(BROADCOM_AFBR_S50_S2PI_SPI_BUS);
|
||||
|
||||
IRQ_UNLOCK();
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
@@ -254,22 +256,23 @@ status_t S2PI_ReadGpioPin(s2pi_slave_t slave, s2pi_pin_t pin, uint32_t *value)
|
||||
status_t S2PI_CycleCsPin(s2pi_slave_t slave)
|
||||
{
|
||||
/* Check the driver status. */
|
||||
irqstate_t irqstate_flags = px4_enter_critical_section();
|
||||
IRQ_LOCK();
|
||||
status_t status = s2pi_.Status;
|
||||
|
||||
if (status != STATUS_IDLE) {
|
||||
px4_leave_critical_section(irqstate_flags);
|
||||
IRQ_UNLOCK();
|
||||
return status;
|
||||
}
|
||||
|
||||
s2pi_.Status = STATUS_BUSY;
|
||||
px4_leave_critical_section(irqstate_flags);
|
||||
|
||||
px4_arch_gpiowrite(s2pi_.GPIOs[S2PI_CS], 0);
|
||||
px4_arch_gpiowrite(s2pi_.GPIOs[S2PI_CS], 1);
|
||||
|
||||
s2pi_.Status = STATUS_IDLE;
|
||||
|
||||
IRQ_UNLOCK();
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
@@ -339,11 +342,11 @@ status_t S2PI_TransferFrame(s2pi_slave_t spi_slave, uint8_t const *txData, uint8
|
||||
}
|
||||
|
||||
/* Check the driver status, lock if idle. */
|
||||
irqstate_t irqstate_flags = px4_enter_critical_section();
|
||||
IRQ_LOCK();
|
||||
status_t status = s2pi_.Status;
|
||||
|
||||
if (status != STATUS_IDLE) {
|
||||
px4_leave_critical_section(irqstate_flags);
|
||||
IRQ_UNLOCK();
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -358,7 +361,7 @@ status_t S2PI_TransferFrame(s2pi_slave_t spi_slave, uint8_t const *txData, uint8
|
||||
s2pi_.spi_frame_size = frameSize;
|
||||
work_queue(HPWORK, &broadcom_s2pi_transfer_work, broadcom_s2pi_transfer_callout, NULL, 0);
|
||||
|
||||
px4_leave_critical_section(irqstate_flags);
|
||||
IRQ_UNLOCK();
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ static constexpr uint8_t LL40LS_UNIT_ID_3_V4 = 0x19;
|
||||
static constexpr uint8_t LL40LS_DISTHIGH_REG_V4 = 0x10; /* High byte of distance register, auto increment */
|
||||
|
||||
// Normal conversion wait time.
|
||||
static constexpr uint32_t LL40LS_CONVERSION_INTERVAL{50_ms};
|
||||
static constexpr uint32_t LL40LS_CONVERSION_INTERVAL{10_ms};
|
||||
|
||||
// Maximum time to wait for a conversion to complete.
|
||||
static constexpr uint32_t LL40LS_CONVERSION_TIMEOUT{100_ms};
|
||||
|
||||
+13
-12
@@ -128,18 +128,19 @@
|
||||
#define DRV_BARO_DEVTYPE_MPC2520 0x5F
|
||||
#define DRV_BARO_DEVTYPE_LPS22HB 0x60
|
||||
|
||||
#define DRV_ACC_DEVTYPE_LSM303AGR 0x61
|
||||
#define DRV_MAG_DEVTYPE_LSM303AGR 0x62
|
||||
#define DRV_IMU_DEVTYPE_ADIS16497 0x63
|
||||
#define DRV_BARO_DEVTYPE_BAROSIM 0x65
|
||||
#define DRV_GYR_DEVTYPE_BMI088 0x66
|
||||
#define DRV_BARO_DEVTYPE_BMP388 0x67
|
||||
#define DRV_BARO_DEVTYPE_DPS310 0x68
|
||||
#define DRV_PWM_DEVTYPE_PCA9685 0x69
|
||||
#define DRV_ACC_DEVTYPE_BMI088 0x6a
|
||||
#define DRV_OSD_DEVTYPE_ATXXXX 0x6b
|
||||
#define DRV_ACC_DEVTYPE_BMI085 0x6C
|
||||
#define DRV_GYR_DEVTYPE_BMI085 0x6D
|
||||
#define DRV_ACC_DEVTYPE_LSM303AGR 0x61
|
||||
#define DRV_MAG_DEVTYPE_LSM303AGR 0x62
|
||||
#define DRV_IMU_DEVTYPE_ADIS16497 0x63
|
||||
#define DRV_BARO_DEVTYPE_BAROSIM 0x65
|
||||
#define DRV_GYR_DEVTYPE_BMI088 0x66
|
||||
#define DRV_BARO_DEVTYPE_BMP388 0x67
|
||||
#define DRV_BARO_DEVTYPE_DPS310 0x68
|
||||
#define DRV_PWM_DEVTYPE_PCA9685 0x69
|
||||
#define DRV_ACC_DEVTYPE_BMI088 0x6a
|
||||
#define DRV_OSD_DEVTYPE_ATXXXX 0x6b
|
||||
#define DRV_ACC_DEVTYPE_BMI085 0x6C
|
||||
#define DRV_GYR_DEVTYPE_BMI085 0x6D
|
||||
#define DRV_BARO_DEVTYPE_BMP390 0x6E
|
||||
|
||||
#define DRV_DIST_DEVTYPE_LL40LS 0x70
|
||||
#define DRV_DIST_DEVTYPE_MAPPYDOT 0x71
|
||||
|
||||
+1
-1
Submodule src/drivers/gps/devices updated: 8c09c5426d...1ff87868f6
+12
-1
@@ -783,9 +783,20 @@ GPS::run()
|
||||
|
||||
} else if (gps_ubx_mode == 4) {
|
||||
ubx_mode = GPSDriverUBX::UBXMode::MovingBaseUART1;
|
||||
|
||||
} else if (gps_ubx_mode == 5) { // rover with static base on Uart2
|
||||
ubx_mode = GPSDriverUBX::UBXMode::RoverWithStaticBaseUart2;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
handle = param_find("GPS_UBX_BAUD2");
|
||||
int32_t f9p_uart2_baudrate = 57600;
|
||||
|
||||
if (handle != PARAM_INVALID) {
|
||||
param_get(handle, &f9p_uart2_baudrate);
|
||||
}
|
||||
|
||||
int32_t gnssSystemsParam = static_cast<int32_t>(GPSHelper::GNSSSystemsMask::RECEIVER_DEFAULTS);
|
||||
|
||||
if (_instance == Instance::Main) {
|
||||
@@ -846,7 +857,7 @@ GPS::run()
|
||||
/* FALLTHROUGH */
|
||||
case gps_driver_mode_t::UBX:
|
||||
_helper = new GPSDriverUBX(_interface, &GPS::callback, this, &_report_gps_pos, _p_report_sat_info,
|
||||
gps_ubx_dynmodel, heading_offset, ubx_mode);
|
||||
gps_ubx_dynmodel, heading_offset, f9p_uart2_baudrate, ubx_mode);
|
||||
set_device_type(DRV_GPS_DEVTYPE_UBX);
|
||||
break;
|
||||
#ifndef CONSTRAINED_FLASH
|
||||
|
||||
@@ -87,6 +87,7 @@ PARAM_DEFINE_INT32(GPS_SAT_INFO, 0);
|
||||
* Select the u-blox configuration setup. Most setups will use the default, including RTK and
|
||||
* dual GPS without heading.
|
||||
*
|
||||
* If rover has RTCM corrections from a static base (or other static correction source) coming in on UART2, then select Mode 5.
|
||||
* The Heading mode requires 2 F9P devices to be attached. The main GPS will act as rover and output
|
||||
* heading information, whereas the secondary will act as moving base.
|
||||
* Modes 1 and 2 require each F9P UART1 to be connected to the Autopilot. In addition, UART2 on the
|
||||
@@ -101,6 +102,7 @@ PARAM_DEFINE_INT32(GPS_SAT_INFO, 0);
|
||||
* @value 2 Moving Base (UART1 Connected To Autopilot, UART2 Connected To Rover)
|
||||
* @value 3 Heading (Rover With Moving Base UART1 Connected to Autopilot Or Can Node At 921600)
|
||||
* @value 4 Moving Base (Moving Base UART1 Connected to Autopilot Or Can Node At 921600)
|
||||
* @value 5 Rover with Static Base on UART2 (similar to Default, except coming in on UART2)
|
||||
*
|
||||
* @reboot_required true
|
||||
* @group GPS
|
||||
@@ -108,6 +110,22 @@ PARAM_DEFINE_INT32(GPS_SAT_INFO, 0);
|
||||
PARAM_DEFINE_INT32(GPS_UBX_MODE, 0);
|
||||
|
||||
|
||||
/**
|
||||
* u-blox F9P UART2 Baudrate
|
||||
*
|
||||
* Select a baudrate for the F9P's UART2 port.
|
||||
* In GPS_UBX_MODE 1, 2, and 3, the F9P's UART2 port is configured to send/receive RTCM corrections.
|
||||
* Set this to 57600 if you want to attach a telemetry radio on UART2.
|
||||
*
|
||||
* @min 0
|
||||
* @unit B/s
|
||||
*
|
||||
* @reboot_required true
|
||||
* @group GPS
|
||||
*/
|
||||
PARAM_DEFINE_INT32(GPS_UBX_BAUD2, 230400);
|
||||
|
||||
|
||||
/**
|
||||
* Heading/Yaw offset for dual antenna GPS
|
||||
*
|
||||
|
||||
@@ -88,14 +88,13 @@ void EstimatorChecks::checkAndReport(const Context &context, Report &reporter)
|
||||
}
|
||||
|
||||
if (!missing_data) {
|
||||
estimator_status_s estimator_status;
|
||||
estimator_status_flags_s estimator_status_flags;
|
||||
|
||||
if (_estimator_status_sub.copy(&estimator_status)) {
|
||||
pre_flt_fail_innov_heading = estimator_status.pre_flt_fail_innov_heading;
|
||||
pre_flt_fail_innov_vel_horiz = estimator_status.pre_flt_fail_innov_vel_horiz;
|
||||
|
||||
checkEstimatorStatus(context, reporter, estimator_status, required_groups);
|
||||
checkEstimatorStatusFlags(context, reporter, estimator_status, lpos);
|
||||
if (_estimator_status_flags_sub.copy(&estimator_status_flags)) {
|
||||
pre_flt_fail_innov_heading = estimator_status_flags.pre_flt_fail_innov_heading;
|
||||
pre_flt_fail_innov_vel_horiz = estimator_status_flags.pre_flt_fail_innov_vel_horiz;
|
||||
checkEstimatorStatusFlags(context, reporter, estimator_status_flags, required_groups);
|
||||
checkEstimatorStatus(context, reporter, lpos, required_groups);
|
||||
|
||||
} else {
|
||||
missing_data = true;
|
||||
@@ -129,325 +128,323 @@ void EstimatorChecks::checkAndReport(const Context &context, Report &reporter)
|
||||
}
|
||||
|
||||
void EstimatorChecks::checkEstimatorStatus(const Context &context, Report &reporter,
|
||||
const estimator_status_s &estimator_status, NavModes required_groups)
|
||||
const vehicle_local_position_s &lpos, NavModes required_groups)
|
||||
{
|
||||
if (estimator_status.pre_flt_fail_innov_heading) {
|
||||
/* EVENT
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_heading_not_stable"),
|
||||
events::Log::Error, "Heading estimate not stable");
|
||||
estimator_status_s estimator_status;
|
||||
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: heading estimate not stable");
|
||||
}
|
||||
if (_estimator_status_sub.copy(&estimator_status)) {
|
||||
|
||||
} else if (estimator_status.pre_flt_fail_innov_vel_horiz) {
|
||||
/* EVENT
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_hor_vel_not_stable"),
|
||||
events::Log::Error, "Horizontal velocity estimate not stable");
|
||||
// check vertical position innovation test ratio
|
||||
if (estimator_status.hgt_test_ratio > _param_com_arm_ekf_hgt.get()) {
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* Test ratio: {1:.3}, limit: {2:.3}.
|
||||
*
|
||||
* This check can be configured via <param>COM_ARM_EKF_HGT</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure<float, float>(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_hgt_est_err"),
|
||||
events::Log::Error, "Height estimate error", estimator_status.hgt_test_ratio, _param_com_arm_ekf_hgt.get());
|
||||
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: horizontal velocity estimate not stable");
|
||||
}
|
||||
|
||||
} else if (estimator_status.pre_flt_fail_innov_vel_vert) {
|
||||
/* EVENT
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_vert_vel_not_stable"),
|
||||
events::Log::Error, "Vertical velocity estimate not stable");
|
||||
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: vertical velocity estimate not stable");
|
||||
}
|
||||
|
||||
} else if (estimator_status.pre_flt_fail_innov_height) {
|
||||
/* EVENT
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_hgt_not_stable"),
|
||||
events::Log::Error, "Height estimate not stable");
|
||||
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: height estimate not stable");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((_param_com_arm_mag_str.get() >= 1) && estimator_status.pre_flt_fail_mag_field_disturbed) {
|
||||
NavModes required_groups_mag = required_groups;
|
||||
|
||||
if (_param_com_arm_mag_str.get() != 1) {
|
||||
required_groups_mag = NavModes::None; // optional
|
||||
}
|
||||
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>COM_ARM_MAG_STR</param> and <param>EKF2_MAG_CHECK</param> parameters.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_mag, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_mag_interference"),
|
||||
events::Log::Warning, "Strong magnetic interference detected");
|
||||
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: Strong magnetic interference detected");
|
||||
}
|
||||
}
|
||||
|
||||
// check vertical position innovation test ratio
|
||||
if (estimator_status.hgt_test_ratio > _param_com_arm_ekf_hgt.get()) {
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* Test ratio: {1:.3}, limit: {2:.3}.
|
||||
*
|
||||
* This check can be configured via <param>COM_ARM_EKF_HGT</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure<float, float>(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_hgt_est_err"),
|
||||
events::Log::Error, "Height estimate error", estimator_status.hgt_test_ratio, _param_com_arm_ekf_hgt.get());
|
||||
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: height estimate error");
|
||||
}
|
||||
}
|
||||
|
||||
// check velocity innovation test ratio
|
||||
if (estimator_status.vel_test_ratio > _param_com_arm_ekf_vel.get()) {
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* Test ratio: {1:.3}, limit: {2:.3}.
|
||||
*
|
||||
* This check can be configured via <param>COM_ARM_EKF_VEL</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure<float, float>(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_vel_est_err"),
|
||||
events::Log::Error, "Velocity estimate error", estimator_status.vel_test_ratio, _param_com_arm_ekf_vel.get());
|
||||
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: velocity estimate error");
|
||||
}
|
||||
}
|
||||
|
||||
// check horizontal position innovation test ratio
|
||||
if (estimator_status.pos_test_ratio > _param_com_arm_ekf_pos.get()) {
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* Test ratio: {1:.3}, limit: {2:.3}.
|
||||
*
|
||||
* This check can be configured via <param>COM_ARM_EKF_POS</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure<float, float>(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_pos_est_err"),
|
||||
events::Log::Error, "Position estimate error", estimator_status.pos_test_ratio, _param_com_arm_ekf_pos.get());
|
||||
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: position estimate error");
|
||||
}
|
||||
}
|
||||
|
||||
// check magnetometer innovation test ratio
|
||||
if (estimator_status.mag_test_ratio > _param_com_arm_ekf_yaw.get()) {
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* Test ratio: {1:.3}, limit: {2:.3}.
|
||||
*
|
||||
* This check can be configured via <param>COM_ARM_EKF_YAW</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure<float, float>(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_yaw_est_err"),
|
||||
events::Log::Error, "Yaw estimate error", estimator_status.mag_test_ratio, _param_com_arm_ekf_yaw.get());
|
||||
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: Yaw estimate error");
|
||||
}
|
||||
}
|
||||
|
||||
// If GPS aiding is required, declare fault condition if the required GPS quality checks are failing
|
||||
if (_param_sys_has_gps.get()) {
|
||||
const bool ekf_gps_fusion = estimator_status.control_mode_flags & (1 << estimator_status_s::CS_GPS);
|
||||
const bool ekf_gps_check_fail = estimator_status.gps_check_fail_flags > 0;
|
||||
|
||||
if (ekf_gps_fusion) {
|
||||
reporter.setIsPresent(health_component_t::gps); // should be based on the sensor data directly
|
||||
}
|
||||
|
||||
if (ekf_gps_check_fail) {
|
||||
NavModes required_groups_gps = required_groups;
|
||||
events::Log log_level = events::Log::Error;
|
||||
|
||||
if (_param_com_arm_wo_gps.get()) {
|
||||
required_groups_gps = NavModes::None; // optional
|
||||
log_level = events::Log::Warning;
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: height estimate error");
|
||||
}
|
||||
}
|
||||
|
||||
// Only report the first failure to avoid spamming
|
||||
const char *message = nullptr;
|
||||
// check velocity innovation test ratio
|
||||
if (estimator_status.vel_test_ratio > _param_com_arm_ekf_vel.get()) {
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* Test ratio: {1:.3}, limit: {2:.3}.
|
||||
*
|
||||
* This check can be configured via <param>COM_ARM_EKF_VEL</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure<float, float>(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_vel_est_err"),
|
||||
events::Log::Error, "Velocity estimate error", estimator_status.vel_test_ratio, _param_com_arm_ekf_vel.get());
|
||||
|
||||
if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_GPS_FIX)) {
|
||||
message = "Preflight%s: GPS fix too low";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_fix_too_low"),
|
||||
log_level, "GPS fix too low");
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: velocity estimate error");
|
||||
}
|
||||
}
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MIN_SAT_COUNT)) {
|
||||
message = "Preflight%s: not enough GPS Satellites";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_num_sats_too_low"),
|
||||
log_level, "Not enough GPS Satellites");
|
||||
// check horizontal position innovation test ratio
|
||||
if (estimator_status.pos_test_ratio > _param_com_arm_ekf_pos.get()) {
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* Test ratio: {1:.3}, limit: {2:.3}.
|
||||
*
|
||||
* This check can be configured via <param>COM_ARM_EKF_POS</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure<float, float>(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_pos_est_err"),
|
||||
events::Log::Error, "Position estimate error", estimator_status.pos_test_ratio, _param_com_arm_ekf_pos.get());
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_PDOP)) {
|
||||
message = "Preflight%s: GPS PDOP too high";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_pdop_too_high"),
|
||||
log_level, "GPS PDOP too high");
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: position estimate error");
|
||||
}
|
||||
}
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_HORZ_ERR)) {
|
||||
message = "Preflight%s: GPS Horizontal Pos Error too high";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_hor_pos_err_too_high"),
|
||||
log_level, "GPS Horizontal Position Error too high");
|
||||
// check magnetometer innovation test ratio
|
||||
if (estimator_status.mag_test_ratio > _param_com_arm_ekf_yaw.get()) {
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* Test ratio: {1:.3}, limit: {2:.3}.
|
||||
*
|
||||
* This check can be configured via <param>COM_ARM_EKF_YAW</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure<float, float>(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_yaw_est_err"),
|
||||
events::Log::Error, "Yaw estimate error", estimator_status.mag_test_ratio, _param_com_arm_ekf_yaw.get());
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_VERT_ERR)) {
|
||||
message = "Preflight%s: GPS Vertical Pos Error too high";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_vert_pos_err_too_high"),
|
||||
log_level, "GPS Vertical Position Error too high");
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: Yaw estimate error");
|
||||
}
|
||||
}
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_SPD_ERR)) {
|
||||
message = "Preflight%s: GPS Speed Accuracy too low";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_speed_acc_too_low"),
|
||||
log_level, "GPS Speed Accuracy too low");
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_HORZ_DRIFT)) {
|
||||
message = "Preflight%s: GPS Horizontal Pos Drift too high";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_hor_pos_drift_too_high"),
|
||||
log_level, "GPS Horizontal Position Drift too high");
|
||||
/* Check estimator status for signs of bad yaw induced post takeoff navigation failure
|
||||
* for a short time interval after takeoff.
|
||||
* Most of the time, the drone can recover from a bad initial yaw using GPS-inertial
|
||||
* heading estimation (yaw emergency estimator) or GPS heading (fixed wings only), but
|
||||
* if this does not fix the issue we need to stop using a position controlled
|
||||
* mode to prevent flyaway crashes.
|
||||
*/
|
||||
if (context.status().vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING) {
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_VERT_DRIFT)) {
|
||||
message = "Preflight%s: GPS Vertical Pos Drift too high";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_vert_pos_drift_too_high"),
|
||||
log_level, "GPS Vertical Position Drift too high");
|
||||
const hrt_abstime now = hrt_absolute_time();
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_HORZ_SPD_ERR)) {
|
||||
message = "Preflight%s: GPS Hor Speed Drift too high";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_hor_speed_drift_too_high"),
|
||||
log_level, "GPS Horizontal Speed Drift too high");
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_VERT_SPD_ERR)) {
|
||||
message = "Preflight%s: GPS Vert Speed Drift too high";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_vert_speed_drift_too_high"),
|
||||
log_level, "GPS Vertical Speed Drift too high");
|
||||
if (!context.isArmed()) {
|
||||
_nav_test_failed = false;
|
||||
_nav_test_passed = false;
|
||||
|
||||
} else {
|
||||
if (!ekf_gps_fusion) {
|
||||
// Likely cause unknown
|
||||
message = "Preflight%s: Estimator not using GPS";
|
||||
/* EVENT
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_not_fusing"),
|
||||
log_level, "Estimator not using GPS");
|
||||
if (!_nav_test_passed) {
|
||||
// Both test ratios need to pass/fail together to change the nav test status
|
||||
const bool innovation_pass = (estimator_status.vel_test_ratio < 1.f) && (estimator_status.pos_test_ratio < 1.f)
|
||||
&& (estimator_status.vel_test_ratio > FLT_EPSILON) && (estimator_status.pos_test_ratio > FLT_EPSILON);
|
||||
|
||||
} else {
|
||||
// if we land here there was a new flag added and the code not updated. Show a generic message.
|
||||
message = "Preflight%s: Poor GPS Quality";
|
||||
/* EVENT
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_generic"),
|
||||
log_level, "Poor GPS Quality");
|
||||
}
|
||||
}
|
||||
const bool innovation_fail = (estimator_status.vel_test_ratio >= 1.f) && (estimator_status.pos_test_ratio >= 1.f);
|
||||
|
||||
if (message && reporter.mavlink_log_pub()) {
|
||||
if (!_param_com_arm_wo_gps.get()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), message, " Fail");
|
||||
if (innovation_pass) {
|
||||
_time_last_innov_pass = now;
|
||||
|
||||
} else {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), message, "");
|
||||
// if nav status is unconfirmed, confirm yaw angle as passed after 30 seconds or achieving 5 m/s of speed
|
||||
const bool sufficient_time = context.status().takeoff_time != 0
|
||||
&& now - context.status().takeoff_time > 30_s;
|
||||
const bool sufficient_speed = matrix::Vector2f(lpos.vx, lpos.vy).longerThan(5.f);
|
||||
|
||||
// Even if the test already failed, allow it to pass if it did not fail during the last 10 seconds
|
||||
if (now - _time_last_innov_fail > 10_s && (sufficient_time || sufficient_speed)) {
|
||||
_nav_test_passed = true;
|
||||
_nav_test_failed = false;
|
||||
}
|
||||
|
||||
} else if (innovation_fail) {
|
||||
_time_last_innov_fail = now;
|
||||
|
||||
if (now - _time_last_innov_pass > 2_s) {
|
||||
// if the innovation test has failed continuously, declare the nav as failed
|
||||
_nav_test_failed = true;
|
||||
/* EVENT
|
||||
* @description
|
||||
* Land and recalibrate the sensors.
|
||||
*/
|
||||
reporter.armingCheckFailure(NavModes::All, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_nav_failure"),
|
||||
events::Log::Emergency, "Navigation failure");
|
||||
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Navigation failure! Land and recalibrate sensors\t");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If GPS aiding is required, declare fault condition if the required GPS quality checks are failing
|
||||
if (_param_sys_has_gps.get()) {
|
||||
const bool ekf_gps_fusion = estimator_status.control_mode_flags & (1 << estimator_status_s::CS_GPS);
|
||||
const bool ekf_gps_check_fail = estimator_status.gps_check_fail_flags > 0;
|
||||
|
||||
if (ekf_gps_fusion) {
|
||||
reporter.setIsPresent(health_component_t::gps); // should be based on the sensor data directly
|
||||
}
|
||||
|
||||
if (ekf_gps_check_fail) {
|
||||
NavModes required_groups_gps = required_groups;
|
||||
events::Log log_level = events::Log::Error;
|
||||
|
||||
if (_param_com_arm_wo_gps.get()) {
|
||||
required_groups_gps = NavModes::None; // optional
|
||||
log_level = events::Log::Warning;
|
||||
}
|
||||
|
||||
// Only report the first failure to avoid spamming
|
||||
const char *message = nullptr;
|
||||
|
||||
if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_GPS_FIX)) {
|
||||
message = "Preflight%s: GPS fix too low";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_fix_too_low"),
|
||||
log_level, "GPS fix too low");
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MIN_SAT_COUNT)) {
|
||||
message = "Preflight%s: not enough GPS Satellites";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_num_sats_too_low"),
|
||||
log_level, "Not enough GPS Satellites");
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_PDOP)) {
|
||||
message = "Preflight%s: GPS PDOP too high";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_pdop_too_high"),
|
||||
log_level, "GPS PDOP too high");
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_HORZ_ERR)) {
|
||||
message = "Preflight%s: GPS Horizontal Pos Error too high";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_hor_pos_err_too_high"),
|
||||
log_level, "GPS Horizontal Position Error too high");
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_VERT_ERR)) {
|
||||
message = "Preflight%s: GPS Vertical Pos Error too high";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_vert_pos_err_too_high"),
|
||||
log_level, "GPS Vertical Position Error too high");
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_SPD_ERR)) {
|
||||
message = "Preflight%s: GPS Speed Accuracy too low";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_speed_acc_too_low"),
|
||||
log_level, "GPS Speed Accuracy too low");
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_HORZ_DRIFT)) {
|
||||
message = "Preflight%s: GPS Horizontal Pos Drift too high";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_hor_pos_drift_too_high"),
|
||||
log_level, "GPS Horizontal Position Drift too high");
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_VERT_DRIFT)) {
|
||||
message = "Preflight%s: GPS Vertical Pos Drift too high";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_vert_pos_drift_too_high"),
|
||||
log_level, "GPS Vertical Position Drift too high");
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_HORZ_SPD_ERR)) {
|
||||
message = "Preflight%s: GPS Hor Speed Drift too high";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_hor_speed_drift_too_high"),
|
||||
log_level, "GPS Horizontal Speed Drift too high");
|
||||
|
||||
} else if (estimator_status.gps_check_fail_flags & (1 << estimator_status_s::GPS_CHECK_FAIL_MAX_VERT_SPD_ERR)) {
|
||||
message = "Preflight%s: GPS Vert Speed Drift too high";
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>EKF2_GPS_CHECK</param> parameter.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_vert_speed_drift_too_high"),
|
||||
log_level, "GPS Vertical Speed Drift too high");
|
||||
|
||||
} else {
|
||||
if (!ekf_gps_fusion) {
|
||||
// Likely cause unknown
|
||||
message = "Preflight%s: Estimator not using GPS";
|
||||
/* EVENT
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_not_fusing"),
|
||||
log_level, "Estimator not using GPS");
|
||||
|
||||
} else {
|
||||
// if we land here there was a new flag added and the code not updated. Show a generic message.
|
||||
message = "Preflight%s: Poor GPS Quality";
|
||||
/* EVENT
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_gps, health_component_t::gps,
|
||||
events::ID("check_estimator_gps_generic"),
|
||||
log_level, "Poor GPS Quality");
|
||||
}
|
||||
}
|
||||
|
||||
if (message && reporter.mavlink_log_pub()) {
|
||||
if (!_param_com_arm_wo_gps.get()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), message, " Fail");
|
||||
|
||||
} else {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), message, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void EstimatorChecks::checkSensorBias(const Context &context, Report &reporter, NavModes required_groups)
|
||||
@@ -528,112 +525,113 @@ void EstimatorChecks::checkSensorBias(const Context &context, Report &reporter,
|
||||
}
|
||||
|
||||
void EstimatorChecks::checkEstimatorStatusFlags(const Context &context, Report &reporter,
|
||||
const estimator_status_s &estimator_status, const vehicle_local_position_s &lpos)
|
||||
const estimator_status_flags_s &estimator_status_flags, NavModes required_groups)
|
||||
{
|
||||
estimator_status_flags_s estimator_status_flags;
|
||||
bool dead_reckoning = estimator_status_flags.cs_wind_dead_reckoning
|
||||
|| estimator_status_flags.cs_inertial_dead_reckoning;
|
||||
|
||||
if (_estimator_status_flags_sub.copy(&estimator_status_flags)) {
|
||||
if (!dead_reckoning) {
|
||||
// position requirements (update if not dead reckoning)
|
||||
bool gps = estimator_status_flags.cs_gps;
|
||||
bool optical_flow = estimator_status_flags.cs_opt_flow;
|
||||
bool vision_position = estimator_status_flags.cs_ev_pos;
|
||||
|
||||
bool dead_reckoning = estimator_status_flags.cs_wind_dead_reckoning
|
||||
|| estimator_status_flags.cs_inertial_dead_reckoning;
|
||||
_position_reliant_on_optical_flow = !gps && optical_flow && !vision_position;
|
||||
}
|
||||
|
||||
if (!dead_reckoning) {
|
||||
// position requirements (update if not dead reckoning)
|
||||
bool gps = estimator_status_flags.cs_gps;
|
||||
bool optical_flow = estimator_status_flags.cs_opt_flow;
|
||||
bool vision_position = estimator_status_flags.cs_ev_pos;
|
||||
// Check for a magnetomer fault and notify the user
|
||||
if (estimator_status_flags.cs_mag_fault) {
|
||||
/* EVENT
|
||||
* @description
|
||||
* Land and calibrate the compass.
|
||||
*/
|
||||
reporter.armingCheckFailure(NavModes::All, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_mag_fault"),
|
||||
events::Log::Critical, "Stopping compass use");
|
||||
|
||||
_position_reliant_on_optical_flow = !gps && optical_flow && !vision_position;
|
||||
}
|
||||
|
||||
// Check for a magnetomer fault and notify the user
|
||||
if (estimator_status_flags.cs_mag_fault) {
|
||||
/* EVENT
|
||||
* @description
|
||||
* Land and calibrate the compass.
|
||||
*/
|
||||
reporter.armingCheckFailure(NavModes::All, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_mag_fault"),
|
||||
events::Log::Critical, "Stopping compass use");
|
||||
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Compass needs calibration - Land now!\t");
|
||||
}
|
||||
}
|
||||
|
||||
if (estimator_status_flags.cs_gps_yaw_fault) {
|
||||
/* EVENT
|
||||
* @description
|
||||
* Land now
|
||||
*/
|
||||
reporter.armingCheckFailure(NavModes::All, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_gnss_fault"),
|
||||
events::Log::Critical, "GNSS heading not reliable");
|
||||
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "GNSS heading not reliable - Land now!\t");
|
||||
}
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Compass needs calibration - Land now!\t");
|
||||
}
|
||||
}
|
||||
|
||||
const hrt_abstime now = hrt_absolute_time();
|
||||
if (estimator_status_flags.cs_gps_yaw_fault) {
|
||||
/* EVENT
|
||||
* @description
|
||||
* Land now
|
||||
*/
|
||||
reporter.armingCheckFailure(NavModes::All, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_gnss_fault"),
|
||||
events::Log::Critical, "GNSS heading not reliable");
|
||||
|
||||
/* Check estimator status for signs of bad yaw induced post takeoff navigation failure
|
||||
* for a short time interval after takeoff.
|
||||
* Most of the time, the drone can recover from a bad initial yaw using GPS-inertial
|
||||
* heading estimation (yaw emergency estimator) or GPS heading (fixed wings only), but
|
||||
* if this does not fix the issue we need to stop using a position controlled
|
||||
* mode to prevent flyaway crashes.
|
||||
*/
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "GNSS heading not reliable - Land now!\t");
|
||||
}
|
||||
}
|
||||
|
||||
if (context.status().vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING) {
|
||||
if ((_param_com_arm_mag_str.get() >= 1) && estimator_status_flags.cs_mag_field_disturbed) {
|
||||
NavModes required_groups_mag = required_groups;
|
||||
|
||||
if (!context.isArmed()) {
|
||||
_nav_test_failed = false;
|
||||
_nav_test_passed = false;
|
||||
if (_param_com_arm_mag_str.get() != 1) {
|
||||
required_groups_mag = NavModes::None; // optional
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!_nav_test_passed) {
|
||||
// Both test ratios need to pass/fail together to change the nav test status
|
||||
const bool innovation_pass = (estimator_status.vel_test_ratio < 1.f) && (estimator_status.pos_test_ratio < 1.f)
|
||||
&& (estimator_status.vel_test_ratio > FLT_EPSILON) && (estimator_status.pos_test_ratio > FLT_EPSILON);
|
||||
/* EVENT
|
||||
* @description
|
||||
* <profile name="dev">
|
||||
* This check can be configured via <param>COM_ARM_MAG_STR</param> and <param>EKF2_MAG_CHECK</param> parameters.
|
||||
* </profile>
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups_mag, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_mag_interference"),
|
||||
events::Log::Warning, "Strong magnetic interference detected");
|
||||
|
||||
const bool innovation_fail = (estimator_status.vel_test_ratio >= 1.f) && (estimator_status.pos_test_ratio >= 1.f);
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: Strong magnetic interference detected");
|
||||
}
|
||||
}
|
||||
|
||||
if (innovation_pass) {
|
||||
_time_last_innov_pass = now;
|
||||
if (estimator_status_flags.pre_flt_fail_innov_heading) {
|
||||
/* EVENT
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_heading_not_stable"),
|
||||
events::Log::Error, "Heading estimate not stable");
|
||||
|
||||
// if nav status is unconfirmed, confirm yaw angle as passed after 30 seconds or achieving 5 m/s of speed
|
||||
const bool sufficient_time = context.status().takeoff_time != 0
|
||||
&& now - context.status().takeoff_time > 30_s;
|
||||
const bool sufficient_speed = matrix::Vector2f(lpos.vx, lpos.vy).longerThan(5.f);
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: heading estimate not stable");
|
||||
}
|
||||
|
||||
// Even if the test already failed, allow it to pass if it did not fail during the last 10 seconds
|
||||
if (now - _time_last_innov_fail > 10_s && (sufficient_time || sufficient_speed)) {
|
||||
_nav_test_passed = true;
|
||||
_nav_test_failed = false;
|
||||
}
|
||||
} else if (estimator_status_flags.pre_flt_fail_innov_vel_horiz) {
|
||||
/* EVENT
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_hor_vel_not_stable"),
|
||||
events::Log::Error, "Horizontal velocity estimate not stable");
|
||||
|
||||
} else if (innovation_fail) {
|
||||
_time_last_innov_fail = now;
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: horizontal velocity estimate not stable");
|
||||
}
|
||||
|
||||
if (now - _time_last_innov_pass > 2_s) {
|
||||
// if the innovation test has failed continuously, declare the nav as failed
|
||||
_nav_test_failed = true;
|
||||
/* EVENT
|
||||
* @description
|
||||
* Land and recalibrate the sensors.
|
||||
*/
|
||||
reporter.armingCheckFailure(NavModes::All, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_nav_failure"),
|
||||
events::Log::Emergency, "Navigation failure");
|
||||
} else if (estimator_status_flags.pre_flt_fail_innov_vel_vert) {
|
||||
/* EVENT
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_vert_vel_not_stable"),
|
||||
events::Log::Error, "Vertical velocity estimate not stable");
|
||||
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Navigation failure! Land and recalibrate sensors\t");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: vertical velocity estimate not stable");
|
||||
}
|
||||
|
||||
} else if (estimator_status_flags.pre_flt_fail_innov_height) {
|
||||
/* EVENT
|
||||
*/
|
||||
reporter.armingCheckFailure(required_groups, health_component_t::local_position_estimate,
|
||||
events::ID("check_estimator_hgt_not_stable"),
|
||||
events::Log::Error, "Height estimate not stable");
|
||||
|
||||
if (reporter.mavlink_log_pub()) {
|
||||
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: height estimate not stable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,11 +59,11 @@ public:
|
||||
void checkAndReport(const Context &context, Report &reporter) override;
|
||||
|
||||
private:
|
||||
void checkEstimatorStatus(const Context &context, Report &reporter, const estimator_status_s &estimator_status,
|
||||
void checkEstimatorStatus(const Context &context, Report &reporter, const vehicle_local_position_s &lpos,
|
||||
NavModes required_groups);
|
||||
void checkSensorBias(const Context &context, Report &reporter, NavModes required_groups);
|
||||
void checkEstimatorStatusFlags(const Context &context, Report &reporter, const estimator_status_s &estimator_status,
|
||||
const vehicle_local_position_s &lpos);
|
||||
void checkEstimatorStatusFlags(const Context &context, Report &reporter,
|
||||
const estimator_status_flags_s &estimator_status_flags, NavModes required_groups);
|
||||
|
||||
void checkGps(const Context &context, Report &reporter, const sensor_gps_s &vehicle_gps_position) const;
|
||||
void gpsNoLongerValid(const Context &context, Report &reporter) const;
|
||||
|
||||
@@ -1351,12 +1351,6 @@ void EKF2::PublishStatus(const hrt_abstime ×tamp)
|
||||
|
||||
status.time_slip = _last_time_slip_us * 1e-6f;
|
||||
|
||||
status.pre_flt_fail_innov_heading = _preflt_checker.hasHeadingFailed();
|
||||
status.pre_flt_fail_innov_vel_horiz = _preflt_checker.hasHorizVelFailed();
|
||||
status.pre_flt_fail_innov_vel_vert = _preflt_checker.hasVertVelFailed();
|
||||
status.pre_flt_fail_innov_height = _preflt_checker.hasHeightFailed();
|
||||
status.pre_flt_fail_mag_field_disturbed = _ekf.control_status_flags().mag_field_disturbed;
|
||||
|
||||
status.accel_device_id = _device_id_accel;
|
||||
status.baro_device_id = _device_id_baro;
|
||||
status.gyro_device_id = _device_id_gyro;
|
||||
@@ -1464,6 +1458,11 @@ void EKF2::PublishStatusFlags(const hrt_abstime ×tamp)
|
||||
status_flags.reject_optflow_x = _ekf.innov_check_fail_status_flags().reject_optflow_X;
|
||||
status_flags.reject_optflow_y = _ekf.innov_check_fail_status_flags().reject_optflow_Y;
|
||||
|
||||
status_flags.pre_flt_fail_innov_heading = _preflt_checker.hasHeadingFailed();
|
||||
status_flags.pre_flt_fail_innov_vel_horiz = _preflt_checker.hasHorizVelFailed();
|
||||
status_flags.pre_flt_fail_innov_vel_vert = _preflt_checker.hasVertVelFailed();
|
||||
status_flags.pre_flt_fail_innov_height = _preflt_checker.hasHeightFailed();
|
||||
|
||||
status_flags.timestamp = _replay_mode ? timestamp : hrt_absolute_time();
|
||||
_estimator_status_flags_pub.publish(status_flags);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user