merge in nyc-dr1-release history after reset to nyc-dr1-dev
diff --git a/firmware/inc/algos/fusion.h b/firmware/inc/algos/fusion.h
index 506cd1c..6bf4878 100644
--- a/firmware/inc/algos/fusion.h
+++ b/firmware/inc/algos/fusion.h
@@ -22,6 +22,7 @@
#include "mat.h"
#include "quat.h"
+#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
@@ -51,6 +52,9 @@
uint32_t mCount[3];
uint32_t flags;
+ float trustedMagDuration;
+ bool lastMagInvalid;
+
float fake_mag_decimation;
struct FusionParam param;
};
@@ -61,17 +65,28 @@
FUSION_REINITIALIZE = 1 << 2,
};
+enum MagTrustMode {
+ NORMAL,
+ INITIALIZATION, // right after initialization of fusion
+ BACK_TO_VALID, // when the mag value goes from invalid to valid
+ MANUAL_MAG_CAL // right after a manual calibration
+};
+
void initFusion(struct Fusion *fusion, uint32_t flags);
void fusionHandleGyro(struct Fusion *fusion, const struct Vec3 *w, float dT);
int fusionHandleAcc(struct Fusion *fusion, const struct Vec3 *a, float dT);
-int fusionHandleMag(struct Fusion *fusion, const struct Vec3 *m);
+int fusionHandleMag(struct Fusion *fusion, const struct Vec3 *m, float dT);
+
+// set trust mode of mag sensors depending on scenarios, see MagTrustMode
+void fusionSetMagTrust(struct Fusion *fusion, int mode);
void fusionGetAttitude(const struct Fusion *fusion, struct Vec4 *attitude);
void fusionGetBias(const struct Fusion *fusion, struct Vec3 *bias);
void fusionGetRotationMatrix(const struct Fusion *fusion, struct Mat33 *R);
int fusionHasEstimate(const struct Fusion *fusion);
+
#ifdef __cplusplus
}
#endif
diff --git a/firmware/src/algos/fusion.c b/firmware/src/algos/fusion.c
index 537af51..a786cef 100644
--- a/firmware/src/algos/fusion.c
+++ b/firmware/src/algos/fusion.c
@@ -54,7 +54,7 @@
#define MAX_VALID_MAGNETIC_FIELD 75.0f
#define MAX_VALID_MAGNETIC_FIELD_SQ (MAX_VALID_MAGNETIC_FIELD * MAX_VALID_MAGNETIC_FIELD)
-#define MIN_VALID_MAGNETIC_FIELD 30.0f
+#define MIN_VALID_MAGNETIC_FIELD 20.0f //norminal mag field strength is 25uT in some area
#define MIN_VALID_MAGNETIC_FIELD_SQ (MIN_VALID_MAGNETIC_FIELD * MIN_VALID_MAGNETIC_FIELD)
#define MIN_VALID_CROSS_PRODUCT_MAG 1.0e-3
@@ -62,6 +62,8 @@
#define DELTA_TIME_MARGIN 1.0e-9f
+#define TRUST_DURATION_MANUAL_MAG_CAL 5.f //unit: seconds
+
void initFusion(struct Fusion *fusion, uint32_t flags) {
fusion->flags = flags;
@@ -95,12 +97,16 @@
initVec3(&fusion->mData[0], 0.0f, 0.0f, 0.0f);
initVec3(&fusion->mData[1], 0.0f, 0.0f, 0.0f);
initVec3(&fusion->mData[2], 0.0f, 0.0f, 0.0f);
+
} else {
// mask off disabled sensor bit
fusion->mInitState &= (ACC
| ((fusion->flags & FUSION_USE_MAG) ? MAG : 0)
| ((fusion->flags & FUSION_USE_GYRO) ? GYRO : 0));
}
+
+ fusionSetMagTrust(fusion, NORMAL);
+ fusion->lastMagInvalid = false;
}
int fusionHasEstimate(const struct Fusion *fusion) {
@@ -218,6 +224,8 @@
initZeroMatrix(&fusion->P[0][1]);
initZeroMatrix(&fusion->P[1][0]);
initZeroMatrix(&fusion->P[1][1]);
+
+ fusionSetMagTrust(fusion, INITIALIZATION);
}
return 0;
@@ -576,10 +584,11 @@
return 0;
}
-#define MAG_COS_CONV_FACTOR 0.02f
-#define MAG_COS_CONV_LIMIT 2.f
+#define MAG_COS_CONV_FACTOR 0.02f
+#define MAG_COS_CONV_LIMIT 3.5f
+#define MAG_STDEV_REDUCTION 0.005f // lower stdev means more trust
-int fusionHandleMag(struct Fusion *fusion, const struct Vec3 *m) {
+int fusionHandleMag(struct Fusion *fusion, const struct Vec3 *m, float dT) {
if (!fusion_init_complete(fusion, MAG, m, 0.0f /* dT */)) {
return -EINVAL;
}
@@ -588,6 +597,8 @@
if (magFieldSq > MAX_VALID_MAGNETIC_FIELD_SQ
|| magFieldSq < MIN_VALID_MAGNETIC_FIELD_SQ) {
+ fusionSetMagTrust(fusion, NORMAL);
+ fusion->lastMagInvalid = true;
return -EINVAL;
}
@@ -601,9 +612,16 @@
vec3Cross(&east, m, &up);
if (vec3NormSquared(&east) < MIN_VALID_CROSS_PRODUCT_MAG_SQ) {
+ fusionSetMagTrust(fusion, NORMAL);
+ fusion->lastMagInvalid = true;
return -EINVAL;
}
+ if (fusion->lastMagInvalid) {
+ fusion->lastMagInvalid = false;
+ fusionSetMagTrust(fusion, BACK_TO_VALID);
+ }
+
struct Vec3 north;
vec3Cross(&north, &up, &east);
@@ -616,12 +634,26 @@
struct Vec3 mm;
mat33Apply(&mm, &R, &fusion->Bm);
float cos_err = vec3Dot(&mm, &north);
- cos_err = cos_err < (1.f - MAG_COS_CONV_FACTOR) ?
- (1.f - MAG_COS_CONV_FACTOR) : cos_err;
- float fc;
- fc = (1.f - cos_err) * (1.0f / MAG_COS_CONV_FACTOR * MAG_COS_CONV_LIMIT);
- p *= expf(-fc);
+ if (fusion->trustedMagDuration > 0) {
+ // if the trust mag time period is not finished
+ if (cos_err < (1.f - MAG_COS_CONV_FACTOR/4)) {
+ // if the mag direction and the fusion north has not converged, lower the
+ // standard deviation of mag to speed up convergence.
+ p *= MAG_STDEV_REDUCTION;
+ fusion->trustedMagDuration -= dT;
+ } else {
+ // it has converged already, so no need to keep the trust period any longer
+ fusionSetMagTrust(fusion, NORMAL);
+ }
+ } else {
+ cos_err = cos_err < (1.f - MAG_COS_CONV_FACTOR) ?
+ (1.f - MAG_COS_CONV_FACTOR) : cos_err;
+
+ float fc;
+ fc = (1.f - cos_err) * (1.0f / MAG_COS_CONV_FACTOR * MAG_COS_CONV_LIMIT);
+ p *= expf(-fc);
+ }
}
fusionUpdate(fusion, &north, &fusion->Bm, p);
@@ -629,6 +661,24 @@
return 0;
}
+void fusionSetMagTrust(struct Fusion *fusion, int mode) {
+ switch(mode) {
+ case NORMAL:
+ fusion->trustedMagDuration = 0; // disable
+ break;
+ case INITIALIZATION:
+ case BACK_TO_VALID:
+ fusion->trustedMagDuration = 0; // no special treatment for these two
+ break;
+ case MANUAL_MAG_CAL:
+ fusion->trustedMagDuration = TRUST_DURATION_MANUAL_MAG_CAL;
+ break;
+ default:
+ fusion->trustedMagDuration = 0; // by default it is disable
+ break;
+ }
+}
+
void fusionGetAttitude(const struct Fusion *fusion, struct Vec4 *attitude) {
*attitude = fusion->x0;
}
diff --git a/firmware/src/drivers/orientation/orientation.c b/firmware/src/drivers/orientation/orientation.c
index 7bb06ef..c9bd5e2 100644
--- a/firmware/src/drivers/orientation/orientation.c
+++ b/firmware/src/drivers/orientation/orientation.c
@@ -29,6 +29,7 @@
#include <nanohub_math.h>
#include <algos/fusion.h>
#include <sensors.h>
+#include <variant/inc/sensType.h>
#include <limits.h>
#include <slab.h>
@@ -51,6 +52,7 @@
#define EVT_SENSOR_ACC_DATA_RDY sensorGetMyEventType(SENS_TYPE_ACCEL)
#define EVT_SENSOR_GYR_DATA_RDY sensorGetMyEventType(SENS_TYPE_GYRO)
#define EVT_SENSOR_MAG_DATA_RDY sensorGetMyEventType(SENS_TYPE_MAG)
+#define EVT_SENSOR_MAG_BIAS sensorGetMyEventType(SENS_TYPE_MAG_BIAS)
#define kGravityEarth 9.80665f
#define kRad2deg (180.0f / M_PI)
@@ -478,7 +480,7 @@
case MAG:
initVec3(&m, mTask.samples[MAG][k].x, mTask.samples[MAG][k].y, mTask.samples[MAG][k].z);
- fusionHandleMag(&mTask.fusion, &m);
+ fusionHandleMag(&mTask.fusion, &m, dT);
--mTask.sample_counts[MAG];
if (++k == MAX_NUM_SAMPLES)
@@ -589,6 +591,7 @@
if (sensorRequest(mTask.tid, mTask.magHandle, mTask.raw_sensor_rate[MAG],
mTask.raw_sensor_latency)) {
osEventSubscribe(mTask.tid, EVT_SENSOR_MAG_DATA_RDY);
+ osEventSubscribe(mTask.tid, EVT_SENSOR_MAG_BIAS);
break;
}
}
@@ -760,6 +763,13 @@
fillSamples(ev, GYR);
drainSamples();
break;
+ case EVT_SENSOR_MAG_BIAS:
+ ev = (struct TripleAxisDataEvent *)evtData;
+ if (ev->samples[0].firstSample.biasPresent && mTask.flags & FUSION_FLAG_ENABLED) {
+ //it is a user initiated mag cal event
+ fusionSetMagTrust(&mTask.fusion, MANUAL_MAG_CAL);
+ }
+ break;
case EVT_SENSOR_MAG_DATA_RDY:
ev = (struct TripleAxisDataEvent *)evtData;
fillSamples(ev, MAG);