Skip to content

Commit 837c4f2

Browse files
committed
Add XKF (third Kalman filter) analyzer
1 parent 69b11f1 commit 837c4f2

8 files changed

+211
-3
lines changed

LA_MsgHandler.cpp

+73-1
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ void LA_MsgHandler_ATT::xprocess(const uint8_t *msg) {
181181
}
182182

183183

184-
// TODO: if a third Kalman filter exists, factor this EKF1 and NKF1
184+
// TODO: factor with NKF1 and XKF1
185185
LA_MsgHandler_EKF1::LA_MsgHandler_EKF1(std::string name,
186186
const struct log_Format &f,
187187
Analyze *analyze,
@@ -508,6 +508,78 @@ void LA_MsgHandler_NKF1::xprocess(const uint8_t *msg) {
508508

509509
}
510510

511+
// FIXME: factor!
512+
LA_MsgHandler_XKF1::LA_MsgHandler_XKF1(std::string name,
513+
const struct log_Format &f,
514+
Analyze *analyze,
515+
AnalyzerVehicle::Base *&vehicle) :
516+
LA_MsgHandler(name, f, analyze, vehicle) {
517+
_analyze->add_data_source("ATTITUDE_ESTIMATE_XKF1", "XKF1.Roll");
518+
_analyze->add_data_source("ATTITUDE_ESTIMATE_XKF1", "XKF1.Pitch");
519+
_analyze->add_data_source("ATTITUDE_ESTIMATE_XKF1", "XKF1.Yaw");
520+
521+
_analyze->add_data_source("POSITION_ESTIMATE_XKF1", "XKF1.PN");
522+
_analyze->add_data_source("POSITION_ESTIMATE_XKF1", "XKF1.PE");
523+
524+
_analyze->add_data_source("ALTITUDE_ESTIMATE_XKF1", "XKF1.PD");
525+
526+
_analyze->add_data_source("VELOCITY_ESTIMATE_XKF1", "XKF1.VN");
527+
_analyze->add_data_source("VELOCITY_ESTIMATE_XKF1", "XKF1.VE");
528+
_analyze->add_data_source("VELOCITY_ESTIMATE_XKF1", "XKF1.VD");
529+
530+
}
531+
532+
void LA_MsgHandler_XKF1::xprocess(const uint8_t *msg) {
533+
int16_t Roll = require_field_int16_t(msg, "Roll");
534+
int16_t Pitch = require_field_int16_t(msg, "Pitch");
535+
float Yaw = require_field_float(msg, "Yaw");
536+
537+
_vehicle->attitude_estimate("XKF1")->set_roll(T(), Roll/(double)100.0f);
538+
_vehicle->attitude_estimate("XKF1")->set_pitch(T(), Pitch/(double)100.0f);
539+
_vehicle->attitude_estimate("XKF1")->set_yaw(T(), Yaw-180);
540+
541+
// these are all relative; need to work out an origin:
542+
if (_vehicle->origin_lat_T() != 0) {
543+
double posN = require_field_float(msg, "PN");
544+
double posE = require_field_float(msg, "PE");
545+
double origin_lat = _vehicle->origin_lat();
546+
double origin_lon = _vehicle->origin_lon();
547+
548+
double lat = 0;
549+
double lon = 0;
550+
gps_offset(origin_lat, origin_lon, posE, posN, lat, lon);
551+
// ::fprintf(stderr, "%f+%f / %f+%f = %f / %f\n",
552+
// origin_lat, posE, origin_lon, posN, lat, lon);
553+
554+
_vehicle->position_estimate("XKF1")->set_lat(T(), lat);
555+
_vehicle->position_estimate("XKF1")->set_lon(T(), lon);
556+
}
557+
if (_vehicle->origin_altitude_T() != 0) {
558+
double posD = require_field_float(msg, "PD");
559+
double origin_alt = _vehicle->origin_altitude();
560+
_vehicle->altitude_estimate("XKF1")->set_alt(T(), origin_alt - posD);
561+
}
562+
563+
{
564+
double vn = require_field_float(msg, "VN");
565+
double ve = require_field_float(msg, "VE");
566+
double vd = require_field_float(msg, "VD");
567+
568+
_vehicle->velocity_estimate("XKF1")->velocity().set_x(T(), vn);
569+
_vehicle->velocity_estimate("XKF1")->velocity().set_y(T(), ve);
570+
_vehicle->velocity_estimate("XKF1")->velocity().set_z(T(), vd);
571+
572+
if (int(_vehicle->require_param_with_defaults("AHRS_EKF_TYPE")) == 2) {
573+
// set XKF1 as canonical for velocity:
574+
// Sadly, NTUN isn't updated if we're not using the nav controller
575+
_vehicle->vel().set_x(T(), vn);
576+
_vehicle->vel().set_y(T(), ve);
577+
_vehicle->vel().set_z(T(), vd);
578+
}
579+
}
580+
581+
}
582+
511583
void LA_MsgHandler_PM::xprocess(const uint8_t *msg)
512584
{
513585
uint16_t nlon;

LA_MsgHandler.h

+33
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,39 @@ class LA_MsgHandler_NKF4 : public LA_MsgHandler {
336336
}
337337
};
338338

339+
class LA_MsgHandler_XKF1 : public LA_MsgHandler {
340+
public:
341+
LA_MsgHandler_XKF1(std::string name, const struct log_Format &f,
342+
Analyze *analyze, AnalyzerVehicle::Base *&vehicle);
343+
void xprocess(const uint8_t *msg) override;
344+
};
345+
346+
class LA_MsgHandler_XKF4 : public LA_MsgHandler {
347+
public:
348+
LA_MsgHandler_XKF4(std::string name, const struct log_Format &f, Analyze *analyze, AnalyzerVehicle::Base *&vehicle) :
349+
LA_MsgHandler(name, f, analyze, vehicle) {
350+
_analyze->add_data_source("XKF_FLAGS", "XKF4.SS");
351+
_analyze->add_data_source("XKF_VARIANCES_velocity_variance", "XKF4.SV");
352+
_analyze->add_data_source("XKF_VARIANCES_pos_horiz_variance", "XKF4.SP");
353+
_analyze->add_data_source("XKF_VARIANCES_pos_vert_variance", "XKF4.SH");
354+
_analyze->add_data_source("XKF_VARIANCES_pos_compass_variance", "XKF4.SM");
355+
_analyze->add_data_source("XKF_VARIANCES_terrain_alt_variance", "XKF4.SVT");
356+
};
357+
void xprocess(const uint8_t *msg) override {
358+
_vehicle->xkf_set_variance("velocity", require_field_uint16_t(msg, "SV") / (double)100.0f);
359+
_vehicle->xkf_set_variance("pos_horiz", require_field_uint16_t(msg, "SP") / (double)100.0f);
360+
_vehicle->xkf_set_variance("pos_vert", require_field_uint16_t(msg, "SH") / (double)100.0f);
361+
_vehicle->xkf_set_variance("compass", require_field_uint16_t(msg, "SM") / (double)100.0f);
362+
_vehicle->xkf_set_variance("terrain_alt", require_field_uint16_t(msg, "SVT") / (double)100.0f);
363+
364+
// FIXME: this will always be present
365+
uint16_t ss;
366+
if (field_value(msg, "SS", ss)) {
367+
_vehicle->xkf_set_flags(ss);
368+
}
369+
}
370+
};
371+
339372
class LA_MsgHandler_ORGN : public LA_MsgHandler {
340373
public:
341374
LA_MsgHandler_ORGN(std::string name, const struct log_Format &f, Analyze *analyze, AnalyzerVehicle::Base *&vehicle) :

analyze.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "analyzer/analyzer_ever_armed.h"
1717
#include "analyzer/analyzer_good_ekf.h"
1818
#include "analyzer/analyzer_good_nkf.h"
19+
#include "analyzer/analyzer_good_xkf.h"
1920
#include "analyzer/analyzer_gps_fix.h"
2021
#include "analyzer/analyzer_gyro_drift.h"
2122
#include "analyzer/analyzer_notcrashed.h"
@@ -133,6 +134,13 @@ void Analyze::instantiate_analyzers(INIReader *config)
133134
la_log(LOG_INFO, "Failed to create analyzer_good_nkf");
134135
}
135136

137+
Analyzer_Good_XKF *analyzer_good_xkf = new Analyzer_Good_XKF(vehicle,_data_sources);
138+
if (analyzer_good_xkf != NULL) {
139+
configure_analyzer(config, analyzer_good_xkf);
140+
} else {
141+
la_log(LOG_INFO, "Failed to create analyzer_good_xkf");
142+
}
143+
136144
Analyzer_GPS_Fix *analyzer_gps_fix = new Analyzer_GPS_Fix(vehicle,_data_sources);
137145
if (analyzer_gps_fix != NULL) {
138146
configure_analyzer(config, analyzer_gps_fix);

analyzer/analyzer_good_kf.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ void Analyzer_Good_KF::open_result_flags(uint16_t flags)
177177
_result_flags->set_reason(string_format("The %s status report indicates a problem with the EKF", shortname().c_str()));
178178
_result_flags->set_flags(this->flags());
179179

180-
_result_flags->add_evidence(string_format("flags=%d", flags));
180+
_result_flags->add_evidence(string_format("flags=%u", flags));
181181
// TODO: put the flags and the "bad" descrption into a structure
182182
_result_flags->increase_severity_score(10);
183183
if (!(flags & EKF_ATTITUDE)) {
@@ -220,6 +220,10 @@ void Analyzer_Good_KF::open_result_flags(uint16_t flags)
220220
_result_flags->increase_severity_score(1);
221221
_result_flags->add_evidence("Predicted horizontal position (absolute) bad");
222222
}
223+
if (flags & (1<<15)) {
224+
_result_flags->increase_severity_score(1);
225+
_result_flags->add_evidence("GPS is glitching");
226+
}
223227

224228
if (_vehicle->any_acc_clipping()) {
225229
_result_flags->add_evidence("Vehicle Accelerometers Clipping");

analyzer/analyzer_good_xkf.cpp

Whitespace-only changes.

analyzer/analyzer_good_xkf.h

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#ifndef ANALYZER_GOOD_XKF_H
2+
#define ANALYZER_GOOD_XKF_H
3+
4+
/*
5+
* analyzer_good_xkf
6+
*
7+
*/
8+
9+
#include "analyzer.h"
10+
#include "data_sources.h"
11+
#include "analyzer_good_kf.h"
12+
13+
class Analyzer_Good_XKF : public Analyzer_Good_KF {
14+
15+
public:
16+
17+
// borrow the constructor:
18+
using Analyzer_Good_KF::Analyzer_Good_KF;
19+
20+
const std::string name() const override { return "Good EKF3"; }
21+
const std::string description() const override {
22+
return "ArduPilot's third Extended Kalman Filter (EKF3) has many built-in checks to ensure that it is functioning correctly. This test will FAIL or WARN if EKF variances exceed the respective thresholds, or FAIL if the EKF status flags indicate errors.";
23+
}
24+
25+
const std::string shortname_lc() const override { return "xkf"; }
26+
const std::string shortname() const override { return "XKF"; }
27+
28+
uint64_t variance_T(std::string name) const override {
29+
return _vehicle->xkf_variance_T(name);
30+
}
31+
uint64_t flags_T() const override {
32+
return _vehicle->xkf_flags_T();
33+
}
34+
uint16_t flags() const override {
35+
return _vehicle->xkf_flags();
36+
}
37+
38+
std::map<const std::string, double> variances() {
39+
return _vehicle->xkf_variances();
40+
}
41+
42+
private:
43+
44+
};
45+
46+
#endif
47+
48+

analyzervehicle.h

+40-1
Original file line numberDiff line numberDiff line change
@@ -273,12 +273,18 @@ namespace AnalyzerVehicle {
273273
uint64_t _flags_T = 0;
274274
};
275275

276-
/// @brief State information for a base Extended Kalman Filter.
276+
/// @brief State information for a second-edition Extended Kalman Filter.
277277
class NKF : public EKF {
278278
public:
279279
private:
280280
};
281281

282+
/// @brief State information for a third-edition Extended Kalman Filter.
283+
class XKF : public NKF {
284+
public:
285+
private:
286+
};
287+
282288
// class AV_PosNED {
283289
// public:
284290
// uint16_t N;
@@ -682,6 +688,38 @@ class Base {
682688
return _nkf.variances();
683689
}
684690

691+
692+
/// @brief Set a variance value by name.
693+
/// @param name Name of variance to set (e.g. "pos_horiz").
694+
/// @param value New value of the variance.
695+
void xkf_set_variance(const char *name, double value) {
696+
_xkf.set_variance(T(), name, value);
697+
}
698+
uint64_t xkf_variance_T(std::string name) const {
699+
return _xkf.variance_T(name);
700+
}
701+
/// @brief Set XKF (EKF3) status flags.
702+
/// @param flags XKF (EKF3 self-assessment status flags.
703+
void xkf_set_flags(uint16_t flags) {
704+
_xkf.set_flags(T(), flags);
705+
}
706+
/// @brief XKF status flags.
707+
/// @return XKF self-assessment status flags.
708+
uint16_t xkf_flags() const {
709+
return _xkf.flags();
710+
}
711+
712+
/// @brief XKF (EKF3) status flags modification time.
713+
/// @return timestamp Timestamp at which the XKF self-assessment flags were last changed (microseconds).
714+
uint64_t xkf_flags_T() const {
715+
return _xkf.flags_T();
716+
}
717+
/// @brief All XKF (EKF3) variances.
718+
/// @return Returns all XKF (EKF3) variances as a map from name to value.
719+
std::map<const std::string, double> xkf_variances() {
720+
return _xkf.variances();
721+
}
722+
685723
/// @brief Retrieve parameter value.
686724
/// @param name Parameter value to retrieve.
687725
/// @detail This function will abort if the parameter has not been seen and no default is known.
@@ -1234,6 +1272,7 @@ class Base {
12341272

12351273
EKF _ekf;
12361274
NKF _nkf;
1275+
XKF _xkf;
12371276

12381277
bool _armed = false;
12391278

analyzing_dataflash_message_handler.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ void Analyzing_DataFlash_Message_Handler::handle_format_message_received(const c
5151
handlers[new_msg_type] = new LA_MsgHandler_NKF1(name, format, _analyze, _vehicle);
5252
} else if (streq(name, "NKF4")) {
5353
handlers[new_msg_type] = new LA_MsgHandler_NKF4(name, format, _analyze, _vehicle);
54+
} else if (streq(name, "XKF1")) {
55+
handlers[new_msg_type] = new LA_MsgHandler_XKF1(name, format, _analyze, _vehicle);
56+
} else if (streq(name, "XKF4")) {
57+
handlers[new_msg_type] = new LA_MsgHandler_XKF4(name, format, _analyze, _vehicle);
5458
} else if (streq(name, "ORGN")) {
5559
have_orgn = true;
5660
handlers[new_msg_type] = new LA_MsgHandler_ORGN(name, format, _analyze, _vehicle);

0 commit comments

Comments
 (0)