mirror of https://github.com/ArduPilot/ardupilot
357 lines
14 KiB
C++
357 lines
14 KiB
C++
#include "AP_NavEKF2.h"
|
|
|
|
#include <AP_HAL/HAL.h>
|
|
#include <AP_Logger/AP_Logger.h>
|
|
|
|
void NavEKF2::Log_Write_NKF1(uint8_t _core, uint64_t time_us) const
|
|
{
|
|
// Write first EKF packet
|
|
Vector3f euler;
|
|
Vector2f posNE;
|
|
float posD;
|
|
Vector3f velNED;
|
|
Vector3f gyroBias;
|
|
float posDownDeriv;
|
|
Location originLLH;
|
|
getEulerAngles(_core,euler);
|
|
getVelNED(_core,velNED);
|
|
getPosNE(_core,posNE);
|
|
getPosD(_core,posD);
|
|
getGyroBias(_core,gyroBias);
|
|
posDownDeriv = getPosDownDerivative(_core);
|
|
if (!getOriginLLH(_core,originLLH)) {
|
|
originLLH.alt = 0;
|
|
}
|
|
const struct log_EKF1 pkt{
|
|
LOG_PACKET_HEADER_INIT(LOG_NKF1_MSG),
|
|
time_us : time_us,
|
|
core : _core,
|
|
roll : (int16_t)(100*degrees(euler.x)), // roll angle (centi-deg, displayed as deg due to format string)
|
|
pitch : (int16_t)(100*degrees(euler.y)), // pitch angle (centi-deg, displayed as deg due to format string)
|
|
yaw : (uint16_t)wrap_360_cd(100*degrees(euler.z)), // yaw angle (centi-deg, displayed as deg due to format string)
|
|
velN : (float)(velNED.x), // velocity North (m/s)
|
|
velE : (float)(velNED.y), // velocity East (m/s)
|
|
velD : (float)(velNED.z), // velocity Down (m/s)
|
|
posD_dot : (float)(posDownDeriv), // first derivative of down position
|
|
posN : (float)(posNE.x), // metres North
|
|
posE : (float)(posNE.y), // metres East
|
|
posD : (float)(posD), // metres Down
|
|
gyrX : (int16_t)(100*degrees(gyroBias.x)), // cd/sec, displayed as deg/sec due to format string
|
|
gyrY : (int16_t)(100*degrees(gyroBias.y)), // cd/sec, displayed as deg/sec due to format string
|
|
gyrZ : (int16_t)(100*degrees(gyroBias.z)), // cd/sec, displayed as deg/sec due to format string
|
|
originHgt : originLLH.alt // WGS-84 altitude of EKF origin in cm
|
|
};
|
|
AP::logger().WriteBlock(&pkt, sizeof(pkt));
|
|
}
|
|
|
|
void NavEKF2::Log_Write_NKF2(uint8_t _core, uint64_t time_us) const
|
|
{
|
|
// Write second EKF packet
|
|
float azbias = 0;
|
|
Vector3f wind;
|
|
Vector3f magNED;
|
|
Vector3f magXYZ;
|
|
Vector3f gyroScaleFactor;
|
|
uint8_t magIndex = getActiveMag(_core);
|
|
getAccelZBias(_core,azbias);
|
|
getWind(_core,wind);
|
|
getMagNED(_core,magNED);
|
|
getMagXYZ(_core,magXYZ);
|
|
getGyroScaleErrorPercentage(_core,gyroScaleFactor);
|
|
const struct log_NKF2 pkt2{
|
|
LOG_PACKET_HEADER_INIT(LOG_NKF2_MSG),
|
|
time_us : time_us,
|
|
core : _core,
|
|
AZbias : (int8_t)(100*azbias),
|
|
scaleX : (int16_t)(100*gyroScaleFactor.x),
|
|
scaleY : (int16_t)(100*gyroScaleFactor.y),
|
|
scaleZ : (int16_t)(100*gyroScaleFactor.z),
|
|
windN : (int16_t)(100*wind.x),
|
|
windE : (int16_t)(100*wind.y),
|
|
magN : (int16_t)(magNED.x),
|
|
magE : (int16_t)(magNED.y),
|
|
magD : (int16_t)(magNED.z),
|
|
magX : (int16_t)(magXYZ.x),
|
|
magY : (int16_t)(magXYZ.y),
|
|
magZ : (int16_t)(magXYZ.z),
|
|
index : (uint8_t)(magIndex)
|
|
};
|
|
AP::logger().WriteBlock(&pkt2, sizeof(pkt2));
|
|
}
|
|
|
|
void NavEKF2::Log_Write_NKF3(uint8_t _core, uint64_t time_us) const
|
|
{
|
|
// Write third EKF packet
|
|
Vector3f velInnov;
|
|
Vector3f posInnov;
|
|
Vector3f magInnov;
|
|
float tasInnov = 0;
|
|
float yawInnov = 0;
|
|
getInnovations(_core,velInnov, posInnov, magInnov, tasInnov, yawInnov);
|
|
const struct log_NKF3 pkt3{
|
|
LOG_PACKET_HEADER_INIT(LOG_NKF3_MSG),
|
|
time_us : time_us,
|
|
core : _core,
|
|
innovVN : (int16_t)(100*velInnov.x),
|
|
innovVE : (int16_t)(100*velInnov.y),
|
|
innovVD : (int16_t)(100*velInnov.z),
|
|
innovPN : (int16_t)(100*posInnov.x),
|
|
innovPE : (int16_t)(100*posInnov.y),
|
|
innovPD : (int16_t)(100*posInnov.z),
|
|
innovMX : (int16_t)(magInnov.x),
|
|
innovMY : (int16_t)(magInnov.y),
|
|
innovMZ : (int16_t)(magInnov.z),
|
|
innovYaw : (int16_t)(100*degrees(yawInnov)),
|
|
innovVT : (int16_t)(100*tasInnov),
|
|
rerr : 0, // TODO : Relative Error based Lane-Switching like EK3
|
|
errorScore : 0 // TODO : Relative Error based Lane-Switching like EK3
|
|
};
|
|
AP::logger().WriteBlock(&pkt3, sizeof(pkt3));
|
|
}
|
|
|
|
void NavEKF2::Log_Write_NKF4(uint8_t _core, uint64_t time_us) const
|
|
{
|
|
// Write fourth EKF packet
|
|
float velVar = 0;
|
|
float posVar = 0;
|
|
float hgtVar = 0;
|
|
Vector3f magVar;
|
|
float tasVar = 0;
|
|
Vector2f offset;
|
|
uint16_t faultStatus=0;
|
|
uint8_t timeoutStatus=0;
|
|
nav_filter_status solutionStatus {};
|
|
nav_gps_status gpsStatus {};
|
|
getVariances(_core,velVar, posVar, hgtVar, magVar, tasVar, offset);
|
|
float tempVar = fmaxf(fmaxf(magVar.x,magVar.y),magVar.z);
|
|
getFilterFaults(_core,faultStatus);
|
|
getFilterTimeouts(_core,timeoutStatus);
|
|
getFilterStatus(_core,solutionStatus);
|
|
getFilterGpsStatus(_core,gpsStatus);
|
|
float tiltError;
|
|
getTiltError(_core,tiltError);
|
|
int8_t primaryIndex = getPrimaryCoreIndex();
|
|
const struct log_NKF4 pkt4{
|
|
LOG_PACKET_HEADER_INIT(LOG_NKF4_MSG),
|
|
time_us : time_us,
|
|
core : _core,
|
|
sqrtvarV : (int16_t)(100*velVar),
|
|
sqrtvarP : (int16_t)(100*posVar),
|
|
sqrtvarH : (int16_t)(100*hgtVar),
|
|
sqrtvarM : (int16_t)(100*tempVar),
|
|
sqrtvarVT : (int16_t)(100*tasVar),
|
|
tiltErr : (float)tiltError,
|
|
offsetNorth : (int8_t)(offset.x),
|
|
offsetEast : (int8_t)(offset.y),
|
|
faults : (uint16_t)(faultStatus),
|
|
timeouts : (uint8_t)(timeoutStatus),
|
|
solution : (uint32_t)(solutionStatus.value),
|
|
gps : (uint16_t)(gpsStatus.value),
|
|
primary : (int8_t)primaryIndex
|
|
};
|
|
AP::logger().WriteBlock(&pkt4, sizeof(pkt4));
|
|
}
|
|
|
|
void NavEKF2::Log_Write_NKF5(uint64_t time_us) const
|
|
{
|
|
// Write fifth EKF packet - take data from the primary instance
|
|
float normInnov=0; // normalised innovation variance ratio for optical flow observations fused by the main nav filter
|
|
float gndOffset=0; // estimated vertical position of the terrain relative to the nav filter zero datum
|
|
float flowInnovX=0, flowInnovY=0; // optical flow LOS rate vector innovations from the main nav filter
|
|
float auxFlowInnov=0; // optical flow LOS rate innovation from terrain offset estimator
|
|
float HAGL=0; // height above ground level
|
|
float rngInnov=0; // range finder innovations
|
|
float range=0; // measured range
|
|
float gndOffsetErr=0; // filter ground offset state error
|
|
Vector3f predictorErrors; // output predictor angle, velocity and position tracking error
|
|
getFlowDebug(-1,normInnov, gndOffset, flowInnovX, flowInnovY, auxFlowInnov, HAGL, rngInnov, range, gndOffsetErr);
|
|
getOutputTrackingError(-1,predictorErrors);
|
|
const struct log_NKF5 pkt5{
|
|
LOG_PACKET_HEADER_INIT(LOG_NKF5_MSG),
|
|
time_us : time_us,
|
|
normInnov : (uint8_t)(MIN(100*normInnov,255)),
|
|
FIX : (int16_t)(1000*flowInnovX),
|
|
FIY : (int16_t)(1000*flowInnovY),
|
|
AFI : (int16_t)(1000*auxFlowInnov),
|
|
HAGL : (int16_t)(100*HAGL),
|
|
offset : (int16_t)(100*gndOffset),
|
|
RI : (int16_t)(100*rngInnov),
|
|
meaRng : (uint16_t)(100*range),
|
|
errHAGL : (uint16_t)(100*gndOffsetErr),
|
|
angErr : (float)predictorErrors.x,
|
|
velErr : (float)predictorErrors.y,
|
|
posErr : (float)predictorErrors.z
|
|
};
|
|
AP::logger().WriteBlock(&pkt5, sizeof(pkt5));
|
|
}
|
|
|
|
void NavEKF2::Log_Write_Quaternion(uint8_t _core, uint64_t time_us) const
|
|
{
|
|
// log quaternion
|
|
Quaternion quat;
|
|
getQuaternion(_core, quat);
|
|
const struct log_Quaternion pktq1{
|
|
LOG_PACKET_HEADER_INIT(LOG_NKQ_MSG),
|
|
time_us : time_us,
|
|
core : _core,
|
|
q1 : quat.q1,
|
|
q2 : quat.q2,
|
|
q3 : quat.q3,
|
|
q4 : quat.q4
|
|
};
|
|
AP::logger().WriteBlock(&pktq1, sizeof(pktq1));
|
|
}
|
|
|
|
void NavEKF2::Log_Write_Beacon(uint64_t time_us) const
|
|
{
|
|
if (AP::beacon() != nullptr) {
|
|
uint8_t ID;
|
|
float rng;
|
|
float innovVar;
|
|
float innov;
|
|
float testRatio;
|
|
Vector3f beaconPosNED;
|
|
float bcnPosOffsetHigh;
|
|
float bcnPosOffsetLow;
|
|
if (getRangeBeaconDebug(-1, ID, rng, innov, innovVar, testRatio, beaconPosNED, bcnPosOffsetHigh, bcnPosOffsetLow)) {
|
|
if (rng > 0.0f) {
|
|
struct log_RngBcnDebug pkt10 = {
|
|
LOG_PACKET_HEADER_INIT(LOG_NKF10_MSG),
|
|
time_us : time_us,
|
|
ID : (uint8_t)ID,
|
|
rng : (int16_t)(100*rng),
|
|
innov : (int16_t)(100*innov),
|
|
sqrtInnovVar : (uint16_t)(100*safe_sqrt(innovVar)),
|
|
testRatio : (uint16_t)(100*constrain_float(testRatio,0.0f,650.0f)),
|
|
beaconPosN : (int16_t)(100*beaconPosNED.x),
|
|
beaconPosE : (int16_t)(100*beaconPosNED.y),
|
|
beaconPosD : (int16_t)(100*beaconPosNED.z),
|
|
offsetHigh : (int16_t)(100*bcnPosOffsetHigh),
|
|
offsetLow : (int16_t)(100*bcnPosOffsetLow),
|
|
posN : 0,
|
|
posE : 0,
|
|
posD : 0
|
|
};
|
|
AP::logger().WriteBlock(&pkt10, sizeof(pkt10));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void NavEKF2::Log_Write()
|
|
{
|
|
// only log if enabled
|
|
if (activeCores() <= 0) {
|
|
return;
|
|
}
|
|
|
|
const uint64_t time_us = AP_HAL::micros64();
|
|
|
|
Log_Write_NKF5(time_us);
|
|
|
|
for (uint8_t i=0; i<activeCores(); i++) {
|
|
Log_Write_NKF1(i, time_us);
|
|
Log_Write_NKF2(i, time_us);
|
|
Log_Write_NKF3(i, time_us);
|
|
Log_Write_NKF4(i, time_us);
|
|
Log_Write_Quaternion(i, time_us);
|
|
Log_Write_GSF(i, time_us);
|
|
}
|
|
|
|
// write range beacon fusion debug packet if the range value is non-zero
|
|
Log_Write_Beacon(time_us);
|
|
|
|
// log EKF timing statistics every 5s
|
|
static uint32_t lastTimingLogTime_ms = 0;
|
|
if (AP_HAL::millis() - lastTimingLogTime_ms > 5000) {
|
|
lastTimingLogTime_ms = AP_HAL::millis();
|
|
struct ekf_timing timing;
|
|
for (uint8_t i=0; i<activeCores(); i++) {
|
|
getTimingStatistics(i, timing);
|
|
Log_EKF_Timing("NKT", i, time_us, timing);
|
|
}
|
|
}
|
|
}
|
|
|
|
void NavEKF2::Log_Write_GSF(uint8_t _core, uint64_t time_us) const
|
|
{
|
|
float yaw_composite;
|
|
float yaw_composite_variance;
|
|
float yaw[N_MODELS_EKFGSF];
|
|
float ivn[N_MODELS_EKFGSF];
|
|
float ive[N_MODELS_EKFGSF];
|
|
float wgt[N_MODELS_EKFGSF];
|
|
|
|
// @LoggerMessage: NKY0
|
|
// @Description: EKF2 Yaw Estimator States
|
|
// @Field: TimeUS: Time since system startup
|
|
// @Field: C: EKF2 core this data is for
|
|
// @Field: YC: GSF yaw estimate (rad)
|
|
// @Field: YCS: GSF yaw estimate 1-Sigma uncertainty (rad)
|
|
// @Field: Y0: Yaw estimate from individual EKF filter 0 (rad)
|
|
// @Field: Y1: Yaw estimate from individual EKF filter 1 (rad)
|
|
// @Field: Y2: Yaw estimate from individual EKF filter 2 (rad)
|
|
// @Field: Y3: Yaw estimate from individual EKF filter 3 (rad)
|
|
// @Field: Y4: Yaw estimate from individual EKF filter 4 (rad)
|
|
// @Field: W0: Weighting applied to yaw estimate from individual EKF filter 0
|
|
// @Field: W1: Weighting applied to yaw estimate from individual EKF filter 1
|
|
// @Field: W2: Weighting applied to yaw estimate from individual EKF filter 2
|
|
// @Field: W3: Weighting applied to yaw estimate from individual EKF filter 3
|
|
// @Field: W4: Weighting applied to yaw estimate from individual EKF filter 4
|
|
|
|
if (getDataEKFGSF(_core, yaw_composite, yaw_composite_variance, yaw, ivn, ive, wgt)) {
|
|
AP::logger().Write("NKY0",
|
|
"TimeUS,C,YC,YCS,Y0,Y1,Y2,Y3,Y4,W0,W1,W2,W3,W4",
|
|
"s#rrrrrrr-----",
|
|
"F-000000000000",
|
|
"QBffffffffffff",
|
|
time_us,
|
|
_core,
|
|
yaw_composite,
|
|
sqrtf(MAX(yaw_composite_variance, 0.0f)),
|
|
yaw[0],
|
|
yaw[1],
|
|
yaw[2],
|
|
yaw[3],
|
|
yaw[4],
|
|
wgt[0],
|
|
wgt[1],
|
|
wgt[2],
|
|
wgt[3],
|
|
wgt[4]);
|
|
|
|
// @LoggerMessage: NKY1
|
|
// @Description: EKF2 Yaw Estimator Innovations
|
|
// @Field: TimeUS: Time since system startup
|
|
// @Field: C: EKF2 core this data is for
|
|
// @Field: IVN0: North velocity innovation from individual EKF filter 0 (m/s)
|
|
// @Field: IVN1: North velocity innovation from individual EKF filter 1 (m/s)
|
|
// @Field: IVN2: North velocity innovation from individual EKF filter 2 (m/s)
|
|
// @Field: IVN3: North velocity innovation from individual EKF filter 3 (m/s)
|
|
// @Field: IVN4: North velocity innovation from individual EKF filter 4 (m/s)
|
|
// @Field: IVE0: East velocity innovation from individual EKF filter 0 (m/s)
|
|
// @Field: IVE1: East velocity innovation from individual EKF filter 1 (m/s)
|
|
// @Field: IVE2: East velocity innovation from individual EKF filter 2 (m/s)
|
|
// @Field: IVE3: East velocity innovation from individual EKF filter 3 (m/s)
|
|
// @Field: IVE4: East velocity innovation from individual EKF filter 4 (m/s)
|
|
|
|
AP::logger().Write("NKY1",
|
|
"TimeUS,C,IVN0,IVN1,IVN2,IVN3,IVN4,IVE0,IVE1,IVE2,IVE3,IVE4",
|
|
"s#nnnnnnnnnn",
|
|
"F-0000000000",
|
|
"QBffffffffff",
|
|
time_us,
|
|
_core,
|
|
ivn[0],
|
|
ivn[1],
|
|
ivn[2],
|
|
ivn[3],
|
|
ivn[4],
|
|
ive[0],
|
|
ive[1],
|
|
ive[2],
|
|
ive[3],
|
|
ive[4]);
|
|
}
|
|
}
|