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