blob: 89744653c26f83d5c05ec7f8d1b7bfad29a60b30 [file] [log] [blame]
Brian Silvermanf7f267a2017-02-04 16:16:08 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2008-2017. All Rights Reserved. */
3/* 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 "RobotDrive.h"
9
10#include <algorithm>
11#include <cmath>
12
13#include "GenericHID.h"
14#include "Joystick.h"
15#include "Talon.h"
16#include "Utility.h"
17#include "WPIErrors.h"
18
19using namespace frc;
20
21const int RobotDrive::kMaxNumberOfMotors;
22
23static auto make_shared_nodelete(SpeedController* ptr) {
24 return std::shared_ptr<SpeedController>(ptr, NullDeleter<SpeedController>());
25}
26
27/*
28 * Driving functions.
29 *
30 * These functions provide an interface to multiple motors that is used for C
31 * programming.
32 * The Drive(speed, direction) function is the main part of the set that makes
33 * it easy to set speeds and direction independently in one call.
34 */
35
36/**
37 * Common function to initialize all the robot drive constructors.
38 * Create a motor safety object (the real reason for the common code) and
39 * initialize all the motor assignments. The default timeout is set for the
40 * robot drive.
41 */
42void RobotDrive::InitRobotDrive() {
43 // FIXME: m_safetyHelper = new MotorSafetyHelper(this);
44 // FIXME: m_safetyHelper->SetSafetyEnabled(true);
45}
46
47/**
48 * Constructor for RobotDrive with 2 motors specified with channel numbers.
49 *
50 * Set up parameters for a two wheel drive system where the
51 * left and right motor pwm channels are specified in the call.
52 * This call assumes Talons for controlling the motors.
53 *
54 * @param leftMotorChannel The PWM channel number that drives the left motor.
55 * @param rightMotorChannel The PWM channel number that drives the right motor.
56 */
57RobotDrive::RobotDrive(int leftMotorChannel, int rightMotorChannel) {
58 InitRobotDrive();
59 m_rearLeftMotor = std::make_shared<Talon>(leftMotorChannel);
60 m_rearRightMotor = std::make_shared<Talon>(rightMotorChannel);
61 SetLeftRightMotorOutputs(0.0, 0.0);
62 m_deleteSpeedControllers = true;
63}
64
65/**
66 * Constructor for RobotDrive with 4 motors specified with channel numbers.
67 *
68 * Set up parameters for a four wheel drive system where all four motor
69 * pwm channels are specified in the call.
70 * This call assumes Talons for controlling the motors.
71 *
72 * @param frontLeftMotor Front left motor channel number
73 * @param rearLeftMotor Rear Left motor channel number
74 * @param frontRightMotor Front right motor channel number
75 * @param rearRightMotor Rear Right motor channel number
76 */
77RobotDrive::RobotDrive(int frontLeftMotor, int rearLeftMotor,
78 int frontRightMotor, int rearRightMotor) {
79 InitRobotDrive();
80 m_rearLeftMotor = std::make_shared<Talon>(rearLeftMotor);
81 m_rearRightMotor = std::make_shared<Talon>(rearRightMotor);
82 m_frontLeftMotor = std::make_shared<Talon>(frontLeftMotor);
83 m_frontRightMotor = std::make_shared<Talon>(frontRightMotor);
84 SetLeftRightMotorOutputs(0.0, 0.0);
85 m_deleteSpeedControllers = true;
86}
87
88/**
89 * Constructor for RobotDrive with 2 motors specified as SpeedController
90 * objects.
91 *
92 * The SpeedController version of the constructor enables programs to use the
93 * RobotDrive classes with subclasses of the SpeedController objects, for
94 * example, versions with ramping or reshaping of the curve to suit motor bias
95 * or deadband elimination.
96 *
97 * @param leftMotor The left SpeedController object used to drive the robot.
98 * @param rightMotor the right SpeedController object used to drive the robot.
99 */
100RobotDrive::RobotDrive(SpeedController* leftMotor,
101 SpeedController* rightMotor) {
102 InitRobotDrive();
103 if (leftMotor == nullptr || rightMotor == nullptr) {
104 wpi_setWPIError(NullParameter);
105 m_rearLeftMotor = m_rearRightMotor = nullptr;
106 return;
107 }
108 m_rearLeftMotor = make_shared_nodelete(leftMotor);
109 m_rearRightMotor = make_shared_nodelete(rightMotor);
110}
111
112// TODO: Change to rvalue references & move syntax.
113RobotDrive::RobotDrive(SpeedController& leftMotor,
114 SpeedController& rightMotor) {
115 InitRobotDrive();
116 m_rearLeftMotor = make_shared_nodelete(&leftMotor);
117 m_rearRightMotor = make_shared_nodelete(&rightMotor);
118}
119
120RobotDrive::RobotDrive(std::shared_ptr<SpeedController> leftMotor,
121 std::shared_ptr<SpeedController> rightMotor) {
122 InitRobotDrive();
123 if (leftMotor == nullptr || rightMotor == nullptr) {
124 wpi_setWPIError(NullParameter);
125 m_rearLeftMotor = m_rearRightMotor = nullptr;
126 return;
127 }
128 m_rearLeftMotor = leftMotor;
129 m_rearRightMotor = rightMotor;
130}
131
132/**
133 * Constructor for RobotDrive with 4 motors specified as SpeedController
134 * objects.
135 *
136 * Speed controller input version of RobotDrive (see previous comments).
137 *
138 * @param rearLeftMotor The back left SpeedController object used to drive the
139 * robot.
140 * @param frontLeftMotor The front left SpeedController object used to drive
141 * the robot
142 * @param rearRightMotor The back right SpeedController object used to drive
143 * the robot.
144 * @param frontRightMotor The front right SpeedController object used to drive
145 * the robot.
146 */
147RobotDrive::RobotDrive(SpeedController* frontLeftMotor,
148 SpeedController* rearLeftMotor,
149 SpeedController* frontRightMotor,
150 SpeedController* rearRightMotor) {
151 InitRobotDrive();
152 if (frontLeftMotor == nullptr || rearLeftMotor == nullptr ||
153 frontRightMotor == nullptr || rearRightMotor == nullptr) {
154 wpi_setWPIError(NullParameter);
155 return;
156 }
157 m_frontLeftMotor = make_shared_nodelete(frontLeftMotor);
158 m_rearLeftMotor = make_shared_nodelete(rearLeftMotor);
159 m_frontRightMotor = make_shared_nodelete(frontRightMotor);
160 m_rearRightMotor = make_shared_nodelete(rearRightMotor);
161}
162
163RobotDrive::RobotDrive(SpeedController& frontLeftMotor,
164 SpeedController& rearLeftMotor,
165 SpeedController& frontRightMotor,
166 SpeedController& rearRightMotor) {
167 InitRobotDrive();
168 m_frontLeftMotor = make_shared_nodelete(&frontLeftMotor);
169 m_rearLeftMotor = make_shared_nodelete(&rearLeftMotor);
170 m_frontRightMotor = make_shared_nodelete(&frontRightMotor);
171 m_rearRightMotor = make_shared_nodelete(&rearRightMotor);
172}
173
174RobotDrive::RobotDrive(std::shared_ptr<SpeedController> frontLeftMotor,
175 std::shared_ptr<SpeedController> rearLeftMotor,
176 std::shared_ptr<SpeedController> frontRightMotor,
177 std::shared_ptr<SpeedController> rearRightMotor) {
178 InitRobotDrive();
179 if (frontLeftMotor == nullptr || rearLeftMotor == nullptr ||
180 frontRightMotor == nullptr || rearRightMotor == nullptr) {
181 wpi_setWPIError(NullParameter);
182 return;
183 }
184 m_frontLeftMotor = frontLeftMotor;
185 m_rearLeftMotor = rearLeftMotor;
186 m_frontRightMotor = frontRightMotor;
187 m_rearRightMotor = rearRightMotor;
188}
189
190/**
191 * Drive the motors at "outputMagnitude" and "curve".
192 * Both outputMagnitude and curve are -1.0 to +1.0 values, where 0.0 represents
193 * stopped and not turning. curve < 0 will turn left and curve > 0 will turn
194 * right.
195 *
196 * The algorithm for steering provides a constant turn radius for any normal
197 * speed range, both forward and backward. Increasing m_sensitivity causes
198 * sharper turns for fixed values of curve.
199 *
200 * This function will most likely be used in an autonomous routine.
201 *
202 * @param outputMagnitude The speed setting for the outside wheel in a turn,
203 * forward or backwards, +1 to -1.
204 * @param curve The rate of turn, constant for different forward
205 * speeds. Set curve < 0 for left turn or curve > 0 for
206 * right turn. Set curve = e^(-r/w) to get a turn radius
207 * r for wheelbase w of your robot. Conversely, turn
208 * radius r = -ln(curve)*w for a given value of curve and
209 * wheelbase w.
210 */
211void RobotDrive::Drive(double outputMagnitude, double curve) {
212 double leftOutput, rightOutput;
213 static bool reported = false;
214 if (!reported) {
215 reported = true;
216 }
217
218 if (curve < 0) {
219 double value = std::log(-curve);
220 double ratio = (value - m_sensitivity) / (value + m_sensitivity);
221 if (ratio == 0) ratio = .0000000001;
222 leftOutput = outputMagnitude / ratio;
223 rightOutput = outputMagnitude;
224 } else if (curve > 0) {
225 double value = std::log(curve);
226 double ratio = (value - m_sensitivity) / (value + m_sensitivity);
227 if (ratio == 0) ratio = .0000000001;
228 leftOutput = outputMagnitude;
229 rightOutput = outputMagnitude / ratio;
230 } else {
231 leftOutput = outputMagnitude;
232 rightOutput = outputMagnitude;
233 }
234 SetLeftRightMotorOutputs(leftOutput, rightOutput);
235}
236
237/**
238 * Provide tank steering using the stored robot configuration.
239 *
240 * Drive the robot using two joystick inputs. The Y-axis will be selected from
241 * each Joystick object.
242 *
243 * @param leftStick The joystick to control the left side of the robot.
244 * @param rightStick The joystick to control the right side of the robot.
245 */
246void RobotDrive::TankDrive(GenericHID* leftStick, GenericHID* rightStick,
247 bool squaredInputs) {
248 if (leftStick == nullptr || rightStick == nullptr) {
249 wpi_setWPIError(NullParameter);
250 return;
251 }
252 TankDrive(leftStick->GetY(), rightStick->GetY(), squaredInputs);
253}
254
255void RobotDrive::TankDrive(GenericHID& leftStick, GenericHID& rightStick,
256 bool squaredInputs) {
257 TankDrive(leftStick.GetY(), rightStick.GetY(), squaredInputs);
258}
259
260/**
261 * Provide tank steering using the stored robot configuration.
262 *
263 * This function lets you pick the axis to be used on each Joystick object for
264 * the left and right sides of the robot.
265 *
266 * @param leftStick The Joystick object to use for the left side of the robot.
267 * @param leftAxis The axis to select on the left side Joystick object.
268 * @param rightStick The Joystick object to use for the right side of the robot.
269 * @param rightAxis The axis to select on the right side Joystick object.
270 */
271void RobotDrive::TankDrive(GenericHID* leftStick, int leftAxis,
272 GenericHID* rightStick, int rightAxis,
273 bool squaredInputs) {
274 if (leftStick == nullptr || rightStick == nullptr) {
275 wpi_setWPIError(NullParameter);
276 return;
277 }
278 TankDrive(leftStick->GetRawAxis(leftAxis), rightStick->GetRawAxis(rightAxis),
279 squaredInputs);
280}
281
282void RobotDrive::TankDrive(GenericHID& leftStick, int leftAxis,
283 GenericHID& rightStick, int rightAxis,
284 bool squaredInputs) {
285 TankDrive(leftStick.GetRawAxis(leftAxis), rightStick.GetRawAxis(rightAxis),
286 squaredInputs);
287}
288
289/**
290 * Provide tank steering using the stored robot configuration.
291 *
292 * This function lets you directly provide joystick values from any source.
293 *
294 * @param leftValue The value of the left stick.
295 * @param rightValue The value of the right stick.
296 */
297void RobotDrive::TankDrive(double leftValue, double rightValue,
298 bool squaredInputs) {
299 static bool reported = false;
300 if (!reported) {
301 reported = true;
302 }
303
304 // square the inputs (while preserving the sign) to increase fine control
305 // while permitting full power
306 leftValue = Limit(leftValue);
307 rightValue = Limit(rightValue);
308 if (squaredInputs) {
309 if (leftValue >= 0.0) {
310 leftValue = (leftValue * leftValue);
311 } else {
312 leftValue = -(leftValue * leftValue);
313 }
314 if (rightValue >= 0.0) {
315 rightValue = (rightValue * rightValue);
316 } else {
317 rightValue = -(rightValue * rightValue);
318 }
319 }
320
321 SetLeftRightMotorOutputs(leftValue, rightValue);
322}
323
324/**
325 * Arcade drive implements single stick driving.
326 *
327 * Given a single Joystick, the class assumes the Y axis for the move value and
328 * the X axis for the rotate value.
329 * (Should add more information here regarding the way that arcade drive works.)
330 *
331 * @param stick The joystick to use for Arcade single-stick driving.
332 * The Y-axis will be selected for forwards/backwards and
333 * the X-axis will be selected for rotation rate.
334 * @param squaredInputs If true, the sensitivity will be increased for small
335 * values
336 */
337void RobotDrive::ArcadeDrive(GenericHID* stick, bool squaredInputs) {
338 // simply call the full-featured ArcadeDrive with the appropriate values
339 ArcadeDrive(stick->GetY(), stick->GetX(), squaredInputs);
340}
341
342/**
343 * Arcade drive implements single stick driving.
344 *
345 * Given a single Joystick, the class assumes the Y axis for the move value and
346 * the X axis for the rotate value.
347 * (Should add more information here regarding the way that arcade drive works.)
348 *
349 * @param stick The joystick to use for Arcade single-stick driving.
350 * The Y-axis will be selected for forwards/backwards and
351 * the X-axis will be selected for rotation rate.
352 * @param squaredInputs If true, the sensitivity will be increased for small
353 * values
354 */
355void RobotDrive::ArcadeDrive(GenericHID& stick, bool squaredInputs) {
356 // simply call the full-featured ArcadeDrive with the appropriate values
357 ArcadeDrive(stick.GetY(), stick.GetX(), squaredInputs);
358}
359
360/**
361 * Arcade drive implements single stick driving.
362 *
363 * Given two joystick instances and two axis, compute the values to send to
364 * either two or four motors.
365 *
366 * @param moveStick The Joystick object that represents the forward/backward
367 * direction
368 * @param moveAxis The axis on the moveStick object to use for
369 * forwards/backwards (typically Y_AXIS)
370 * @param rotateStick The Joystick object that represents the rotation value
371 * @param rotateAxis The axis on the rotation object to use for the rotate
372 * right/left (typically X_AXIS)
373 * @param squaredInputs Setting this parameter to true increases the sensitivity
374 * at lower speeds
375 */
376void RobotDrive::ArcadeDrive(GenericHID* moveStick, int moveAxis,
377 GenericHID* rotateStick, int rotateAxis,
378 bool squaredInputs) {
379 double moveValue = moveStick->GetRawAxis(moveAxis);
380 double rotateValue = rotateStick->GetRawAxis(rotateAxis);
381
382 ArcadeDrive(moveValue, rotateValue, squaredInputs);
383}
384
385/**
386 * Arcade drive implements single stick driving.
387 *
388 * Given two joystick instances and two axis, compute the values to send to
389 * either two or four motors.
390 *
391 * @param moveStick The Joystick object that represents the forward/backward
392 * direction
393 * @param moveAxis The axis on the moveStick object to use for
394 * forwards/backwards (typically Y_AXIS)
395 * @param rotateStick The Joystick object that represents the rotation value
396 * @param rotateAxis The axis on the rotation object to use for the rotate
397 * right/left (typically X_AXIS)
398 * @param squaredInputs Setting this parameter to true increases the sensitivity
399 * at lower speeds
400 */
401void RobotDrive::ArcadeDrive(GenericHID& moveStick, int moveAxis,
402 GenericHID& rotateStick, int rotateAxis,
403 bool squaredInputs) {
404 double moveValue = moveStick.GetRawAxis(moveAxis);
405 double rotateValue = rotateStick.GetRawAxis(rotateAxis);
406
407 ArcadeDrive(moveValue, rotateValue, squaredInputs);
408}
409
410/**
411 * Arcade drive implements single stick driving.
412 *
413 * This function lets you directly provide joystick values from any source.
414 *
415 * @param moveValue The value to use for fowards/backwards
416 * @param rotateValue The value to use for the rotate right/left
417 * @param squaredInputs If set, increases the sensitivity at low speeds
418 */
419void RobotDrive::ArcadeDrive(double moveValue, double rotateValue,
420 bool squaredInputs) {
421 static bool reported = false;
422 if (!reported) {
423 reported = true;
424 }
425
426 // local variables to hold the computed PWM values for the motors
427 double leftMotorOutput;
428 double rightMotorOutput;
429
430 moveValue = Limit(moveValue);
431 rotateValue = Limit(rotateValue);
432
433 if (squaredInputs) {
434 // square the inputs (while preserving the sign) to increase fine control
435 // while permitting full power
436 if (moveValue >= 0.0) {
437 moveValue = (moveValue * moveValue);
438 } else {
439 moveValue = -(moveValue * moveValue);
440 }
441 if (rotateValue >= 0.0) {
442 rotateValue = (rotateValue * rotateValue);
443 } else {
444 rotateValue = -(rotateValue * rotateValue);
445 }
446 }
447
448 if (moveValue > 0.0) {
449 if (rotateValue > 0.0) {
450 leftMotorOutput = moveValue - rotateValue;
451 rightMotorOutput = std::max(moveValue, rotateValue);
452 } else {
453 leftMotorOutput = std::max(moveValue, -rotateValue);
454 rightMotorOutput = moveValue + rotateValue;
455 }
456 } else {
457 if (rotateValue > 0.0) {
458 leftMotorOutput = -std::max(-moveValue, rotateValue);
459 rightMotorOutput = moveValue + rotateValue;
460 } else {
461 leftMotorOutput = moveValue - rotateValue;
462 rightMotorOutput = -std::max(-moveValue, -rotateValue);
463 }
464 }
465 SetLeftRightMotorOutputs(leftMotorOutput, rightMotorOutput);
466}
467
468/**
469 * Drive method for Mecanum wheeled robots.
470 *
471 * A method for driving with Mecanum wheeled robots. There are 4 wheels
472 * on the robot, arranged so that the front and back wheels are toed in 45
473 * degrees. When looking at the wheels from the top, the roller axles should
474 * form an X across the robot.
475 *
476 * This is designed to be directly driven by joystick axes.
477 *
478 * @param x The speed that the robot should drive in the X direction.
479 * [-1.0..1.0]
480 * @param y The speed that the robot should drive in the Y direction.
481 * This input is inverted to match the forward == -1.0 that
482 * joysticks produce. [-1.0..1.0]
483 * @param rotation The rate of rotation for the robot that is completely
484 * independent of the translation. [-1.0..1.0]
485 * @param gyroAngle The current angle reading from the gyro. Use this to
486 * implement field-oriented controls.
487 */
488void RobotDrive::MecanumDrive_Cartesian(double x, double y, double rotation,
489 double gyroAngle) {
490 static bool reported = false;
491 if (!reported) {
492 reported = true;
493 }
494
495 double xIn = x;
496 double yIn = y;
497 // Negate y for the joystick.
498 yIn = -yIn;
499 // Compenstate for gyro angle.
500 RotateVector(xIn, yIn, gyroAngle);
501
502 double wheelSpeeds[kMaxNumberOfMotors];
503 wheelSpeeds[kFrontLeftMotor] = xIn + yIn + rotation;
504 wheelSpeeds[kFrontRightMotor] = -xIn + yIn - rotation;
505 wheelSpeeds[kRearLeftMotor] = -xIn + yIn + rotation;
506 wheelSpeeds[kRearRightMotor] = xIn + yIn - rotation;
507
508 Normalize(wheelSpeeds);
509
510 m_frontLeftMotor->Set(wheelSpeeds[kFrontLeftMotor] *
511 m_invertedMotors[kFrontLeftMotor] * m_maxOutput);
512 m_frontRightMotor->Set(wheelSpeeds[kFrontRightMotor] *
513 m_invertedMotors[kFrontRightMotor] * m_maxOutput);
514 m_rearLeftMotor->Set(wheelSpeeds[kRearLeftMotor] *
515 m_invertedMotors[kRearLeftMotor] * m_maxOutput);
516 m_rearRightMotor->Set(wheelSpeeds[kRearRightMotor] *
517 m_invertedMotors[kRearRightMotor] * m_maxOutput);
518
519 // FIXME: m_safetyHelper->Feed();
520}
521
522/**
523 * Drive method for Mecanum wheeled robots.
524 *
525 * A method for driving with Mecanum wheeled robots. There are 4 wheels
526 * on the robot, arranged so that the front and back wheels are toed in 45
527 * degrees. When looking at the wheels from the top, the roller axles should
528 * form an X across the robot.
529 *
530 * @param magnitude The speed that the robot should drive in a given direction.
531 * [-1.0..1.0]
532 * @param direction The direction the robot should drive in degrees. The
533 * direction and maginitute are independent of the rotation
534 * rate.
535 * @param rotation The rate of rotation for the robot that is completely
536 * independent of the magnitute or direction. [-1.0..1.0]
537 */
538void RobotDrive::MecanumDrive_Polar(double magnitude, double direction,
539 double rotation) {
540 static bool reported = false;
541 if (!reported) {
542 reported = true;
543 }
544
545 // Normalized for full power along the Cartesian axes.
546 magnitude = Limit(magnitude) * std::sqrt(2.0);
547 // The rollers are at 45 degree angles.
548 double dirInRad = (direction + 45.0) * 3.14159 / 180.0;
549 double cosD = std::cos(dirInRad);
550 double sinD = std::sin(dirInRad);
551
552 double wheelSpeeds[kMaxNumberOfMotors];
553 wheelSpeeds[kFrontLeftMotor] = sinD * magnitude + rotation;
554 wheelSpeeds[kFrontRightMotor] = cosD * magnitude - rotation;
555 wheelSpeeds[kRearLeftMotor] = cosD * magnitude + rotation;
556 wheelSpeeds[kRearRightMotor] = sinD * magnitude - rotation;
557
558 Normalize(wheelSpeeds);
559
560 m_frontLeftMotor->Set(wheelSpeeds[kFrontLeftMotor] *
561 m_invertedMotors[kFrontLeftMotor] * m_maxOutput);
562 m_frontRightMotor->Set(wheelSpeeds[kFrontRightMotor] *
563 m_invertedMotors[kFrontRightMotor] * m_maxOutput);
564 m_rearLeftMotor->Set(wheelSpeeds[kRearLeftMotor] *
565 m_invertedMotors[kRearLeftMotor] * m_maxOutput);
566 m_rearRightMotor->Set(wheelSpeeds[kRearRightMotor] *
567 m_invertedMotors[kRearRightMotor] * m_maxOutput);
568
569 // FIXME: m_safetyHelper->Feed();
570}
571
572/**
573 * Holonomic Drive method for Mecanum wheeled robots.
574 *
575 * This is an alias to MecanumDrive_Polar() for backward compatability
576 *
577 * @param magnitude The speed that the robot should drive in a given direction.
578 * [-1.0..1.0]
579 * @param direction The direction the robot should drive. The direction and
580 * magnitude are independent of the rotation rate.
581 * @param rotation The rate of rotation for the robot that is completely
582 * independent of the magnitude or direction. [-1.0..1.0]
583 */
584void RobotDrive::HolonomicDrive(double magnitude, double direction,
585 double rotation) {
586 MecanumDrive_Polar(magnitude, direction, rotation);
587}
588
589/**
590 * Set the speed of the right and left motors.
591 *
592 * This is used once an appropriate drive setup function is called such as
593 * TwoWheelDrive(). The motors are set to "leftOutput" and "rightOutput"
594 * and includes flipping the direction of one side for opposing motors.
595 *
596 * @param leftOutput The speed to send to the left side of the robot.
597 * @param rightOutput The speed to send to the right side of the robot.
598 */
599void RobotDrive::SetLeftRightMotorOutputs(double leftOutput,
600 double rightOutput) {
601 wpi_assert(m_rearLeftMotor != nullptr && m_rearRightMotor != nullptr);
602
603 if (m_frontLeftMotor != nullptr)
604 m_frontLeftMotor->Set(Limit(leftOutput) *
605 m_invertedMotors[kFrontLeftMotor] * m_maxOutput);
606 m_rearLeftMotor->Set(Limit(leftOutput) * m_invertedMotors[kRearLeftMotor] *
607 m_maxOutput);
608
609 if (m_frontRightMotor != nullptr)
610 m_frontRightMotor->Set(-Limit(rightOutput) *
611 m_invertedMotors[kFrontRightMotor] * m_maxOutput);
612 m_rearRightMotor->Set(-Limit(rightOutput) *
613 m_invertedMotors[kRearRightMotor] * m_maxOutput);
614
615 // FIXME: m_safetyHelper->Feed();
616}
617
618/**
619 * Limit motor values to the -1.0 to +1.0 range.
620 */
621double RobotDrive::Limit(double num) {
622 if (num > 1.0) {
623 return 1.0;
624 }
625 if (num < -1.0) {
626 return -1.0;
627 }
628 return num;
629}
630
631/**
632 * Normalize all wheel speeds if the magnitude of any wheel is greater than 1.0.
633 */
634void RobotDrive::Normalize(double* wheelSpeeds) {
635 double maxMagnitude = std::fabs(wheelSpeeds[0]);
636 int i;
637 for (i = 1; i < kMaxNumberOfMotors; i++) {
638 double temp = std::fabs(wheelSpeeds[i]);
639 if (maxMagnitude < temp) maxMagnitude = temp;
640 }
641 if (maxMagnitude > 1.0) {
642 for (i = 0; i < kMaxNumberOfMotors; i++) {
643 wheelSpeeds[i] = wheelSpeeds[i] / maxMagnitude;
644 }
645 }
646}
647
648/**
649 * Rotate a vector in Cartesian space.
650 */
651void RobotDrive::RotateVector(double& x, double& y, double angle) {
652 double cosA = std::cos(angle * (3.14159 / 180.0));
653 double sinA = std::sin(angle * (3.14159 / 180.0));
654 double xOut = x * cosA - y * sinA;
655 double yOut = x * sinA + y * cosA;
656 x = xOut;
657 y = yOut;
658}
659
660/**
661 * Invert a motor direction.
662 *
663 * This is used when a motor should run in the opposite direction as the drive
664 * code would normally run it. Motors that are direct drive would be inverted,
665 * the Drive code assumes that the motors are geared with one reversal.
666 *
667 * @param motor The motor index to invert.
668 * @param isInverted True if the motor should be inverted when operated.
669 */
670void RobotDrive::SetInvertedMotor(MotorType motor, bool isInverted) {
671 if (motor < 0 || motor > 3) {
672 wpi_setWPIError(InvalidMotorIndex);
673 return;
674 }
675 m_invertedMotors[motor] = isInverted ? -1 : 1;
676}
677
678/**
679 * Set the turning sensitivity.
680 *
681 * This only impacts the Drive() entry-point.
682 *
683 * @param sensitivity Effectively sets the turning sensitivity (or turn radius
684 * for a given value)
685 */
686void RobotDrive::SetSensitivity(double sensitivity) {
687 m_sensitivity = sensitivity;
688}
689
690/**
691 * Configure the scaling factor for using RobotDrive with motor controllers in a
692 * mode other than PercentVbus.
693 *
694 * @param maxOutput Multiplied with the output percentage computed by the drive
695 * functions.
696 */
697void RobotDrive::SetMaxOutput(double maxOutput) { m_maxOutput = maxOutput; }
698
699void RobotDrive::SetExpiration(double timeout) {
700 // FIXME: m_safetyHelper->SetExpiration(timeout);
701}
702
703double RobotDrive::GetExpiration() const {
704 return -1; // FIXME: return m_safetyHelper->GetExpiration();
705}
706
707bool RobotDrive::IsAlive() const {
708 return true; // FIXME: m_safetyHelper->IsAlive();
709}
710
711bool RobotDrive::IsSafetyEnabled() const {
712 return false; // FIXME: return m_safetyHelper->IsSafetyEnabled();
713}
714
715void RobotDrive::SetSafetyEnabled(bool enabled) {
716 // FIXME: m_safetyHelper->SetSafetyEnabled(enabled);
717}
718
719void RobotDrive::GetDescription(std::ostringstream& desc) const {
720 desc << "RobotDrive";
721}
722
723void RobotDrive::StopMotor() {
724 if (m_frontLeftMotor != nullptr) m_frontLeftMotor->Disable();
725 if (m_frontRightMotor != nullptr) m_frontRightMotor->Disable();
726 if (m_rearLeftMotor != nullptr) m_rearLeftMotor->Disable();
727 if (m_rearRightMotor != nullptr) m_rearRightMotor->Disable();
728}