Autonomy Software C++ 24.5.1
Welcome to the Autonomy Software repository of the Mars Rover Design Team (MRDT) at Missouri University of Science and Technology (Missouri S&T)! API reference contains the source code and other resources for the development of the autonomy software for our Mars rover. The Autonomy Software project aims to compete in the University Rover Challenge (URC) by demonstrating advanced autonomous capabilities and robust navigation algorithms.
Loading...
Searching...
No Matches
DifferentialDrive.hpp
Go to the documentation of this file.
1
12#ifndef DIFFERENTIAL_DRIVE_HPP
13#define DIFFERENTIAL_DRIVE_HPP
14
15#include "../../AutonomyLogging.h"
16#include "../../util/NumberOperations.hpp"
17#include "../controllers/PIDController.h"
18
20#include <array>
21#include <cmath>
22
24
25
49namespace diffdrive
50{
52 // Declare public enums that are specific to and used within this namespace.
54
55 // Enum for choosing the differential drive method for certain functions.
56 // Enumerator used to specify what method of drive control to use.
57 enum class DifferentialControlMethod
58 {
59 eArcadeDrive, // Typical drive control method for flightsticks. Uses speed and turn input to determine drive powers.
60 eCurvatureDrive // Similar to arcade drive with flightsticks, but the current turning speed of the robot is dampened when moving fast.
61 };
62
63
73 {
74 public:
75 // Define public struct attributes.
76 double dLeftDrivePower;
77 double dRightDrivePower;
78 };
79
80
91 inline DrivePowers CalculateTankDrive(double dLeftSpeed, double dRightSpeed, bool bSquareInputs = false)
92 {
93 // Limit the input powers.
94 dLeftSpeed = std::clamp(dLeftSpeed, -1.0, 1.0);
95 dRightSpeed = std::clamp(dRightSpeed, -1.0, 1.0);
96
97 // Determine if we should square the inputs.
98 if (bSquareInputs)
99 {
100 // Square the inputs but keep the sign.
101 dLeftSpeed = std::copysign(dLeftSpeed * dLeftSpeed, dLeftSpeed);
102 dRightSpeed = std::copysign(dRightSpeed * dRightSpeed, dRightSpeed);
103 }
104
105 // Return result drive powers.
106 return {dLeftSpeed, dRightSpeed};
107 }
108
109
120 inline DrivePowers CalculateArcadeDrive(double dSpeed, double dRotation, const bool bSquareInputs = false)
121 {
122 // Limit the input powers.
123 dSpeed = std::clamp(dSpeed, -1.0, 1.0);
124 dRotation = std::clamp(dRotation, -1.0, 1.0);
125
126 // Determine if we should square the inputs.
127 if (bSquareInputs)
128 {
129 // Square the inputs but keep the sign.
130 dSpeed = std::copysign(dSpeed * dSpeed, dSpeed);
131 dRotation = std::copysign(dRotation * dRotation, dRotation);
132 }
133
134 // Find the maximum possible value of throttle and turn along the vector that the speed and rotation is pointing.
135 double dGreaterInput = std::max(std::abs(dSpeed), std::abs(dRotation));
136 double dLesserInput = std::min(std::abs(dSpeed), std::abs(dRotation));
137 // If the biggest input is zero, then the wheel speeds should be zero.
138 if (dGreaterInput == 0.0)
139 {
140 // Return zero drive power output.
141 return {0.0, 0.0};
142 }
143
144 // Differential drive inverse kinematics for arcade drive.
145 double dLeftSpeed = dSpeed + dRotation;
146 double dRightSpeed = dSpeed - dRotation;
147 // Desaturate the input. Normalize to (-1.0, 1.0).
148 double dSaturatedInput = (dGreaterInput + dLesserInput) / dGreaterInput;
149 dLeftSpeed /= dSaturatedInput;
150 dRightSpeed /= dSaturatedInput;
151
152 // Return result drive powers.
153 return {dLeftSpeed, dRightSpeed};
154 }
155
156
170 inline DrivePowers CalculateCurvatureDrive(double dSpeed, double dRotation, const bool bAllowTurnInPlace, const bool bSquareInputs = false)
171 {
172 // Create instance variables.
173 double dLeftSpeed = 0.0;
174 double dRightSpeed = 0.0;
175
176 // Limit the input powers.
177 dSpeed = std::clamp(dSpeed, -1.0, 1.0);
178 dRotation = std::clamp(dRotation, -1.0, 1.0);
179
180 // Determine if we should square the inputs.
181 if (bSquareInputs)
182 {
183 // Square the inputs but keep the sign.
184 dSpeed = std::copysign(dSpeed * dSpeed, dSpeed);
185 dRotation = std::copysign(dRotation * dRotation, dRotation);
186 }
187
188 // Check if turn-in-place is allowed.
189 if (bAllowTurnInPlace && dSpeed <= 0.05)
190 {
191 // Differential drive inverse kinematics for curvature drive with turn while stopped.
192 dLeftSpeed = dSpeed + dRotation;
193 dRightSpeed = dSpeed - dRotation;
194 }
195 else
196 {
197 // Differential drive inverse kinematics for curvature drive.
198 dLeftSpeed = dSpeed + std::abs(dSpeed) * dRotation;
199 dRightSpeed = dSpeed - std::abs(dSpeed) * dRotation;
200 }
201
202 // Desaturate the input. Normalize to (-1.0, 1.0).
203 double dMaxMagnitude = std::max(std::abs(dLeftSpeed), std::abs(dRightSpeed));
204 if (dMaxMagnitude > 1.0)
205 {
206 dLeftSpeed /= dMaxMagnitude;
207 dRightSpeed /= dMaxMagnitude;
208 }
209
210 // Return result drive powers.
211 return {dLeftSpeed, dRightSpeed};
212 }
213
214
238 double dGoalHeading,
239 double dActualHeading,
240 const DifferentialControlMethod eDriveMethod,
242 const bool bAlwaysProgressForward = false,
243 const bool bSquareControlInput = false,
244 const bool bCurvatureDriveAllowTurningWhileStopped = true)
245 {
246 // Create instance variables.
247 DrivePowers stOutputPowers;
248
249 // Get control output from PID controller.
250 double dTurnOutput = PID.Calculate(dActualHeading, dGoalHeading);
251
252 // Calculate drive powers from inverse kinematics of goal speed and turning adjustment.
253 switch (eDriveMethod)
254 {
255 case DifferentialControlMethod::eArcadeDrive:
256 {
257 // Check if the rover should always move forward.
258 if (!bAlwaysProgressForward)
259 {
260 // Based on our turn output, inverse-proportionally scale down our goal speed along a squared curve profile. This helps with pivot turns when given a
261 // constant speed.
262 dGoalSpeed *= 1.0 - std::pow(dTurnOutput, 2);
263 }
264 // Calculate drive power with inverse kinematics.
265 stOutputPowers = CalculateArcadeDrive(dGoalSpeed, dTurnOutput, bSquareControlInput);
266 break;
267 }
268 case DifferentialControlMethod::eCurvatureDrive:
269 {
270 // Check if the rover should always move forward.
271 if (!bAlwaysProgressForward)
272 {
273 // Based on our turn output, inverse-proportionally scale down our goal speed along a squared curve profile. This helps with pivot turns when given a
274 // constant speed.
275 dGoalSpeed *= 1.0 - std::pow(dTurnOutput, 2);
276 }
277 // Calculate drive power with inverse kinematics.
278 stOutputPowers = CalculateCurvatureDrive(dGoalSpeed, dTurnOutput, bCurvatureDriveAllowTurningWhileStopped, bSquareControlInput);
279 break;
280 }
281 default:
282 {
283 // Submit logger message.
284 LOG_ERROR(logging::g_qSharedLogger, "eTankDrive is not supported for the CalculateMotorPowerFromHeading() method!");
285 break;
286 }
287 }
288
289 // Return result powers.
290 return stOutputPowers;
291 }
292} // namespace diffdrive
293#endif
This class encapsulates the fundamental principles of Proportional-Integral-Derivative (PID) control ...
Definition PIDController.h:50
double Calculate(const double dActual, const double dSetpoint)
Calculate the next control output given the current actual and a setpoint.
Definition PIDController.cpp:77
Namespace containing algorithms related to calculating drive powers, odometry, trajectories,...
Definition DifferentialDrive.hpp:50
DrivePowers CalculateArcadeDrive(double dSpeed, double dRotation, const bool bSquareInputs=false)
Arcade drive inverse kinematics for differential drive robots.
Definition DifferentialDrive.hpp:120
DrivePowers CalculateCurvatureDrive(double dSpeed, double dRotation, const bool bAllowTurnInPlace, const bool bSquareInputs=false)
Curvature drive inverse kinematics for differential drive robots. The rotation parameter controls the...
Definition DifferentialDrive.hpp:170
DrivePowers CalculateMotorPowerFromHeading(double dGoalSpeed, double dGoalHeading, double dActualHeading, const DifferentialControlMethod eDriveMethod, controllers::PIDController &PID, const bool bAlwaysProgressForward=false, const bool bSquareControlInput=false, const bool bCurvatureDriveAllowTurningWhileStopped=true)
This function will calculate the drive powers for a given speed and absolute heading....
Definition DifferentialDrive.hpp:237
DrivePowers CalculateTankDrive(double dLeftSpeed, double dRightSpeed, bool bSquareInputs=false)
Tank drive inverse kinematics for differential drive robots.
Definition DifferentialDrive.hpp:91
This struct is used to store the left and right drive powers for the robot. Storing these values in a...
Definition DifferentialDrive.hpp:73