TinyRobotics
Loading...
Searching...
No Matches
DroneOdometryModel3D.h
1
2#pragma once
3#include <array>
4
5#include "TinyRobotics/communication/Message.h"
6#include "TinyRobotics/odometry/IOdometryModel3D.h"
7#include "TinyRobotics/units/Units.h"
8
9namespace tinyrobotics {
10
11/**
12 * @class DroneOdometryModel3D
13 * @ingroup odometry
14 * @brief IOdometryModel3D implementation for quadcopters/drones using motor
15 * percentages.
16 *
17 * This model computes linear and angular velocities for a quadcopter based on
18 * the percentage output (0-100%) of each motor. It assumes a standard
19 * X-configuration quadcopter with four motors:
20 * - Motor 0: Front Left
21 * - Motor 1: Front Right
22 * - Motor 2: Rear Right
23 * - Motor 3: Rear Left
24 *
25 * ## Features
26 * - Maps motor percentages to body-frame velocities for odometry integration.
27 * - Supports message-driven control via onMessage() (handles
28 * MessageContent::MotorSpeed with origin_id 0..3).
29 * - All input values are clamped to 0..100%.
30 * - Suitable for simulation, estimation, or as a reference model for real-time
31 * control.
32 *
33 * ## Notes
34 * - This model is designed for extensibility and realism, supporting
35 * multi-motor drones and robust unit-safe arithmetic.
36 * - The mapping logic is as follows:
37 * - Vertical velocity (vz) is proportional to the average of all motor
38 * percentages and scaled by maxVz.
39 * - Roll and pitch rates are proportional to left/right and front/back motor
40 * differences, scaled by maxRollRate and maxPitchRate.
41 * - Yaw rate is proportional to diagonal (CW vs CCW) motor differences,
42 * scaled by maxYawRate.
43 * - All control input values are clamped to the range 0..100% for safety and
44 * realism.
45 * - The model is message-driven: it integrates with the communication framework
46 * and updates motor percentages via MessageContent::MotorSpeed messages
47 * (origin_id 0..3).
48 * - Default parameters (maxVz, maxRollRate, maxPitchRate, maxYawRate) are
49 * chosen to be realistic for typical quadcopters, but can be configured for
50 * other drone types.
51 * - See the README and documentation for integration and usage examples.
52 *
53 * ## Usage Example
54 * @code
55 * DroneOdometryModel3D model;
56 * model.setMotorPercent(0, 60); // Front Left
57 * model.setMotorPercent(1, 60); // Front Right
58 * model.setMotorPercent(2, 60); // Rear Right
59 * model.setMotorPercent(3, 60); // Rear Left
60 * float vx, vy, vz, wx, wy, wz;
61 * model.getLinearVelocity(vx, vy, vz);
62 * model.getAngularVelocity(wx, wy, wz);
63 * @endcode
64 */
66 public:
67 static constexpr int NUM_MOTORS = 4;
68
69 /**
70 * @brief Register a callback to be invoked on relevant events (e.g., input
71 * change).
72 */
73 void registerCallback(void (*callback)(void*), void* userData) override {
74 this->callback = callback;
75 this->userData = userData;
76 }
77
78 /**
79 * @brief Construct a DroneOdometryModel3D with configurable max rates.
80 *
81 * @param maxVz Maximum vertical speed (m/s) at 100% throttle. Typical: 5
82 * m/s.
83 * @param maxRollRate Maximum roll rate (deg/s, converted to rad/s).
84 * Typical: 200 deg/s.
85 * @param maxPitchRate Maximum pitch rate (deg/s, converted to rad/s).
86 * Typical: 200 deg/s.
87 * @param maxYawRate Maximum yaw rate (deg/s, converted to rad/s). Typical:
88 * 100 deg/s.
89 */
90 DroneOdometryModel3D(float maxVz = 5.0f, float maxRollRate = 200.0f,
91 float maxPitchRate = 200.0f, float maxYawRate = 100.0f)
92 : maxVz(maxVz),
93 maxRollRate(maxRollRate * 0.01745329252f),
94 maxPitchRate(maxPitchRate * 0.01745329252f),
95 maxYawRate(maxYawRate * 0.01745329252f) {
96 motorPercent.fill(0.0f);
97 }
98
99 /**
100 * @brief Set the percentage (0..100) for a given motor (0..3).
101 */
102 void setMotorPercent(int motor, float percent) {
103 if (motor < 0 || motor >= NUM_MOTORS) return;
104 motorPercent[motor] = clamp(percent, 0.0f, 100.0f);
105 // update on last motor update to avoid multiple callbacks during batch
106 // updates
107 if (callback && motor == (NUM_MOTORS - 1)) callback(userData);
108 }
109
110 protected:
111 void (*callback)(void*) = nullptr;
112 void* userData = nullptr;
113
114 /**
115 * @brief Handle incoming motor speed messages (MessageContent::MotorSpeed,
116 * origin_id = motor index).
117 */
118 bool onMessage(const Message<float>& msg) {
119 if (msg.content == MessageContent::MotorSpeed &&
120 msg.origin_id < NUM_MOTORS) {
121 setMotorPercent(msg.origin_id, msg.value);
122 return true;
123 }
124 return false;
125 }
126
127 /**
128 * @brief Compute linear velocity (vx, vy, vz) in m/s (body frame).
129 * Only vz is modeled (vertical climb/descent), vx and vy are zero.
130 */
131 void getLinearVelocity(float& vx, float& vy, float& vz) const override {
132 // Average all motors for vertical thrust
133 float avg = 0.0f;
134 for (float p : motorPercent) avg += p;
135 avg /= NUM_MOTORS;
136 vx = 0.0f;
137 vy = 0.0f;
138 vz = (avg / 100.0f) * maxVz;
139 }
140
141 /**
142 * @brief Compute angular velocity (wx, wy, wz) in rad/s (body frame).
143 * Roll and pitch rates are proportional to left/right and front/back motor
144 * differences. Yaw rate is proportional to diagonal differences (simplified
145 * torque model).
146 */
147 void getAngularVelocity(float& wx, float& wy, float& wz) const override {
148 // Roll: left (0+3) vs right (1+2)
149 float rollInput = ((motorPercent[0] + motorPercent[3]) -
150 (motorPercent[1] + motorPercent[2])) /
151 200.0f;
152 // Pitch: front (0+1) vs rear (2+3)
153 float pitchInput = ((motorPercent[0] + motorPercent[1]) -
154 (motorPercent[2] + motorPercent[3])) /
155 200.0f;
156 // Yaw: (CW - CCW) torque, assume 0/2 are CW, 1/3 are CCW
157 float yawInput = ((motorPercent[0] + motorPercent[2]) -
158 (motorPercent[1] + motorPercent[3])) /
159 200.0f;
160 wx = rollInput * maxRollRate;
161 wy = pitchInput * maxPitchRate;
162 wz = yawInput * maxYawRate;
163 }
164
165 protected:
166 std::array<float, NUM_MOTORS> motorPercent; // 0..100 for each motor
167 float maxVz; // m/s
168 float maxRollRate; // rad/s
169 float maxPitchRate; // rad/s
170 float maxYawRate; // rad/s
171
172 static float clamp(float v, float min, float max) {
173 return (v < min) ? min : (v > max) ? max : v;
174 }
175};
176
177} // namespace tinyrobotics
IOdometryModel3D implementation for quadcopters/drones using motor percentages.
Definition: DroneOdometryModel3D.h:65
void registerCallback(void(*callback)(void *), void *userData) override
Register a callback to be invoked on relevant events (e.g., input change).
Definition: DroneOdometryModel3D.h:73
bool onMessage(const Message< float > &msg)
Handle incoming motor speed messages (MessageContent::MotorSpeed, origin_id = motor index).
Definition: DroneOdometryModel3D.h:118
void getAngularVelocity(float &wx, float &wy, float &wz) const override
Compute angular velocity (wx, wy, wz) in rad/s (body frame). Roll and pitch rates are proportional to...
Definition: DroneOdometryModel3D.h:147
DroneOdometryModel3D(float maxVz=5.0f, float maxRollRate=200.0f, float maxPitchRate=200.0f, float maxYawRate=100.0f)
Construct a DroneOdometryModel3D with configurable max rates.
Definition: DroneOdometryModel3D.h:90
void getLinearVelocity(float &vx, float &vy, float &vz) const override
Compute linear velocity (vx, vy, vz) in m/s (body frame). Only vz is modeled (vertical climb/descent)...
Definition: DroneOdometryModel3D.h:131
void setMotorPercent(int motor, float percent)
Set the percentage (0..100) for a given motor (0..3).
Definition: DroneOdometryModel3D.h:102
Abstract interface for 3D odometry models. Provides access to current linear and angular velocities f...
Definition: IOdometryModel3D.h:14
Generic message structure for communication, parameterized by value type.
Definition: Message.h:72