TinyRobotics
Loading...
Searching...
No Matches
OdometryModel2D.h
1#pragma once
2#include <cmath>
3
4#include "TinyRobotics/odometry/IOdometryModel2D.h"
5#include "TinyRobotics/odometry/ISpeedSource.h"
6#include "TinyRobotics/units/Units.h"
7
8namespace tinyrobotics {
9
10/**
11 * @class OdometryModel2D
12 * @ingroup odometry
13 * @brief Odometry model for Ackermann, differential drive, and boat kinematics.
14 *
15 * This model computes the change in heading (theta) for:
16 * - Ackermann steering vehicles (car-like, with nonzero wheelBase)
17 * - Differential drive robots (wheelBase = 0, steeringAngle is angular
18 * velocity)
19 * - Boats (set wheelBase to the distance to the rudder; steeringAngle is rudder
20 * angle)
21 *
22 * ## Kinematic Handling
23 * - If wheelBase > 0: Uses Ackermann/boat kinematics: omega = v *
24 * tan(steeringAngle) / wheelBase
25 * - If wheelBase == 0: Uses differential drive convention: omega =
26 * steeringAngle (interpreted as angular velocity)
27 *
28 * ## Boat Note
29 * For boats, set wheelBase to the distance from the center of mass to the
30 * rudder, and provide the rudder angle as steeringAngle.
31 *
32 * @author TinyRobotics contributors
33 * @date 2026-04-07
34 */
35class OdometryModel2D : public IOdometryModel2D {
36 void registerCallback(void (*callback)(void*), void* userData) override {}
37
38 public:
39 OdometryModel2D(Distance wheelBase) : wheelBase(wheelBase) {}
40
41 void setSpeedSource(ISpeedSource& speedSource) override {
42 p_speedSource = &speedSource;
43 }
44
45 void setSteeringAngle(Angle angle) {
46 this->steeringAngle = angle;
47 if (callback) {
48 callback(userData);
49 }
50 }
51 void setSpeed(Speed speed) {
52 this->speed = speed;
53 if (callback) {
54 callback(userData);
55 }
56 }
57
58 virtual void updateSpeed(uint32_t deltaTimeMs) {
59 assert(p_speedSource != nullptr);
60 speed = p_speedSource->updateSpeed(deltaTimeMs);
61 }
62
63 /**
64 * @brief Compute heading change (deltaTheta) for Ackermann kinematics.
65 * @param speed Speed of the vehicle (meters/second)
66 * @param steeringAngle Steering angle (radians)
67 * @param deltaTimeMs Time interval (milliseconds)
68 * @return Change in heading (radians)
69 */
70 float computeDeltaTheta(uint16_t deltaTimeMs) const override {
71 float wb = wheelBase.getValue(DistanceUnit::M);
72 float speedMps = speed.getValue(SpeedUnit::MPS);
73 float steeringAngleRad = steeringAngle.getValue(AngleUnit::RAD);
74 float omega = (wb > 0.0f) ? speedMps * std::tan(steeringAngleRad) / wb
75 : steeringAngleRad;
76 return omega * static_cast<float>(deltaTimeMs) / 1000.0f;
77 }
78
79 void computeDeltaXY(float theta, uint32_t deltaTimeMs, float& deltaX,
80 float& deltaY) const override {
81 float speedMps = speed.getValue(SpeedUnit::MPS);
82 float dt = deltaTimeMs / 1000.0f;
83 deltaX = speedMps * std::cos(theta) * dt;
84 deltaY = speedMps * std::sin(theta) * dt;
85 }
86
87 bool onMessage(const Message<float>& msg) {
88 if (msg.origin != MessageOrigin::Vehicle) return false;
89 //  update speed and steering angle from messages
90 switch (msg.content) {
91 case MessageContent::MotorSpeed:
92 if (msg.unit != Unit::Percent) return false;
93 p_speedSource->setThrottlePercent(msg.value);
94 setSpeed(
95 p_speedSource->getSpeed()); // Assuming single motor for simplicity
96 return true;
97 case MessageContent::SteeringAngle:
98 steeringAngle = Angle(msg.value, msg.unit == Unit::AngleRadian ? AngleUnit::RAD : AngleUnit::DEG);
99 return true;
100 default:
101 return false; // Unhandled message content
102 }
103 }
104
105 void setCallback(void (*callback)(void*), void* userData) {
106 this->callback = callback;
107 this->userData = userData;
108 }
109
110 Speed getSpeed() const override { return speed; }
111 Angle getSteeringAngle() const override { return steeringAngle; }
112
113 private:
114 Distance wheelBase;
115 Speed speed;
116 Angle steeringAngle;
117 ISpeedSource* p_speedSource = nullptr;;
118 void (*callback)(void*) = nullptr;
119 void* userData = nullptr;
120};
121
122} // namespace tinyrobotics
Represents an angle with unit conversion and wrap-around support.
Definition: Angle.h:42
Represents a distance measurement with unit conversion support.
Definition: Distance.h:40
Abstract interface for 2D odometry models.
Definition: IOdometryModel2D.h:9
Interface for speed sources.
Definition: ISpeedSource.h:9
Odometry model for Ackermann, differential drive, and boat kinematics.
Definition: OdometryModel2D.h:35
void computeDeltaXY(float theta, uint32_t deltaTimeMs, float &deltaX, float &deltaY) const override
Compute position change (deltaX, deltaY) for odometry kinematics.
Definition: OdometryModel2D.h:79
Speed getSpeed() const override
Get the current speed of the vehicle.
Definition: OdometryModel2D.h:110
bool onMessage(const Message< float > &msg)
Handle an incoming message (pure virtual).
Definition: OdometryModel2D.h:87
float computeDeltaTheta(uint16_t deltaTimeMs) const override
Compute heading change (deltaTheta) for Ackermann kinematics.
Definition: OdometryModel2D.h:70
void setSpeedSource(ISpeedSource &speedSource) override
Set the speed source (e.g., encoder, estimator) for this model.
Definition: OdometryModel2D.h:41
Angle getSteeringAngle() const override
Get the current steering angle of the vehicle.
Definition: OdometryModel2D.h:111
virtual void updateSpeed(uint32_t deltaTimeMs)
Update the speed estimate based on elapsed time.
Definition: OdometryModel2D.h:58
Represents a speed measurement with unit conversion support.
Definition: Speed.h:40
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