TinyRobotics
Loading...
Searching...
No Matches
IMU2D.h
1#pragma once
2#include <stdint.h>
3#include <cmath>
4
5#include "TinyRobotics/communication/Message.h"
6#include "TinyRobotics/communication/MessageHandler.h"
7#include "TinyRobotics/communication/MessageSource.h"
8#include "TinyRobotics/control/MotionState2D.h"
9#include "TinyRobotics/coordinates/Coordinate.h"
10#include "TinyRobotics/coordinates/GPSCoordinate.h"
11
12namespace tinyrobotics {
13
14/**
15 * @class IMU2D
16 * @ingroup imu
17 * @brief Basic 2D IMU dead-reckoning class.
18 *
19 * This class estimates 2D position, velocity, and heading (yaw angle) for
20 * robotics applications by integrating gyroscope and accelerometer data over
21 * time.
22 *
23 * - Integrates gyro Z (yaw rate) to estimate heading (radians)
24 * - Integrates accelerometer (X, Y) in the robot frame, rotated to world frame,
25 * to estimate velocity and position
26 * - All units SI (meters, seconds, radians)
27 *
28 * Limitations:
29 * - No sensor fusion with magnetometer or GPS
30 * - No Kalman filter or bias estimation
31 * - Subject to drift over time (no correction)
32 *
33 * Example usage:
34 * @code
35 * IMU2D<float> imu;
36 * imu.begin(initialAngle, initialPosition);
37 * imu.update(accelX, accelY, gyroZ, millis());
38 * auto pos = imu.getPosition();
39 * auto heading = imu.getHeading();
40 * auto speed = imu.getSpeed();
41 * @endcode
42 *
43 * @tparam T Numeric type (float or double recommended)
44 */
45
46template <typename T = float>
47class IMU2D : public IMotionState2D {
48 public:
49 IMU2D() = default;
50
51 bool begin(T initialAngleDeg, Coordinate<DistanceM> initialPosition) {
52 position = initialPosition;
53 headingRad = initialAngleDeg * M_PI / 180.0;
54 speedMPS = 0;
55 lastUpdateMillis = 0;
56 is_active = true;
57 return true;
58 }
59
60 bool begin(Transform2D transform) override {
61 return begin(transform.getHeading(AngleUnit::DEG), transform.pos);
62 }
63
64 void end() { is_active = false; }
65
66 /// Update with accelerometer and gyro measurements (accelX, accelY in sensor
67 /// frame, gyroZ in rad/s)
68 void update(T accelX, T accelY, T gyroZ_in, unsigned long nowMillis) {
69 if (!is_active) return;
70 if (lastUpdateMillis == 0) {
71 lastUpdateMillis = nowMillis;
72 return;
73 }
74
75 T dt = (nowMillis - lastUpdateMillis) / (T)1000;
76 lastUpdateMillis = nowMillis;
77 if (dt <= 0) return;
78
79 // Integrate gyro for heading
80 headingRad += gyroZ_in * dt;
81 // Angle wrap
82 headingRad = normalizeAngleRad(headingRad);
83
84 // Rotate acceleration to world frame
85 T ax_world = accelX * std::cos(headingRad) - accelY * std::sin(headingRad);
86 T ay_world = accelX * std::sin(headingRad) + accelY * std::cos(headingRad);
87
88 // Integrate acceleration for velocity (simple dead-reckoning)
89 static T vx = 0, vy = 0;
90 vx += ax_world * dt;
91 vy += ay_world * dt;
92 speedMPS = std::sqrt(vx * vx + vy * vy);
93
94 // Integrate velocity for position
95 T dx = vx * dt;
96 T dy = vy * dt;
97
98 position.x += dx;
99 position.y += dy;
100 totalDistanceM += std::sqrt(dx * dx + dy * dy);
101
102 lastDelta = {static_cast<float>(dx), static_cast<float>(dy),
103 static_cast<float>(gyroZ_in * dt)};
104 lastAngularVelocity = gyroZ_in;
105 timestamp = millis();
106 publish();
107 }
108
109 /// @brief Get the last delta update (dx, dy, dtheta)
110 Delta2D getLastDelta() const { return lastDelta; }
111 /// @brief Get the current angular velocity (radians/second)
112 float getAngularVelocity() const { return lastAngularVelocity; }
113 /// @brief Get the current linear velocity (meters/second)
114 float getLinearVelocity() const { return speedMPS; }
115 /// @brief Get the current orientation (radians)
116 float getTheta() const { return headingRad; }
117
118 /// get position
119 Coordinate<DistanceM> getPosition() const { return position; }
120 /// get heading as Angle
121 Angle getHeading() const { return Angle(headingRad, AngleUnit::RAD); }
122 /// get speed as Speed
123 Speed getSpeed() const { return Speed(speedMPS, SpeedUnit::MPS); }
124 /// Get the total distance traveled
125 Distance getTotalDistance() const {
126 return Distance(totalDistanceM, DistanceUnit::M);
127 }
128 /// Get time of last update
129 uint32_t getTimestamp() const { return timestamp; }
130
131 Transform2D getTransform() const {
132 return Transform2D(position, headingRad * 180.0f / M_PI);
133 }
134
135 public:
136 bool is_active = false;
137 float headingRad = 0;
138 float speedMPS = 0;
139 Coordinate<DistanceM> position;
140 unsigned long lastUpdateMillis = 0;
141 Delta2D lastDelta = {0.0f, 0.0f, 0.0f};
142 float lastAngularVelocity = 0.0f;
143 float totalDistanceM = 0.0f;
144 uint32_t timestamp = 0;
145
146 void publish() {
147 // Publish position as message
148 Message<Coordinate<DistanceM>> msgPos{MessageContent::Position, position,
149 Unit::Meters};
150 msgPos.origin = MessageOrigin::IMU;
151 sendMessage(msgPos);
152
153 // Publish heading as float (radians)
154 Message<float> msgHeading{MessageContent::Heading, headingRad,
155 Unit::AngleRadian};
156 msgHeading.origin = MessageOrigin::IMU;
157 sendMessage(msgHeading);
158
159 // Publish speed as float (m/s)
160 Message<float> msgSpeed{MessageContent::Speed, speedMPS,
161 Unit::MetersPerSecond};
162 msgSpeed.origin = MessageOrigin::IMU;
163 sendMessage(msgSpeed);
164 }
165};
166
167} // namespace tinyrobotics
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
Represents a distance measurement with unit conversion support.
Definition: Distance.h:40
Basic 2D IMU dead-reckoning class.
Definition: IMU2D.h:47
float getLinearVelocity() const
Get the current linear velocity (meters/second)
Definition: IMU2D.h:114
void update(T accelX, T accelY, T gyroZ_in, unsigned long nowMillis)
Definition: IMU2D.h:68
Delta2D getLastDelta() const
Get the last delta update (dx, dy, dtheta)
Definition: IMU2D.h:110
Angle getHeading() const
get heading as Angle
Definition: IMU2D.h:121
Distance getTotalDistance() const
Get the total distance traveled.
Definition: IMU2D.h:125
float getTheta() const
Get the current orientation (radians)
Definition: IMU2D.h:116
uint32_t getTimestamp() const
Get time of last update.
Definition: IMU2D.h:129
Speed getSpeed() const
get speed as Speed
Definition: IMU2D.h:123
float getAngularVelocity() const
Get the current angular velocity (radians/second)
Definition: IMU2D.h:112
Coordinate< DistanceM > getPosition() const
get position
Definition: IMU2D.h:119
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
Represents a 2D rigid body transform (SE(2)): translation and rotation.
Definition: FrameMgr2D.h:42
float getHeading(AngleUnit unit) const
Get heading in specified unit (degrees or radians)
Definition: FrameMgr2D.h:54
DistanceUnit
Supported distance units for conversion and representation.
Definition: Distance.h:10
AngleUnit
Supported angle units for conversion and representation.
Definition: Angle.h:11
SpeedUnit
Supported speed units for conversion and representation.
Definition: Speed.h:10
Represents a 2D incremental motion update (dx, dy, dtheta).
Definition: MotionState2D.h:15
Generic message structure for communication, parameterized by value type.
Definition: Message.h:72