TinyRobotics
Loading...
Searching...
No Matches
AirPlane.h
1#pragma once
2
3#include "TinyRobotics/motors/Motors.h"
4#include "Vehicle.h"
5
6namespace tinyrobotics {
7
8/**
9 * @class AirPlane
10 * @ingroup vehicles
11 * @brief Simple fixed-wing airplane model with motor, rudder, elevator, and
12 * aileron control.
13 *
14 * This class abstracts the control of a basic RC airplane:
15 * - Motor (throttle) via ServoMotor (ESC)
16 * - Rudder (yaw), Elevator (pitch), and Ailerons (roll) via ServoMotor
17 *
18 * Usage Example:
19 * @code
20 * AirPlane plane;
21 * // setup pins
22 * plane.setPinsMotor(5, 6); // HBridge pins
23 * plane.setPinRudder(10); // rudder servo
24 * plane.setPinElevator(11); // elevator servo
25 * plane.setPinsAilerons(12, 13); // aileron servos
26 * // control airplane
27 * plane.setThrottle(70); // 70% throttle
28 * plane.setRudder(20); // 20 degrees left
29 * plane.setElevator(-10); // 10 degrees down
30 * plane.setAilerons(15, -15); // left up, right down
31 * @endcode
32 */
33
34template <typename T=float, typename MotorMT = BrushedMotor<T>, typename ServoMT = ServoMotor<T>>
35class AirPlane : public Vehicle<T> {
36 public:
37 enum ControlSurface {
38 Rudder = 0,
39 Elevator = 1,
40 AileronLeft = 2,
41 AileronRight = 3,
42 NumSurfaces = 4
43 };
44
45 public:
46 AirPlane() = default;
47
48 /** Attach the motor HBridge. */
49 void setPinsMotor(int in1, int in2) {
50 motor_.setPins(in1, in2);
51 motor_.setID(0); // Motor ID 0
52 }
53
54 /** Attach the rudder servo. */
55 void setPinRudder(int pin) {
56 pins_[Rudder] = pin;
57 servos_[Rudder].setPin(pin);
58 servos_[Rudder].setID(static_cast<uint8_t>(Rudder));
59 }
60
61 /** Attach the elevator servo. */
62 void setPinElevator(int pin) {
63 pins_[Elevator] = pin;
64 servos_[Elevator].setPin(pin);
65 servos_[Elevator].setID(static_cast<uint8_t>(Elevator));
66 }
67
68 /** Attach the aileron servos. */
69 void setPinsAilerons(int leftPin, int rightPin) {
70 pins_[AileronLeft] = leftPin;
71 pins_[AileronRight] = rightPin;
72 servos_[AileronLeft].setPin(leftPin);
73 servos_[AileronRight].setPin(rightPin);
74 servos_[AileronLeft].setID(static_cast<uint8_t>(AileronLeft));
75 servos_[AileronRight].setID(static_cast<uint8_t>(AileronRight));
76 }
77
78 void setPinServo(ControlSurface surface, int pin) {
79 if (surface >= 0 && surface < NumSurfaces) {
80 pins_[surface] = pin;
81 servos_[surface].setPin(pin);
82 servos_[surface].setID(static_cast<uint8_t>(surface));
83 }
84 }
85
86 /** Set throttle (0-100%) */
87 void setThrottle(int percent) {
88 percent = constrain(percent, 0, 100);
89 motor_.setSpeedPercent(percent);
90
91 // publish motor speed as message for telemetry
92 Message<float> msg(MessageContent::MotorSpeed, percent, Unit::Percent);
93 msg.origin = MessageOrigin::Motor;
94 Vehicle<T>::sendMessage(msg);
95 }
96
97 /** Set rudder angle (degrees, -30 to 30 typical) */
98 void setRudder(int angle) {
99 servos_[Rudder].setAngle(angle);
100 // publish rudder update as message for telemetry
101 Message<float> msg(MessageContent::Yaw, angle, Unit::AngleDegree);
102 msg.origin = MessageOrigin::Rudder;
103 Vehicle<T>::sendMessage(msg);
104 }
105
106 /** Set elevator angle (degrees, -30 to 30 typical) */
107 void setElevator(int angle) {
108 servos_[Elevator].setAngle(angle);
109 // publish elevator update as message for telemetry
110 Message<float> msg(MessageContent::Pitch, angle, Unit::AngleDegree);
111 msg.origin = MessageOrigin::Elevator;
112 Vehicle<T>::sendMessage(msg);
113 }
114
115 /** Set aileron angles (degrees, left and right) */
116 void setAilerons(int leftAngle, int rightAngle) {
117 servos_[AileronLeft].setAngle(leftAngle);
118 servos_[AileronRight].setAngle(rightAngle);
119 // publish aileron update as message for telemetry
120 Message<float> msgLeft(MessageContent::Roll, leftAngle, Unit::AngleDegree);
121 msgLeft.origin = MessageOrigin::Aileron;
122 msgLeft.origin_id = 0; // Left aileron
123 Vehicle<T>::sendMessage(msgLeft);
124 Message<float> msgRight(MessageContent::Roll, rightAngle,
125 Unit::AngleDegree);
126 msgRight.origin = MessageOrigin::Aileron;
127 msgRight.origin_id = 1; // Right aileron
128 Vehicle<T>::sendMessage(msgRight);
129 }
130
131 /** Reset state of all controls */
132 void end() {
137 // stop all motors
138 for (auto& motor : getMotors()) {
139 motor.end();
140 }
141 }
142
143 bool isPinsSet() const {
144 if (!motor_.isPinsSet()) return false;
145 for (const auto& s : servos_) {
146 if (!s.isPinsSet()) return false;
147 }
148 return true;
149 }
150
151 /** Set pitch (degrees): positive = nose up, negative = nose down */
152 void setPitch(int angle) { setElevator(angle); }
153
154 /** Set roll (degrees): positive = left wing up, negative = right wing up */
155 void setRoll(int angle) { setAilerons(angle, -angle); }
156
157 /** Set yaw (degrees): positive = nose left, negative = nose right */
158 void setYaw(int angle) { setRudder(angle); }
159
160 bool onMessage(const Message<float>& msg) override {
161 float angle;
162 switch (msg.content) {
163 case MessageContent::Throttle:
164 if (msg.unit != Unit::Percent) return false;
165 setThrottle(static_cast<int>(msg.value));
166 return true;
167 case MessageContent::Pitch:
168 angle = msg.value;
169 if (!toAngleDegree(angle, msg.unit, angle))
170 return false; // Invalid unit
171 setPitch(angle);
172 return true;
173 case MessageContent::Roll:
174 angle = msg.value;
175 if (!toAngleDegree(angle, msg.unit, angle))
176 return false; // Invalid unit
177 setRoll(angle);
178 return true;
179 case MessageContent::Yaw:
180 angle = msg.value;
181 if (!toAngleDegree(angle, msg.unit, angle))
182 return false; // Invalid unit
183 setYaw(angle);
184 return true;
185 default:
186 return false; // Unhandled message content
187 }
188 }
189
190 std::vector<MessageContent> getControls() const override {
191 return {MessageContent::Throttle, MessageContent::Pitch,
192 MessageContent::Roll, MessageContent::Yaw};
193 }
194
195 MotorMT& getMotor() { return motor_; }
196 ServoMT& getServo(ControlSurface surface) { return servos_[surface]; }
197
198 std::vector<IMotor<T>*> getMotors() override {
199 std::vector<IMotor<T>*> motors;
200 motors.push_back(&motor_);
201 for (auto& s : servos_) {
202 motors.push_back(&s);
203 }
204 return motors;
205 }
206
207 protected:
208 MotorMT motor_;
209 std::vector<int> pins_ = std::vector<int>(NumSurfaces, -1);
210 std::vector<ServoMT> servos_ = std::vector<ServoMT>(NumSurfaces, ServoMT());
211};
212
213} // namespace tinyrobotics
Simple fixed-wing airplane model with motor, rudder, elevator, and aileron control.
Definition: AirPlane.h:35
void setPinsAilerons(int leftPin, int rightPin)
Definition: AirPlane.h:69
void setYaw(int angle)
Definition: AirPlane.h:158
void setPinElevator(int pin)
Definition: AirPlane.h:62
void setPitch(int angle)
Definition: AirPlane.h:152
void setPinsMotor(int in1, int in2)
Definition: AirPlane.h:49
void setAilerons(int leftAngle, int rightAngle)
Definition: AirPlane.h:116
void setElevator(int angle)
Definition: AirPlane.h:107
bool isPinsSet() const
Check if the necessary pins for the vehicle's actuators have been set (pure virtual).
Definition: AirPlane.h:143
void end()
Definition: AirPlane.h:132
bool onMessage(const Message< float > &msg) override
Handle an incoming message (pure virtual).
Definition: AirPlane.h:160
void setRudder(int angle)
Definition: AirPlane.h:98
void setPinRudder(int pin)
Definition: AirPlane.h:55
void setThrottle(int percent)
Definition: AirPlane.h:87
void setRoll(int angle)
Definition: AirPlane.h:155
High-level H-Bridge motor driver class for bidirectional DC motor control.
Definition: BrushedMotor.h:36
High-level wrapper for Arduino Servo control (RC servo motors).
Definition: ServoMotor.h:40
Abstract base class for all vehicle types.
Definition: Vehicle.h:26
Generic message structure for communication, parameterized by value type.
Definition: Message.h:72