7#include "TinyRobotics/communication/Message.h"
8#include "TinyRobotics/communication/MessageHandler.h"
9#include "TinyRobotics/communication/MessageSource.h"
10#include "TinyRobotics/control/KalmanFilter.h"
11#include "TinyRobotics/control/MotionState2D.h"
12#include "TinyRobotics/coordinates/Coordinate.h"
13#include "TinyRobotics/coordinates/GPSCoordinate.h"
15namespace tinyrobotics {
18
19
20
21
22
23
24
25
26
27
28
29
33
34
44
45
52
53
56 bool begin(
const Coordinate<DistanceM>& initialPosition = {0, 0},
57 float initialHeadingDeg = 0) {
69 return begin(initialTransform.pos,
77
78
79
80
81
82
83
84
85
86
87
88
89 void predict(uint32_t timeMs,
float ax = 0.0f,
float ay = 0.0f) {
90 uint32_t dtMs = timeMs - lastPredictTime;
91 lastPredictTime = timeMs;
92 float dt = dtMs * 0.001f;
93 if (dt <= 0.0f)
return;
94 if (dt > 0.1f) dt = 0.1f;
103 if (!hasWheelSpeed && hasIMU) {
104 float ax_world = ax * c - ay * s;
105 float ay_world = ax * s + ay * c;
106 float dv = std::sqrt(ax_world * ax_world + ay_world * ay_world) * dt;
112 float omega = hasIMU ? (omegaMeasured - state
.gyroBias) : 0.0f;
118 state.x += v * c * dt;
119 state
.y += v * s * dt;
123 float F[5][5] = {{1, 0, -v * s * dt, c * dt, 0},
124 {0, 1, v * c * dt, s * dt, 0},
129 float q_pos = 0.05f, q_heading = 0.01f, q_speed = 0.1f, q_bias = 0.0005f;
130 float Q[5][5] = {{q_pos, 0, 0, 0, 0},
132 {0, 0, q_heading, 0, 0},
133 {0, 0, 0, q_speed, 0},
134 {0, 0, 0, 0, q_bias}};
136 float FP[5][5] = {}, FPFt[5][5] = {};
137 for (
int i = 0; i < 5; i++)
138 for (
int j = 0; j < 5; j++)
139 for (
int k = 0; k < 5; k++) FP[i][j] += F[i][k] * P[k][j];
140 for (
int i = 0; i < 5; i++)
141 for (
int j = 0; j < 5; j++)
142 for (
int k = 0; k < 5; k++) FPFt[i][j] += FP[i][k] * F[j][k];
143 for (
int i = 0; i < 5; i++)
144 for (
int j = 0; j < 5; j++) P[i][j] = FPFt[i][j] + Q[i][j];
153
154
155
156
157
158
159
160
161
162
163 void updateIMU(uint32_t timeMs,
float yawRate,
float ax = 0.0f,
166 omegaMeasured = yawRate;
171 void updateIMU(
const IMU2D<
float>& imu) {
172 uint32_t t = imu.getTimestamp();
173 float omega = imu.getAngularVelocity();
174 float v = imu.getLinearVelocity();
184
185
186
187
188
189
190
192 hasWheelSpeed =
true;
194 float y = speed - state
.speed;
196 float S = P[3][3] + R;
198 for (
int i = 0; i < 5; i++) K[i] = P[i][3] / S;
200 updateCovariance(K, 3);
203 void updateSpeed(uint32_t timeMs,
Speed newSpeed) {
208
209
210
211
212
213
214
215
218 float y = normalizeAngleRad(heading - state
.heading);
220 float S = P[2][2] + R;
222 for (
int i = 0; i < 5; i++) K[i] = P[i][2] / S;
225 updateCovariance(K, 2);
228 void updateHeading(uint32_t timeMs,
Angle newHeading) {
233
234
235
236
237
238
239
240
241
242
243 void updateGPS(uint32_t timeMs,
float x,
float y,
float accuracy) {
245 float R = accuracy * accuracy;
248 float residual = x - state.x;
249 float S = P[0][0] + R;
251 for (
int i = 0; i < 5; i++) K[i] = P[i][0] / S;
252 applyUpdate(K, residual);
253 updateCovariance(K, 0);
257 float residual = y - state
.y;
258 float S = P[1][1] + R;
260 for (
int i = 0; i < 5; i++) K[i] = P[i][1] / S;
261 applyUpdate(K, residual);
262 updateCovariance(K, 1);
266 void updateGPS(uint32_t timeMs,
const Coordinate<DistanceM>& gpsCoord,
268 updateGPS(timeMs, gpsCoord.x, gpsCoord.y, accuracyM);
275
276
277
281
282
283
287
288
289
293
294
295
299 return Coordinate<DistanceM>(state.x, state.y);
305 Coordinate<DistanceM>(state.x, state
.y),
316 uint32_t lastPredictTime = 0;
317 float omegaMeasured = 0.0f;
318 bool hasWheelSpeed =
false;
321 void applyUpdate(
float K[5],
float residual) {
322 state.x += K[0] * residual;
323 state
.y += K[1] * residual;
325 state
.speed += K[3] * residual;
330 void updateCovariance(
float K[5],
int idx) {
332 for (
int i = 0; i < 5; i++)
333 for (
int j = 0; j < 5; j++) newP[i][j] = P[i][j] - K[i] * P[idx][j];
334 for (
int i = 0; i < 5; i++)
335 for (
int j = 0; j < 5; j++) P[i][j] = newP[i][j];
339
340
341
342 void reset(uint32_t timeMs = millis()) {
349 hasWheelSpeed =
false;
352 for (
int i = 0; i < 5; i++)
353 for (
int j = 0; j < 5; j++) P[i][j] = (i == j) ? 1.0f : 0.0f;
355 lastPredictTime = timeMs;
356 omegaMeasured = 0.0f;
Represents an angle with unit conversion and wrap-around support.
Definition: Angle.h:42
A generic 3D coordinate class for robotics, navigation, and spatial calculations.
Definition: Coordinate.h:57
2D sensor fusion EKF for position, heading, and speed estimation.
Definition: Fusion2D.h:30
Fusion2D()
Constructor. Resets the EKF state to zeros.
Definition: Fusion2D.h:54
void updateSpeed(uint32_t timeMs, float speed)
Update the EKF with wheel speed.
Definition: Fusion2D.h:191
void updateGPS(uint32_t timeMs, float x, float y, float accuracy)
Update the EKF with GPS position.
Definition: Fusion2D.h:243
void updateHeading(uint32_t timeMs, float heading)
Update the EKF with an absolute heading measurement.
Definition: Fusion2D.h:216
Pose2D getPose() const
Get 2D pose (position + heading).
Definition: Fusion2D.h:284
void predict(uint32_t timeMs, float ax=0.0f, float ay=0.0f)
Predict the next state based on elapsed time.
Definition: Fusion2D.h:89
void reset(uint32_t timeMs=millis())
Reset the EKF state and covariance.
Definition: Fusion2D.h:342
State2D getState() const
Get the full estimated state.
Definition: Fusion2D.h:278
float getSpeedMPS() const
Get the current speed estimate.
Definition: Fusion2D.h:290
float getGyroBias() const
Get the current estimated gyro bias.
Definition: Fusion2D.h:296
void updateIMU(uint32_t timeMs, float yawRate, float ax=0.0f, float ay=0.0f)
Update the EKF with IMU measurements.
Definition: Fusion2D.h:163
Interface for representing the navigation state of a robot in 2D space.
Definition: MotionState2D.h:35
Represents a speed measurement with unit conversion support.
Definition: Speed.h:40
AngleUnit
Supported angle units for conversion and representation.
Definition: Angle.h:11
SpeedUnit
Supported speed units for conversion and representation.
Definition: Speed.h:10
Simple 2D pose (x, y, heading).
Definition: Fusion2D.h:46
Holds the estimated 2D state.
Definition: Fusion2D.h:35
float gyroBias
Estimated gyro bias (radians/sec)
Definition: Fusion2D.h:40
float speed
Speed in meters per second.
Definition: Fusion2D.h:39
uint32_t timeMs
Timestamp of the state in milliseconds.
Definition: Fusion2D.h:36
float y
Position in meters.
Definition: Fusion2D.h:37
float heading
Heading in radians.
Definition: Fusion2D.h:38