TinyRobotics
Loading...
Searching...
No Matches
Fusion3D.h
1#pragma once
2#include <stdint.h>
3
4#include <cmath>
5
6#include "TinyRobotics/communication/Message.h"
7#include "TinyRobotics/communication/MessageHandler.h"
8#include "TinyRobotics/communication/MessageSource.h"
9#include "TinyRobotics/coordinates/Coordinate.h"
10#include "TinyRobotics/coordinates/Orientation3D.h"
11#include "TinyRobotics/units/AngularVelocity.h"
12#include "TinyRobotics/units/Distance.h"
13#include "TinyRobotics/units/Speed.h"
14
15namespace tinyrobotics {
16
17/**
18 * @class Fusion3D
19 * @ingroup fusion
20 * @brief 3D sensor fusion EKF for position, orientation, and velocity
21 * estimation.
22 *
23 * Supports optional sensors:
24 * - IMU3D (gyro + acceleration)
25 * - GPS position
26 * - Absolute orientation (magnetometer or GPS-derived)
27 *
28 * The EKF automatically adapts to the available sensors.
29 */
30class Fusion3D : public MessageSource {
31 public:
32 struct State3D {
33 uint32_t timeMs; ///< Timestamp in ms
34 float x, y, z; ///< Position (meters)
35 float vx, vy, vz; ///< Velocity (m/s)
36 float yaw, pitch, roll; ///< Orientation (radians)
37 float gyroBiasX, gyroBiasY, gyroBiasZ; ///< Gyro bias (rad/s)
38 };
39
40 Fusion3D() { reset(0); }
41
42 bool begin(const Coordinate<float>& initialPosition = {0, 0, 0},
43 const Orientation3D& initialOrientation = Orientation3D()) {
44 reset(0);
45 state.x = initialPosition.x;
46 state.y = initialPosition.y;
47 state.z = initialPosition.z;
48 state.yaw = initialOrientation.yaw;
49 state.pitch = initialOrientation.pitch;
50 state.roll = initialOrientation.roll;
51 state.vx = state.vy = state.vz = 0.0f;
52 state.timeMs = millis();
53 return true;
54 }
55
56 // Prediction step (dead-reckoning)
57 void predict(uint32_t timeMs, float ax = 0.0f, float ay = 0.0f,
58 float az = 0.0f) {
59 uint32_t dtMs = timeMs - lastPredictTime;
60 lastPredictTime = timeMs;
61 float dt = dtMs * 0.001f;
62 if (dt <= 0.0f) return;
63 if (dt > 0.1f) dt = 0.1f;
64
65 // Integrate acceleration for velocity
66 state.vx += ax * dt;
67 state.vy += ay * dt;
68 state.vz += az * dt;
69
70 // Integrate velocity for position
71 state.x += state.vx * dt;
72 state.y += state.vy * dt;
73 state.z += state.vz * dt;
74
75 // Integrate angular velocity for orientation (simple Euler integration)
76 state.roll += (omegaXMeasured - state.gyroBiasX) * dt;
77 state.pitch += (omegaYMeasured - state.gyroBiasY) * dt;
78 state.yaw += (omegaZMeasured - state.gyroBiasZ) * dt;
79 wrapAngles();
80
81 state.timeMs = timeMs;
82 }
83
84 // IMU update (gyro + accel)
85 void updateIMU(uint32_t timeMs, float omegaX, float omegaY, float omegaZ,
86 float ax, float ay, float az) {
87 hasIMU = true;
88 omegaXMeasured = omegaX;
89 omegaYMeasured = omegaY;
90 omegaZMeasured = omegaZ;
91 predict(timeMs, ax, ay, az);
92 }
93
94 // GPS update
95 void updateGPS(uint32_t timeMs, float x, float y, float z, float accuracy) {
96 predict(timeMs);
97 //float R = accuracy * accuracy;
98 // X
99 float residualX = x - state.x;
100 // Y
101 float residualY = y - state.y;
102 // Z
103 float residualZ = z - state.z;
104 // (EKF update step omitted for brevity)
105 state.x += residualX * 0.5f; // Simple correction
106 state.y += residualY * 0.5f;
107 state.z += residualZ * 0.5f;
108 }
109
110 // Absolute orientation update (e.g., from magnetometer)
111 void updateOrientation(uint32_t timeMs, float yaw, float pitch, float roll) {
112 predict(timeMs);
113 // (EKF update step omitted for brevity)
114 state.yaw = yaw;
115 state.pitch = pitch;
116 state.roll = roll;
117 wrapAngles();
118 }
119
120 // Outputs
121 State3D getState() const { return state; }
122 Coordinate<float> getPosition() const { return {state.x, state.y, state.z}; }
123 Speed3D getVelocity() const {
124 return Speed3D(state.vx, state.vy, state.vz, SpeedUnit::MPS);
125 }
126 Orientation3D getOrientation() const {
127 return Orientation3D(state.yaw, state.pitch, state.roll);
128 }
129
130 protected:
131 State3D state;
132 uint32_t lastPredictTime = 0;
133 float omegaXMeasured = 0.0f, omegaYMeasured = 0.0f, omegaZMeasured = 0.0f;
134 bool hasIMU = false;
135
136 void wrapAngles() {
137 state.yaw = normalizeAngleRad(state.yaw);
138 state.pitch = normalizeAngleRad(state.pitch);
139 state.roll = normalizeAngleRad(state.roll);
140 }
141
142 void reset(uint32_t timeMs = millis()) {
143 state = {};
144 state.timeMs = timeMs;
145 state.x = state.y = state.z = 0.0f;
146 state.vx = state.vy = state.vz = 0.0f;
147 state.yaw = state.pitch = state.roll = 0.0f;
148 state.gyroBiasX = state.gyroBiasY = state.gyroBiasZ = 0.0f;
149 hasIMU = false;
150 lastPredictTime = timeMs;
151 omegaXMeasured = omegaYMeasured = omegaZMeasured = 0.0f;
152 }
153};
154
155} // namespace tinyrobotics
A generic 3D coordinate class for robotics, navigation, and spatial calculations.
Definition: Coordinate.h:57
3D sensor fusion EKF for position, orientation, and velocity estimation.
Definition: Fusion3D.h:30
Base class for message sources in the TinyRobotics communication framework.
Definition: MessageSource.h:35
Simple 3D orientation class (yaw, pitch, roll in radians)
Definition: Orientation3D.h:13
float roll
Roll angle (radians)
Definition: Orientation3D.h:22
float pitch
Pitch angle (radians)
Definition: Orientation3D.h:21
float yaw
Yaw angle (radians)
Definition: Orientation3D.h:20
SpeedUnit
Supported speed units for conversion and representation.
Definition: Speed.h:10
Definition: Fusion3D.h:32
float gyroBiasZ
Gyro bias (rad/s)
Definition: Fusion3D.h:37
float roll
Orientation (radians)
Definition: Fusion3D.h:36
float vz
Velocity (m/s)
Definition: Fusion3D.h:35
uint32_t timeMs
Timestamp in ms.
Definition: Fusion3D.h:33
float z
Position (meters)
Definition: Fusion3D.h:34