TinyRobotics
Loading...
Searching...
No Matches
CarDifferential.h
1#include <algorithm>
2#pragma once
3
4#include "TinyRobotics/motors/Motors.h"
5#include "Vehicle.h"
6
7namespace tinyrobotics {
8
9/**
10 * @class CarDifferential
11 * @ingroup vehicles
12 * @brief Car model with differential drive. The direction is controlled by
13 * adjusting the speed of the motors. Even motors are on the left side, odd
14 * motors are on the right side.
15 *
16 * This class abstracts a simple N-wheel-drive car:
17 * - N motor count (e.g. 4: front left, front right, rear left, rear right) via
18 * HBridge
19 * - No steering servo: direction is controlled by varying motor speeds
20 *
21 * Usage Example:
22 * @code
23 * CarDifferentialWD<4> car;
24 * car.setPins(0, 2, 3); // motor 0 (front left): in1=2, in2=3
25 * car.setPins(1, 5, 6); // motor 1 (front right): in1=5, in2=6
26 * car.setPins(2, 8, 9); // motor 2 (rear left): in1=8, in2=9
27 * car.setPins(3, 11, 12); // motor 3 (rear right): in1=11, in2=12
28 * car.setSpeed(60); // 60% forward
29 * car.setTurn(30); // turn right by slowing left motors
30 * car.end(); // brake all motors
31 * @endcode
32 */
33
34template <size_t N = 4, typename T=float, typename MotorMT = BrushedMotor<T>>
35class CarDifferential : public Vehicle<T> {
36 public:
37 CarDifferential() : speed_(0), turn_(0) {}
38
39 /**
40 * @brief Set the pins for a specific motor (0=front left, 1=front right,
41 * 2=rear left, 3=rear right)
42 */
43 void setPins(int motor, int in1, int in2) {
44 if (motor >= 0 && motor < 4) {
45 motors_[motor].setPins(in1, in2);
46 motors_[motor].setID((uint8_t)motor);
47 }
48 }
49
50 /**
51 * @brief Set forward/reverse speed for all motors (percent, -100 to 100).
52 * Positive = forward, negative = reverse.
53 */
54 void setSpeed(float percent) {
55 speed_ = constrain(percent * Vehicle<T>::getSpeedFactor(), -100, 100);
57 }
58
59 /**
60 * @brief Set turn (percent, -100 to 100). Positive = right, negative = left.
61 * This slows down the motors on one side to turn the car.
62 */
63 void setSteeringAgle(float angle) {
64 float percent = map(angle, -45.0f, 45.0f, -100.0f, 100.0f); // Map angle to turn percent
65 turn_ = constrain(percent, -100.0f, 100.0f);
67 }
68
69 void setSteeringAngle(Angle angle) {
70 setSteeringAngle(static_cast<int>(angle.getValue(AngleUnit::DEG)));
71 }
72
73 /**
74 * @brief Stop all motors and reset speed and turn state.
75 */
76 void end() override {
79 // stop all motors
80 for (int i = 0; i < 4; ++i) {
81 motors_[i].end();
82 }
83 }
84
85 /**
86 * @brief Set a calibration gain for a specific motor (default 1.0).
87 * @param motor Motor index (0=front left, 1=front right, 2=rear left, 3=rear
88 * right)
89 * @param gain Gain factor (e.g., 1.05 for +5% output)
90 */
91 void setMotorGain(int motor, float gain) {
92 if (motor >= 0 && motor < 4) {
93 motorGain_[motor] = gain;
94 }
95 }
96
97 bool isPinsSet() const {
98 for (int i = 0; i < 4; ++i) {
99 if (!motors_[i].isPinsSet()) return false;
100 }
101 return true;
102 }
103
104 bool onMessage(const Message<float>& msg) override {
105 switch (msg.content) {
106 case MessageContent::Throttle:
107 if (msg.unit != Unit::Percent) return false;
108 setSpeed(static_cast<int>(msg.value));
109 return true;
110 case MessageContent::SteeringAngle:
111 float angle = msg.value;
112 if (!toAngleDegree(angle, msg.unit, angle))
113 return false; // Invalid unit
114 this->setSteeringAgle(angle);
115 return true;
116 case MessageContent::Obstacle:
117 Vehicle<T>::setSpeedFactor(0);
118 return true;
119 default:
120 return false; // Unhandled message content
121 }
122 }
123
124 std::vector<MessageContent> getControls() const override {
125 return {MessageContent::Throttle, MessageContent::SteeringAngle};
126 }
127
128 MotorMT& getMotor(size_t index) { return motors_[index % N]; }
129
130 std::vector<IMotor<T>*> getMotors() override {
131 std::vector<IMotor<T>*> motors;
132 for (int i = 0; i < N; ++i) {
133 motors.push_back(&motors_[i]);
134 }
135 return motors;
136 }
137
138 protected:
139 MotorMT motors_[N];
140 float motorGain_[N] = {1.0f, 1.0f, 1.0f, 1.0f};
141 float speed_, turn_;
142
143 /**
144 * @brief Update all motors based on speed and turn.
145 *
146 * - m1: front left
147 * - m2: front right
148 * - m3: rear left
149 * - m4: rear right
150 *
151 * To turn right, left motors go slower, right motors go faster (and vice
152 * versa).
153 */
154 void updateMotors() {
155 int left = speed_ - turn_;
156 int right = speed_ + turn_;
157 float speed[4];
158 for (int i = 0; i < 4; ++i) {
159 speed[i] = (i % 2 == 0) ? left * motorGain_[i] : right * motorGain_[i];
160 speed[i] = constrain(speed[i], -100, 100);
161 }
162
163 // update speed
164 for (int i = 0; i < 4; ++i) {
165 motors_[i].setSpeedPercent(speed[i]);
166 }
167
168 // publish motor speeds as messages for telemetry
169 for (int i = 0; i < 4; ++i) {
170 Message<float> msg(MessageContent::MotorSpeed, speed[i], Unit::Percent);
171 msg.origin = MessageOrigin::Vehicle;
172 msg.origin_id = i; // Motor index
173 Vehicle<T>::sendMessage(msg);
174 }
175 }
176};
177
178} // namespace tinyrobotics
Represents an angle with unit conversion and wrap-around support.
Definition: Angle.h:42
High-level H-Bridge motor driver class for bidirectional DC motor control.
Definition: BrushedMotor.h:36
Car model with differential drive. The direction is controlled by adjusting the speed of the motors....
Definition: CarDifferential.h:35
void setSpeed(float percent)
Set forward/reverse speed for all motors (percent, -100 to 100). Positive = forward,...
Definition: CarDifferential.h:54
void setMotorGain(int motor, float gain)
Set a calibration gain for a specific motor (default 1.0).
Definition: CarDifferential.h:91
void end() override
Stop all motors and reset speed and turn state.
Definition: CarDifferential.h:76
void setSteeringAgle(float angle)
Set turn (percent, -100 to 100). Positive = right, negative = left. This slows down the motors on one...
Definition: CarDifferential.h:63
void updateMotors()
Update all motors based on speed and turn.
Definition: CarDifferential.h:154
bool isPinsSet() const
Check if the necessary pins for the vehicle's actuators have been set (pure virtual).
Definition: CarDifferential.h:97
bool onMessage(const Message< float > &msg) override
Handle an incoming message (pure virtual).
Definition: CarDifferential.h:104
void setPins(int motor, int in1, int in2)
Set the pins for a specific motor (0=front left, 1=front right, 2=rear left, 3=rear right)
Definition: CarDifferential.h:43
Abstract base class for all vehicle types.
Definition: Vehicle.h:26
AngleUnit
Supported angle units for conversion and representation.
Definition: Angle.h:11
Generic message structure for communication, parameterized by value type.
Definition: Message.h:72