-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathattitude_resolution.cpp
138 lines (120 loc) · 4.28 KB
/
attitude_resolution.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include <cmath>
#include <cstdio>
#include "everything.h"
#include "bigcat-blas.h"
namespace hardware {
const blas::vector<3> accelerometer();
const blas::vector<3> magnetometer();
const blas::vector<3> gyroscope();
}
void Madgwick_update(blas::quaternion &, const float);
void thread_attitude_resolution() {
LoopDuration dur(0.01);
blas::quaternion q = {1, 0, 0, 0};
while (true) {
// printf("%s\r\n", hardware::gyroscope().to_string());
Madgwick_update(q, dur.measure());
sys::enter_critical();
auto euler = q.to_euler_angles();
global_state.pitch = euler(1);
global_state.yaw = euler(0);
sys::leave_critical();
}
}
void Madgwick_update(blas::quaternion &q, const float duration) {
using blas::quaternion;
using blas::vector;
using blas::matrix;
const float beta = 0.8;
const bool
USE_GYR = true,
USE_ACC = true,
USE_MAG = false;
vector<3> gyr;
quaternion gradient;
if (USE_ACC || USE_MAG) {
if (USE_ACC) {
const vector<3> acc = hardware::accelerometer().normalized();
const vector<3> acc_expect = q.rotate_inv({0, 0, 1});
const quaternion acc_error = vector<3>(acc_expect - acc);
const matrix<4> acc_jacobian = q.rotate_inv_jacobian({0, 0, 1});
gradient += vector<4>(acc_jacobian.trans() * acc_error.to_vector());
}
if (USE_MAG) {
const vector<3> mag = hardware::magnetometer().normalized();
const vector<3> mag_0 = q.rotate(mag);
const float mag_h = sqrtf(mag_0(0) * mag_0(0) + mag_0(1) * mag_0(1));
const float mag_v = mag_0(2);
const vector<3> mag_expect = q.rotate_inv({mag_h, 0, mag_v});
const quaternion mag_error = vector<3>(mag_expect - mag);
const matrix<4> mag_jacobian = q.rotate_inv_jacobian({mag_h, 0, mag_v});
gradient += vector<4>(mag_jacobian.trans() * mag_error.to_vector());
}
gradient = gradient.normalized();
}
if (USE_GYR) {
gyr = hardware::gyroscope();
sys::enter_critical();
global_state.pitch_rate = gyr(1);
global_state.yaw_rate = gyr(2);
sys::leave_critical();
}
quaternion q_new = 0.5 * q * gyr;
if (!isnan(gradient.b()))
q_new += beta * gradient;
// Approximate the integral
q += q_new * duration;
q = q.normalized();
}
extern void (*ICM20948_Read)(uint8_t, uint8_t *, uint32_t);
extern void (*AK09916_Read)(uint8_t, uint8_t *, uint32_t);
extern void (*MPU6050_Read)(uint8_t, uint8_t *, uint32_t);
namespace hardware {
blas::matrix<3> direction_correction = {
{ 0, -1, 0 },
{ -1, 0, 0 },
{ 0, 0, 1 }
};
static float int16_to_float(uint8_t *buf) {
return (int16_t)(buf[0] * 256 + buf[1]) / 32768.0;
}
const blas::vector<3> accelerometer() {
uint8_t buf[6] = {};
// ICM20948_Read(0x2d, buf, 6);
MPU6050_Read(0x3b, buf, 6);
const float scale = 2;
return direction_correction * blas::vector<3> {
int16_to_float(&buf[0]) * scale,
int16_to_float(&buf[2]) * scale,
int16_to_float(&buf[4]) * scale
};
}
const blas::vector<3> gyroscope() {
const float PI = 3.141593f;
const float DEG2ARC = PI/180;
uint8_t buf[6];
// ICM20948_Read(0x33, buf, 6);
MPU6050_Read(0x43, buf, 6);
const float scale = 250;
return direction_correction * blas::vector<3> {
-int16_to_float(&buf[0]) * scale * DEG2ARC,
-int16_to_float(&buf[2]) * scale * DEG2ARC,
int16_to_float(&buf[4]) * scale * DEG2ARC
};
}
const blas::vector<3> magnetometer() {
uint8_t buf[6];
AK09916_Read(0x11, buf, 6);
uint8_t overflow_flag;
AK09916_Read(0x18, &overflow_flag, 1); // Must read after every measurement.
overflow_flag &= 0x8;
const float scale = 0.15;
static blas::vector<3> prev;
blas::vector<3> cur = {
int16_to_float(&buf[0]) * scale,
int16_to_float(&buf[2]) * scale,
int16_to_float(&buf[4]) * scale
};
return direction_correction * 0.5 * (prev + cur);
}
}