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"
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.01)
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
236 double dGoalHeading,
237 double dActualHeading,
238 const DifferentialControlMethod eDriveMethod,
240 const bool bSquareControlInput = false,
241 const bool bCurvatureDriveAllowTurningWhileStopped = true)
242 {
243 // Create instance variables.
244 DrivePowers stOutputPowers;
245
246 // Get control output from PID controller.
247 double dTurnOutput = PID.Calculate(dActualHeading, dGoalHeading);
248
249 // Calculate drive powers from inverse kinematics of goal speed and turning adjustment.
250 switch (eDriveMethod)
251 {
252 case DifferentialControlMethod::eArcadeDrive:
253 {
254 // Based on our turn output, inverse-proportionally scale down our goal speed along a squared curve profile. This helps with pivot turns.
255 dGoalSpeed *= 1.0 - std::pow(dTurnOutput, 2);
256 // Calculate drive power with inverse kinematics.
257 stOutputPowers = CalculateArcadeDrive(dGoalSpeed, dTurnOutput, bSquareControlInput);
258 break;
259 }
260 case DifferentialControlMethod::eCurvatureDrive:
261 {
262 // Based on our turn output, inverse-proportionally scale down our goal speed along a squared curve profile. This helps with pivot turns.
263 dGoalSpeed *= 1.0 - std::pow(dTurnOutput, 2);
264 // Calculate drive power with inverse kinematics.
265 stOutputPowers = CalculateCurvatureDrive(dGoalSpeed, dTurnOutput, bCurvatureDriveAllowTurningWhileStopped, bSquareControlInput);
266 break;
267 }
268 default:
269 {
270 // Submit logger message.
271 LOG_ERROR(logging::g_qSharedLogger, "eTankDrive is not supported for the CalculateMotorPowerFromHeading() method!");
272 break;
273 }
274 }
275
276 // Return result powers.
277 return stOutputPowers;
278 }
279} // namespace diffdrive
280#endif
Defines the PIDController class.
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:74
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 CalculateTankDrive(double dLeftSpeed, double dRightSpeed, bool bSquareInputs=false)
Tank drive inverse kinematics for differential drive robots.
Definition DifferentialDrive.hpp:91
DrivePowers CalculateMotorPowerFromHeading(double dGoalSpeed, double dGoalHeading, double dActualHeading, const DifferentialControlMethod eDriveMethod, controllers::PIDController &PID, 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:235
This struct is used to store the left and right drive powers for the robot. Storing these values in a...
Definition DifferentialDrive.hpp:73