blob: fd43c960f1240d312e6a9351e1e5d997138f9bcd [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -08002/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
Brian Silverman41cdd3e2019-01-19 19:48:58 -08003/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "frc/RobotDrive.h"
9
10#include <algorithm>
11#include <cmath>
12
13#include <hal/HAL.h>
14
15#include "frc/GenericHID.h"
16#include "frc/Joystick.h"
17#include "frc/Talon.h"
18#include "frc/Utility.h"
19#include "frc/WPIErrors.h"
20
21using namespace frc;
22
23static std::shared_ptr<SpeedController> make_shared_nodelete(
24 SpeedController* ptr) {
25 return std::shared_ptr<SpeedController>(ptr, NullDeleter<SpeedController>());
26}
27
28RobotDrive::RobotDrive(int leftMotorChannel, int rightMotorChannel) {
29 InitRobotDrive();
30 m_rearLeftMotor = std::make_shared<Talon>(leftMotorChannel);
31 m_rearRightMotor = std::make_shared<Talon>(rightMotorChannel);
32 SetLeftRightMotorOutputs(0.0, 0.0);
33}
34
35RobotDrive::RobotDrive(int frontLeftMotor, int rearLeftMotor,
36 int frontRightMotor, int rearRightMotor) {
37 InitRobotDrive();
38 m_rearLeftMotor = std::make_shared<Talon>(rearLeftMotor);
39 m_rearRightMotor = std::make_shared<Talon>(rearRightMotor);
40 m_frontLeftMotor = std::make_shared<Talon>(frontLeftMotor);
41 m_frontRightMotor = std::make_shared<Talon>(frontRightMotor);
42 SetLeftRightMotorOutputs(0.0, 0.0);
43}
44
45RobotDrive::RobotDrive(SpeedController* leftMotor,
46 SpeedController* rightMotor) {
47 InitRobotDrive();
48 if (leftMotor == nullptr || rightMotor == nullptr) {
49 wpi_setWPIError(NullParameter);
50 m_rearLeftMotor = m_rearRightMotor = nullptr;
51 return;
52 }
53 m_rearLeftMotor = make_shared_nodelete(leftMotor);
54 m_rearRightMotor = make_shared_nodelete(rightMotor);
55}
56
57RobotDrive::RobotDrive(SpeedController& leftMotor,
58 SpeedController& rightMotor) {
59 InitRobotDrive();
60 m_rearLeftMotor = make_shared_nodelete(&leftMotor);
61 m_rearRightMotor = make_shared_nodelete(&rightMotor);
62}
63
64RobotDrive::RobotDrive(std::shared_ptr<SpeedController> leftMotor,
65 std::shared_ptr<SpeedController> rightMotor) {
66 InitRobotDrive();
67 if (leftMotor == nullptr || rightMotor == nullptr) {
68 wpi_setWPIError(NullParameter);
69 m_rearLeftMotor = m_rearRightMotor = nullptr;
70 return;
71 }
72 m_rearLeftMotor = leftMotor;
73 m_rearRightMotor = rightMotor;
74}
75
76RobotDrive::RobotDrive(SpeedController* frontLeftMotor,
77 SpeedController* rearLeftMotor,
78 SpeedController* frontRightMotor,
79 SpeedController* rearRightMotor) {
80 InitRobotDrive();
81 if (frontLeftMotor == nullptr || rearLeftMotor == nullptr ||
82 frontRightMotor == nullptr || rearRightMotor == nullptr) {
83 wpi_setWPIError(NullParameter);
84 return;
85 }
86 m_frontLeftMotor = make_shared_nodelete(frontLeftMotor);
87 m_rearLeftMotor = make_shared_nodelete(rearLeftMotor);
88 m_frontRightMotor = make_shared_nodelete(frontRightMotor);
89 m_rearRightMotor = make_shared_nodelete(rearRightMotor);
90}
91
92RobotDrive::RobotDrive(SpeedController& frontLeftMotor,
93 SpeedController& rearLeftMotor,
94 SpeedController& frontRightMotor,
95 SpeedController& rearRightMotor) {
96 InitRobotDrive();
97 m_frontLeftMotor = make_shared_nodelete(&frontLeftMotor);
98 m_rearLeftMotor = make_shared_nodelete(&rearLeftMotor);
99 m_frontRightMotor = make_shared_nodelete(&frontRightMotor);
100 m_rearRightMotor = make_shared_nodelete(&rearRightMotor);
101}
102
103RobotDrive::RobotDrive(std::shared_ptr<SpeedController> frontLeftMotor,
104 std::shared_ptr<SpeedController> rearLeftMotor,
105 std::shared_ptr<SpeedController> frontRightMotor,
106 std::shared_ptr<SpeedController> rearRightMotor) {
107 InitRobotDrive();
108 if (frontLeftMotor == nullptr || rearLeftMotor == nullptr ||
109 frontRightMotor == nullptr || rearRightMotor == nullptr) {
110 wpi_setWPIError(NullParameter);
111 return;
112 }
113 m_frontLeftMotor = frontLeftMotor;
114 m_rearLeftMotor = rearLeftMotor;
115 m_frontRightMotor = frontRightMotor;
116 m_rearRightMotor = rearRightMotor;
117}
118
119void RobotDrive::Drive(double outputMagnitude, double curve) {
120 double leftOutput, rightOutput;
121 static bool reported = false;
122 if (!reported) {
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800123 HAL_Report(HALUsageReporting::kResourceType_RobotDrive,
124 HALUsageReporting::kRobotDrive_ArcadeRatioCurve, GetNumMotors());
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800125 reported = true;
126 }
127
128 if (curve < 0) {
129 double value = std::log(-curve);
130 double ratio = (value - m_sensitivity) / (value + m_sensitivity);
131 if (ratio == 0) ratio = .0000000001;
132 leftOutput = outputMagnitude / ratio;
133 rightOutput = outputMagnitude;
134 } else if (curve > 0) {
135 double value = std::log(curve);
136 double ratio = (value - m_sensitivity) / (value + m_sensitivity);
137 if (ratio == 0) ratio = .0000000001;
138 leftOutput = outputMagnitude;
139 rightOutput = outputMagnitude / ratio;
140 } else {
141 leftOutput = outputMagnitude;
142 rightOutput = outputMagnitude;
143 }
144 SetLeftRightMotorOutputs(leftOutput, rightOutput);
145}
146
147void RobotDrive::TankDrive(GenericHID* leftStick, GenericHID* rightStick,
148 bool squaredInputs) {
149 if (leftStick == nullptr || rightStick == nullptr) {
150 wpi_setWPIError(NullParameter);
151 return;
152 }
153 TankDrive(leftStick->GetY(), rightStick->GetY(), squaredInputs);
154}
155
156void RobotDrive::TankDrive(GenericHID& leftStick, GenericHID& rightStick,
157 bool squaredInputs) {
158 TankDrive(leftStick.GetY(), rightStick.GetY(), squaredInputs);
159}
160
161void RobotDrive::TankDrive(GenericHID* leftStick, int leftAxis,
162 GenericHID* rightStick, int rightAxis,
163 bool squaredInputs) {
164 if (leftStick == nullptr || rightStick == nullptr) {
165 wpi_setWPIError(NullParameter);
166 return;
167 }
168 TankDrive(leftStick->GetRawAxis(leftAxis), rightStick->GetRawAxis(rightAxis),
169 squaredInputs);
170}
171
172void RobotDrive::TankDrive(GenericHID& leftStick, int leftAxis,
173 GenericHID& rightStick, int rightAxis,
174 bool squaredInputs) {
175 TankDrive(leftStick.GetRawAxis(leftAxis), rightStick.GetRawAxis(rightAxis),
176 squaredInputs);
177}
178
179void RobotDrive::TankDrive(double leftValue, double rightValue,
180 bool squaredInputs) {
181 static bool reported = false;
182 if (!reported) {
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800183 HAL_Report(HALUsageReporting::kResourceType_RobotDrive,
184 HALUsageReporting::kRobotDrive_Tank, GetNumMotors());
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800185 reported = true;
186 }
187
188 leftValue = Limit(leftValue);
189 rightValue = Limit(rightValue);
190
191 // square the inputs (while preserving the sign) to increase fine control
192 // while permitting full power
193 if (squaredInputs) {
194 leftValue = std::copysign(leftValue * leftValue, leftValue);
195 rightValue = std::copysign(rightValue * rightValue, rightValue);
196 }
197
198 SetLeftRightMotorOutputs(leftValue, rightValue);
199}
200
201void RobotDrive::ArcadeDrive(GenericHID* stick, bool squaredInputs) {
202 // simply call the full-featured ArcadeDrive with the appropriate values
203 ArcadeDrive(stick->GetY(), stick->GetX(), squaredInputs);
204}
205
206void RobotDrive::ArcadeDrive(GenericHID& stick, bool squaredInputs) {
207 // simply call the full-featured ArcadeDrive with the appropriate values
208 ArcadeDrive(stick.GetY(), stick.GetX(), squaredInputs);
209}
210
211void RobotDrive::ArcadeDrive(GenericHID* moveStick, int moveAxis,
212 GenericHID* rotateStick, int rotateAxis,
213 bool squaredInputs) {
214 double moveValue = moveStick->GetRawAxis(moveAxis);
215 double rotateValue = rotateStick->GetRawAxis(rotateAxis);
216
217 ArcadeDrive(moveValue, rotateValue, squaredInputs);
218}
219
220void RobotDrive::ArcadeDrive(GenericHID& moveStick, int moveAxis,
221 GenericHID& rotateStick, int rotateAxis,
222 bool squaredInputs) {
223 double moveValue = moveStick.GetRawAxis(moveAxis);
224 double rotateValue = rotateStick.GetRawAxis(rotateAxis);
225
226 ArcadeDrive(moveValue, rotateValue, squaredInputs);
227}
228
229void RobotDrive::ArcadeDrive(double moveValue, double rotateValue,
230 bool squaredInputs) {
231 static bool reported = false;
232 if (!reported) {
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800233 HAL_Report(HALUsageReporting::kResourceType_RobotDrive,
234 HALUsageReporting::kRobotDrive_ArcadeStandard, GetNumMotors());
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800235 reported = true;
236 }
237
238 // local variables to hold the computed PWM values for the motors
239 double leftMotorOutput;
240 double rightMotorOutput;
241
242 moveValue = Limit(moveValue);
243 rotateValue = Limit(rotateValue);
244
245 // square the inputs (while preserving the sign) to increase fine control
246 // while permitting full power
247 if (squaredInputs) {
248 moveValue = std::copysign(moveValue * moveValue, moveValue);
249 rotateValue = std::copysign(rotateValue * rotateValue, rotateValue);
250 }
251
252 if (moveValue > 0.0) {
253 if (rotateValue > 0.0) {
254 leftMotorOutput = moveValue - rotateValue;
255 rightMotorOutput = std::max(moveValue, rotateValue);
256 } else {
257 leftMotorOutput = std::max(moveValue, -rotateValue);
258 rightMotorOutput = moveValue + rotateValue;
259 }
260 } else {
261 if (rotateValue > 0.0) {
262 leftMotorOutput = -std::max(-moveValue, rotateValue);
263 rightMotorOutput = moveValue + rotateValue;
264 } else {
265 leftMotorOutput = moveValue - rotateValue;
266 rightMotorOutput = -std::max(-moveValue, -rotateValue);
267 }
268 }
269 SetLeftRightMotorOutputs(leftMotorOutput, rightMotorOutput);
270}
271
272void RobotDrive::MecanumDrive_Cartesian(double x, double y, double rotation,
273 double gyroAngle) {
274 static bool reported = false;
275 if (!reported) {
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800276 HAL_Report(HALUsageReporting::kResourceType_RobotDrive,
277 HALUsageReporting::kRobotDrive_MecanumCartesian, GetNumMotors());
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800278 reported = true;
279 }
280
281 double xIn = x;
282 double yIn = y;
283 // Negate y for the joystick.
284 yIn = -yIn;
285 // Compenstate for gyro angle.
286 RotateVector(xIn, yIn, gyroAngle);
287
288 double wheelSpeeds[kMaxNumberOfMotors];
289 wheelSpeeds[kFrontLeftMotor] = xIn + yIn + rotation;
290 wheelSpeeds[kFrontRightMotor] = -xIn + yIn - rotation;
291 wheelSpeeds[kRearLeftMotor] = -xIn + yIn + rotation;
292 wheelSpeeds[kRearRightMotor] = xIn + yIn - rotation;
293
294 Normalize(wheelSpeeds);
295
296 m_frontLeftMotor->Set(wheelSpeeds[kFrontLeftMotor] * m_maxOutput);
297 m_frontRightMotor->Set(wheelSpeeds[kFrontRightMotor] * m_maxOutput);
298 m_rearLeftMotor->Set(wheelSpeeds[kRearLeftMotor] * m_maxOutput);
299 m_rearRightMotor->Set(wheelSpeeds[kRearRightMotor] * m_maxOutput);
300
301 Feed();
302}
303
304void RobotDrive::MecanumDrive_Polar(double magnitude, double direction,
305 double rotation) {
306 static bool reported = false;
307 if (!reported) {
James Kuszmaul4f3ad3c2019-12-01 16:35:21 -0800308 HAL_Report(HALUsageReporting::kResourceType_RobotDrive,
309 HALUsageReporting::kRobotDrive_MecanumPolar, GetNumMotors());
Brian Silverman41cdd3e2019-01-19 19:48:58 -0800310 reported = true;
311 }
312
313 // Normalized for full power along the Cartesian axes.
314 magnitude = Limit(magnitude) * std::sqrt(2.0);
315 // The rollers are at 45 degree angles.
316 double dirInRad = (direction + 45.0) * 3.14159 / 180.0;
317 double cosD = std::cos(dirInRad);
318 double sinD = std::sin(dirInRad);
319
320 double wheelSpeeds[kMaxNumberOfMotors];
321 wheelSpeeds[kFrontLeftMotor] = sinD * magnitude + rotation;
322 wheelSpeeds[kFrontRightMotor] = cosD * magnitude - rotation;
323 wheelSpeeds[kRearLeftMotor] = cosD * magnitude + rotation;
324 wheelSpeeds[kRearRightMotor] = sinD * magnitude - rotation;
325
326 Normalize(wheelSpeeds);
327
328 m_frontLeftMotor->Set(wheelSpeeds[kFrontLeftMotor] * m_maxOutput);
329 m_frontRightMotor->Set(wheelSpeeds[kFrontRightMotor] * m_maxOutput);
330 m_rearLeftMotor->Set(wheelSpeeds[kRearLeftMotor] * m_maxOutput);
331 m_rearRightMotor->Set(wheelSpeeds[kRearRightMotor] * m_maxOutput);
332
333 Feed();
334}
335
336void RobotDrive::HolonomicDrive(double magnitude, double direction,
337 double rotation) {
338 MecanumDrive_Polar(magnitude, direction, rotation);
339}
340
341void RobotDrive::SetLeftRightMotorOutputs(double leftOutput,
342 double rightOutput) {
343 wpi_assert(m_rearLeftMotor != nullptr && m_rearRightMotor != nullptr);
344
345 if (m_frontLeftMotor != nullptr)
346 m_frontLeftMotor->Set(Limit(leftOutput) * m_maxOutput);
347 m_rearLeftMotor->Set(Limit(leftOutput) * m_maxOutput);
348
349 if (m_frontRightMotor != nullptr)
350 m_frontRightMotor->Set(-Limit(rightOutput) * m_maxOutput);
351 m_rearRightMotor->Set(-Limit(rightOutput) * m_maxOutput);
352
353 Feed();
354}
355
356void RobotDrive::SetInvertedMotor(MotorType motor, bool isInverted) {
357 if (motor < 0 || motor > 3) {
358 wpi_setWPIError(InvalidMotorIndex);
359 return;
360 }
361 switch (motor) {
362 case kFrontLeftMotor:
363 m_frontLeftMotor->SetInverted(isInverted);
364 break;
365 case kFrontRightMotor:
366 m_frontRightMotor->SetInverted(isInverted);
367 break;
368 case kRearLeftMotor:
369 m_rearLeftMotor->SetInverted(isInverted);
370 break;
371 case kRearRightMotor:
372 m_rearRightMotor->SetInverted(isInverted);
373 break;
374 }
375}
376
377void RobotDrive::SetSensitivity(double sensitivity) {
378 m_sensitivity = sensitivity;
379}
380
381void RobotDrive::SetMaxOutput(double maxOutput) { m_maxOutput = maxOutput; }
382
383void RobotDrive::GetDescription(wpi::raw_ostream& desc) const {
384 desc << "RobotDrive";
385}
386
387void RobotDrive::StopMotor() {
388 if (m_frontLeftMotor != nullptr) m_frontLeftMotor->StopMotor();
389 if (m_frontRightMotor != nullptr) m_frontRightMotor->StopMotor();
390 if (m_rearLeftMotor != nullptr) m_rearLeftMotor->StopMotor();
391 if (m_rearRightMotor != nullptr) m_rearRightMotor->StopMotor();
392 Feed();
393}
394
395void RobotDrive::InitRobotDrive() { SetSafetyEnabled(true); }
396
397double RobotDrive::Limit(double number) {
398 if (number > 1.0) {
399 return 1.0;
400 }
401 if (number < -1.0) {
402 return -1.0;
403 }
404 return number;
405}
406
407void RobotDrive::Normalize(double* wheelSpeeds) {
408 double maxMagnitude = std::fabs(wheelSpeeds[0]);
409 for (int i = 1; i < kMaxNumberOfMotors; i++) {
410 double temp = std::fabs(wheelSpeeds[i]);
411 if (maxMagnitude < temp) maxMagnitude = temp;
412 }
413 if (maxMagnitude > 1.0) {
414 for (int i = 0; i < kMaxNumberOfMotors; i++) {
415 wheelSpeeds[i] = wheelSpeeds[i] / maxMagnitude;
416 }
417 }
418}
419
420void RobotDrive::RotateVector(double& x, double& y, double angle) {
421 double cosA = std::cos(angle * (3.14159 / 180.0));
422 double sinA = std::sin(angle * (3.14159 / 180.0));
423 double xOut = x * cosA - y * sinA;
424 double yOut = x * sinA + y * cosA;
425 x = xOut;
426 y = yOut;
427}