blob: e471b4255bc7648fbb34a99297ec23becbee29ec [file] [log] [blame]
jerrymf1579332013-02-07 01:56:28 +00001/*----------------------------------------------------------------------------*/
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 "NetworkCommunication/UsageReporting.h"
14#include "Utility.h"
15#include "WPIErrors.h"
16#include <math.h>
17
18#define max(x, y) (((x) > (y)) ? (x) : (y))
19
20const INT32 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 m_frontLeftMotor = NULL;
36 m_frontRightMotor = NULL;
37 m_rearRightMotor = NULL;
38 m_rearLeftMotor = NULL;
39 m_sensitivity = 0.5;
40 m_maxOutput = 1.0;
41 m_safetyHelper = new MotorSafetyHelper(this);
42 m_safetyHelper->SetSafetyEnabled(true);
43}
44
45/** Constructor for RobotDrive with 2 motors specified with channel numbers.
46 * Set up parameters for a two wheel drive system where the
47 * left and right motor pwm channels are specified in the call.
48 * This call assumes Jaguars for controlling the motors.
49 * @param leftMotorChannel The PWM channel number on the default digital module that drives the left motor.
50 * @param rightMotorChannel The PWM channel number on the default digital module that drives the right motor.
51 */
52RobotDrive::RobotDrive(UINT32 leftMotorChannel, UINT32 rightMotorChannel)
53{
54 InitRobotDrive();
55 m_rearLeftMotor = new Jaguar(leftMotorChannel);
56 m_rearRightMotor = new Jaguar(rightMotorChannel);
57 for (INT32 i=0; i < kMaxNumberOfMotors; i++)
58 {
59 m_invertedMotors[i] = 1;
60 }
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 * Set up parameters for a four wheel drive system where all four motor
68 * pwm channels are specified in the call.
69 * This call assumes Jaguars for controlling the motors.
70 * @param frontLeftMotor Front left motor channel number on the default digital module
71 * @param rearLeftMotor Rear Left motor channel number on the default digital module
72 * @param frontRightMotor Front right motor channel number on the default digital module
73 * @param rearRightMotor Rear Right motor channel number on the default digital module
74 */
75RobotDrive::RobotDrive(UINT32 frontLeftMotor, UINT32 rearLeftMotor,
76 UINT32 frontRightMotor, UINT32 rearRightMotor)
77{
78 InitRobotDrive();
79 m_rearLeftMotor = new Jaguar(rearLeftMotor);
80 m_rearRightMotor = new Jaguar(rearRightMotor);
81 m_frontLeftMotor = new Jaguar(frontLeftMotor);
82 m_frontRightMotor = new Jaguar(frontRightMotor);
83 for (INT32 i=0; i < kMaxNumberOfMotors; i++)
84 {
85 m_invertedMotors[i] = 1;
86 }
87 SetLeftRightMotorOutputs(0.0, 0.0);
88 m_deleteSpeedControllers = true;
89}
90
91/**
92 * Constructor for RobotDrive with 2 motors specified as SpeedController objects.
93 * The SpeedController version of the constructor enables programs to use the RobotDrive classes with
94 * subclasses of the SpeedController objects, for example, versions with ramping or reshaping of
95 * the curve to suit motor bias or deadband elimination.
96 * @param leftMotor The left SpeedController object used to drive the robot.
97 * @param rightMotor the right SpeedController object used to drive the robot.
98 */
99RobotDrive::RobotDrive(SpeedController *leftMotor, SpeedController *rightMotor)
100{
101 InitRobotDrive();
102 if (leftMotor == NULL || rightMotor == NULL)
103 {
104 wpi_setWPIError(NullParameter);
105 m_rearLeftMotor = m_rearRightMotor = NULL;
106 return;
107 }
108 m_rearLeftMotor = leftMotor;
109 m_rearRightMotor = rightMotor;
110 for (INT32 i=0; i < kMaxNumberOfMotors; i++)
111 {
112 m_invertedMotors[i] = 1;
113 }
114 m_deleteSpeedControllers = false;
115}
116
117RobotDrive::RobotDrive(SpeedController &leftMotor, SpeedController &rightMotor)
118{
119 InitRobotDrive();
120 m_rearLeftMotor = &leftMotor;
121 m_rearRightMotor = &rightMotor;
122 for (INT32 i=0; i < kMaxNumberOfMotors; i++)
123 {
124 m_invertedMotors[i] = 1;
125 }
126 m_deleteSpeedControllers = false;
127}
128
129/**
130 * Constructor for RobotDrive with 4 motors specified as SpeedController objects.
131 * Speed controller input version of RobotDrive (see previous comments).
132 * @param rearLeftMotor The back left SpeedController object used to drive the robot.
133 * @param frontLeftMotor The front left SpeedController object used to drive the robot
134 * @param rearRightMotor The back right SpeedController object used to drive the robot.
135 * @param frontRightMotor The front right SpeedController object used to drive the robot.
136 */
137RobotDrive::RobotDrive(SpeedController *frontLeftMotor, SpeedController *rearLeftMotor,
138 SpeedController *frontRightMotor, SpeedController *rearRightMotor)
139{
140 InitRobotDrive();
141 if (frontLeftMotor == NULL || rearLeftMotor == NULL || frontRightMotor == NULL || rearRightMotor == NULL)
142 {
143 wpi_setWPIError(NullParameter);
144 return;
145 }
146 m_frontLeftMotor = frontLeftMotor;
147 m_rearLeftMotor = rearLeftMotor;
148 m_frontRightMotor = frontRightMotor;
149 m_rearRightMotor = rearRightMotor;
150 for (INT32 i=0; i < kMaxNumberOfMotors; i++)
151 {
152 m_invertedMotors[i] = 1;
153 }
154 m_deleteSpeedControllers = false;
155}
156
157RobotDrive::RobotDrive(SpeedController &frontLeftMotor, SpeedController &rearLeftMotor,
158 SpeedController &frontRightMotor, SpeedController &rearRightMotor)
159{
160 InitRobotDrive();
161 m_frontLeftMotor = &frontLeftMotor;
162 m_rearLeftMotor = &rearLeftMotor;
163 m_frontRightMotor = &frontRightMotor;
164 m_rearRightMotor = &rearRightMotor;
165 for (INT32 i=0; i < kMaxNumberOfMotors; i++)
166 {
167 m_invertedMotors[i] = 1;
168 }
169 m_deleteSpeedControllers = false;
170}
171
172/**
173 * RobotDrive destructor.
174 * Deletes motor objects that were not passed in and created internally only.
175 **/
176RobotDrive::~RobotDrive()
177{
178 if (m_deleteSpeedControllers)
179 {
180 delete m_frontLeftMotor;
181 delete m_rearLeftMotor;
182 delete m_frontRightMotor;
183 delete m_rearRightMotor;
184 }
185 delete m_safetyHelper;
186}
187
188/**
189 * Drive the motors at "speed" and "curve".
190 *
191 * The speed and curve are -1.0 to +1.0 values where 0.0 represents stopped and
192 * not turning. The algorithm for adding in the direction attempts to provide a constant
193 * turn radius for differing speeds.
194 *
195 * This function will most likely be used in an autonomous routine.
196 *
197 * @param outputMagnitude The forward component of the output magnitude to send to the motors.
198 * @param curve The rate of turn, constant for different forward speeds.
199 */
200void RobotDrive::Drive(float outputMagnitude, float curve)
201{
202 float leftOutput, rightOutput;
203 static bool reported = false;
204 if (!reported)
205 {
206 nUsageReporting::report(nUsageReporting::kResourceType_RobotDrive, GetNumMotors(), nUsageReporting::kRobotDrive_ArcadeRatioCurve);
207 reported = true;
208 }
209
210 if (curve < 0)
211 {
212 float value = log(-curve);
213 float ratio = (value - m_sensitivity)/(value + m_sensitivity);
214 if (ratio == 0) ratio =.0000000001;
215 leftOutput = outputMagnitude / ratio;
216 rightOutput = outputMagnitude;
217 }
218 else if (curve > 0)
219 {
220 float value = log(curve);
221 float ratio = (value - m_sensitivity)/(value + m_sensitivity);
222 if (ratio == 0) ratio =.0000000001;
223 leftOutput = outputMagnitude;
224 rightOutput = outputMagnitude / ratio;
225 }
226 else
227 {
228 leftOutput = outputMagnitude;
229 rightOutput = outputMagnitude;
230 }
231 SetLeftRightMotorOutputs(leftOutput, rightOutput);
232}
233
234/**
235 * Provide tank steering using the stored robot configuration.
236 * Drive the robot using two joystick inputs. The Y-axis will be selected from
237 * each Joystick object.
238 * @param leftStick The joystick to control the left side of the robot.
239 * @param rightStick The joystick to control the right side of the robot.
240 */
241void RobotDrive::TankDrive(GenericHID *leftStick, GenericHID *rightStick, bool squaredInputs)
242{
243 if (leftStick == NULL || rightStick == NULL)
244 {
245 wpi_setWPIError(NullParameter);
246 return;
247 }
248 TankDrive(leftStick->GetY(), rightStick->GetY(), squaredInputs);
249}
250
251void RobotDrive::TankDrive(GenericHID &leftStick, GenericHID &rightStick, bool squaredInputs)
252{
253 TankDrive(leftStick.GetY(), rightStick.GetY(), squaredInputs);
254}
255
256/**
257 * Provide tank steering using the stored robot configuration.
258 * This function lets you pick the axis to be used on each Joystick object for the left
259 * and right sides of the robot.
260 * @param leftStick The Joystick object to use for the left side of the robot.
261 * @param leftAxis The axis to select on the left side Joystick object.
262 * @param rightStick The Joystick object to use for the right side of the robot.
263 * @param rightAxis The axis to select on the right side Joystick object.
264 */
265void RobotDrive::TankDrive(GenericHID *leftStick, UINT32 leftAxis,
266 GenericHID *rightStick, UINT32 rightAxis, bool squaredInputs)
267{
268 if (leftStick == NULL || rightStick == NULL)
269 {
270 wpi_setWPIError(NullParameter);
271 return;
272 }
273 TankDrive(leftStick->GetRawAxis(leftAxis), rightStick->GetRawAxis(rightAxis), squaredInputs);
274}
275
276void RobotDrive::TankDrive(GenericHID &leftStick, UINT32 leftAxis,
277 GenericHID &rightStick, UINT32 rightAxis, bool squaredInputs)
278{
279 TankDrive(leftStick.GetRawAxis(leftAxis), rightStick.GetRawAxis(rightAxis), squaredInputs);
280}
281
282
283/**
284 * Provide tank steering using the stored robot configuration.
285 * This function lets you directly provide joystick values from any source.
286 * @param leftValue The value of the left stick.
287 * @param rightValue The value of the right stick.
288 */
289void RobotDrive::TankDrive(float leftValue, float rightValue, bool squaredInputs)
290{
291 static bool reported = false;
292 if (!reported)
293 {
294 nUsageReporting::report(nUsageReporting::kResourceType_RobotDrive, GetNumMotors(), nUsageReporting::kRobotDrive_Tank);
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 moveAxis,
365 GenericHID* rotateStick, UINT32 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 moveAxis,
386 GenericHID &rotateStick, UINT32 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 nUsageReporting::report(nUsageReporting::kResourceType_RobotDrive, GetNumMotors(), nUsageReporting::kRobotDrive_ArcadeStandard);
408 reported = true;
409 }
410
411 // local variables to hold the computed PWM values for the motors
412 float leftMotorOutput;
413 float rightMotorOutput;
414
415 moveValue = Limit(moveValue);
416 rotateValue = Limit(rotateValue);
417
418 if (squaredInputs)
419 {
420 // square the inputs (while preserving the sign) to increase fine control while permitting full power
421 if (moveValue >= 0.0)
422 {
423 moveValue = (moveValue * moveValue);
424 }
425 else
426 {
427 moveValue = -(moveValue * moveValue);
428 }
429 if (rotateValue >= 0.0)
430 {
431 rotateValue = (rotateValue * rotateValue);
432 }
433 else
434 {
435 rotateValue = -(rotateValue * rotateValue);
436 }
437 }
438
439 if (moveValue > 0.0)
440 {
441 if (rotateValue > 0.0)
442 {
443 leftMotorOutput = moveValue - rotateValue;
444 rightMotorOutput = max(moveValue, rotateValue);
445 }
446 else
447 {
448 leftMotorOutput = max(moveValue, -rotateValue);
449 rightMotorOutput = moveValue + rotateValue;
450 }
451 }
452 else
453 {
454 if (rotateValue > 0.0)
455 {
456 leftMotorOutput = - max(-moveValue, rotateValue);
457 rightMotorOutput = moveValue + rotateValue;
458 }
459 else
460 {
461 leftMotorOutput = moveValue - rotateValue;
462 rightMotorOutput = - 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 degrees.
473 * When looking at the wheels from the top, the roller axles should form an X across the robot.
474 *
475 * This is designed to be directly driven by joystick axes.
476 *
477 * @param x The speed that the robot should drive in the X direction. [-1.0..1.0]
478 * @param y The speed that the robot should drive in the Y direction.
479 * This input is inverted to match the forward == -1.0 that joysticks produce. [-1.0..1.0]
480 * @param rotation The rate of rotation for the robot that is completely independent of
481 * the translation. [-1.0..1.0]
482 * @param gyroAngle The current angle reading from the gyro. Use this to implement field-oriented controls.
483 */
484void RobotDrive::MecanumDrive_Cartesian(float x, float y, float rotation, float gyroAngle)
485{
486 static bool reported = false;
487 if (!reported)
488 {
489 nUsageReporting::report(nUsageReporting::kResourceType_RobotDrive, GetNumMotors(), nUsageReporting::kRobotDrive_MecanumCartesian);
490 reported = true;
491 }
492
493 double xIn = x;
494 double yIn = y;
495 // Negate y for the joystick.
496 yIn = -yIn;
497 // Compenstate for gyro angle.
498 RotateVector(xIn, yIn, gyroAngle);
499
500 double wheelSpeeds[kMaxNumberOfMotors];
501 wheelSpeeds[kFrontLeftMotor] = xIn + yIn + rotation;
502 wheelSpeeds[kFrontRightMotor] = -xIn + yIn - rotation;
503 wheelSpeeds[kRearLeftMotor] = -xIn + yIn + rotation;
504 wheelSpeeds[kRearRightMotor] = xIn + yIn - rotation;
505
506 Normalize(wheelSpeeds);
507
508 UINT8 syncGroup = 0x80;
509
510 m_frontLeftMotor->Set(wheelSpeeds[kFrontLeftMotor] * m_invertedMotors[kFrontLeftMotor] * m_maxOutput, syncGroup);
511 m_frontRightMotor->Set(wheelSpeeds[kFrontRightMotor] * m_invertedMotors[kFrontRightMotor] * m_maxOutput, syncGroup);
512 m_rearLeftMotor->Set(wheelSpeeds[kRearLeftMotor] * m_invertedMotors[kRearLeftMotor] * m_maxOutput, syncGroup);
513 m_rearRightMotor->Set(wheelSpeeds[kRearRightMotor] * m_invertedMotors[kRearRightMotor] * m_maxOutput, syncGroup);
514
515 CANJaguar::UpdateSyncGroup(syncGroup);
516
517 m_safetyHelper->Feed();
518}
519
520/**
521 * Drive method for Mecanum wheeled robots.
522 *
523 * A method for driving with Mecanum wheeled robots. There are 4 wheels
524 * on the robot, arranged so that the front and back wheels are toed in 45 degrees.
525 * When looking at the wheels from the top, the roller axles should form an X across the robot.
526 *
527 * @param magnitude The speed that the robot should drive in a given direction. [-1.0..1.0]
528 * @param direction The direction the robot should drive in degrees. The direction and maginitute are
529 * independent of the rotation rate.
530 * @param rotation The rate of rotation for the robot that is completely independent of
531 * the magnitute or direction. [-1.0..1.0]
532 */
533void RobotDrive::MecanumDrive_Polar(float magnitude, float direction, float rotation)
534{
535 static bool reported = false;
536 if (!reported)
537 {
538 nUsageReporting::report(nUsageReporting::kResourceType_RobotDrive, GetNumMotors(), nUsageReporting::kRobotDrive_MecanumPolar);
539 reported = true;
540 }
541
542 // Normalized for full power along the Cartesian axes.
543 magnitude = Limit(magnitude) * sqrt(2.0);
544 // The rollers are at 45 degree angles.
545 double dirInRad = (direction + 45.0) * 3.14159 / 180.0;
546 double cosD = cos(dirInRad);
547 double sinD = sin(dirInRad);
548
549 double wheelSpeeds[kMaxNumberOfMotors];
550 wheelSpeeds[kFrontLeftMotor] = sinD * magnitude + rotation;
551 wheelSpeeds[kFrontRightMotor] = cosD * magnitude - rotation;
552 wheelSpeeds[kRearLeftMotor] = cosD * magnitude + rotation;
553 wheelSpeeds[kRearRightMotor] = sinD * magnitude - rotation;
554
555 Normalize(wheelSpeeds);
556
557 UINT8 syncGroup = 0x80;
558
559 m_frontLeftMotor->Set(wheelSpeeds[kFrontLeftMotor] * m_invertedMotors[kFrontLeftMotor] * m_maxOutput, syncGroup);
560 m_frontRightMotor->Set(wheelSpeeds[kFrontRightMotor] * m_invertedMotors[kFrontRightMotor] * m_maxOutput, syncGroup);
561 m_rearLeftMotor->Set(wheelSpeeds[kRearLeftMotor] * m_invertedMotors[kRearLeftMotor] * m_maxOutput, syncGroup);
562 m_rearRightMotor->Set(wheelSpeeds[kRearRightMotor] * m_invertedMotors[kRearRightMotor] * m_maxOutput, syncGroup);
563
564 CANJaguar::UpdateSyncGroup(syncGroup);
565
566 m_safetyHelper->Feed();
567}
568
569/**
570 * Holonomic Drive method for Mecanum wheeled robots.
571 *
572 * This is an alias to MecanumDrive_Polar() for backward compatability
573 *
574 * @param magnitude The speed that the robot should drive in a given direction. [-1.0..1.0]
575 * @param direction The direction the robot should drive. The direction and maginitute are
576 * independent of the rotation rate.
577 * @param rotation The rate of rotation for the robot that is completely independent of
578 * the magnitute or direction. [-1.0..1.0]
579 */
580void RobotDrive::HolonomicDrive(float magnitude, float direction, float rotation)
581{
582 MecanumDrive_Polar(magnitude, direction, rotation);
583}
584
585/** Set the speed of the right and left motors.
586 * This is used once an appropriate drive setup function is called such as
587 * TwoWheelDrive(). The motors are set to "leftOutput" and "rightOutput"
588 * and includes flipping the direction of one side for opposing motors.
589 * @param leftOutput The speed to send to the left side of the robot.
590 * @param rightOutput The speed to send to the right side of the robot.
591 */
592void RobotDrive::SetLeftRightMotorOutputs(float leftOutput, float rightOutput)
593{
594 wpi_assert(m_rearLeftMotor != NULL && m_rearRightMotor != NULL);
595
596 UINT8 syncGroup = 0x80;
597
598 if (m_frontLeftMotor != NULL)
599 m_frontLeftMotor->Set(Limit(leftOutput) * m_invertedMotors[kFrontLeftMotor] * m_maxOutput, syncGroup);
600 m_rearLeftMotor->Set(Limit(leftOutput) * m_invertedMotors[kRearLeftMotor] * m_maxOutput, syncGroup);
601
602 if (m_frontRightMotor != NULL)
603 m_frontRightMotor->Set(-Limit(rightOutput) * m_invertedMotors[kFrontRightMotor] * m_maxOutput, syncGroup);
604 m_rearRightMotor->Set(-Limit(rightOutput) * m_invertedMotors[kRearRightMotor] * m_maxOutput, syncGroup);
605
606 CANJaguar::UpdateSyncGroup(syncGroup);
607
608 m_safetyHelper->Feed();
609}
610
611/**
612 * Limit motor values to the -1.0 to +1.0 range.
613 */
614float RobotDrive::Limit(float num)
615{
616 if (num > 1.0)
617 {
618 return 1.0;
619 }
620 if (num < -1.0)
621 {
622 return -1.0;
623 }
624 return num;
625}
626
627/**
628 * Normalize all wheel speeds if the magnitude of any wheel is greater than 1.0.
629 */
630void RobotDrive::Normalize(double *wheelSpeeds)
631{
632 double maxMagnitude = fabs(wheelSpeeds[0]);
633 INT32 i;
634 for (i=1; i<kMaxNumberOfMotors; i++)
635 {
636 double temp = fabs(wheelSpeeds[i]);
637 if (maxMagnitude < temp) maxMagnitude = temp;
638 }
639 if (maxMagnitude > 1.0)
640 {
641 for (i=0; i<kMaxNumberOfMotors; i++)
642 {
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{
653 double cosA = cos(angle * (3.14159 / 180.0));
654 double sinA = sin(angle * (3.14159 / 180.0));
655 double xOut = x * cosA - y * sinA;
656 double yOut = x * sinA + y * cosA;
657 x = xOut;
658 y = yOut;
659}
660
661/*
662 * Invert a motor direction.
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, the
665 * Drive code assumes that the motors are geared with one reversal.
666 * @param motor The motor index to invert.
667 * @param isInverted True if the motor should be inverted when operated.
668 */
669void RobotDrive::SetInvertedMotor(MotorType motor, bool isInverted)
670{
671 if (motor < 0 || motor > 3)
672 {
673 wpi_setWPIError(InvalidMotorIndex);
674 return;
675 }
676 m_invertedMotors[motor] = isInverted ? -1 : 1;
677}
678
679/**
680 * Set the turning sensitivity.
681 *
682 * This only impacts the Drive() entry-point.
683 * @param sensitivity Effectively sets the turning sensitivity (or turn radius for a given value)
684 */
685void RobotDrive::SetSensitivity(float sensitivity)
686{
687 m_sensitivity = sensitivity;
688}
689
690/**
691 * Configure the scaling factor for using RobotDrive with motor controllers in a mode other than PercentVbus.
692 * @param maxOutput Multiplied with the output percentage computed by the drive functions.
693 */
694void RobotDrive::SetMaxOutput(double maxOutput)
695{
696 m_maxOutput = maxOutput;
697}
698
699
700
701void RobotDrive::SetExpiration(float timeout)
702{
703 m_safetyHelper->SetExpiration(timeout);
704}
705
706float RobotDrive::GetExpiration()
707{
708 return m_safetyHelper->GetExpiration();
709}
710
711bool RobotDrive::IsAlive()
712{
713 return m_safetyHelper->IsAlive();
714}
715
716bool RobotDrive::IsSafetyEnabled()
717{
718 return m_safetyHelper->IsSafetyEnabled();
719}
720
721void RobotDrive::SetSafetyEnabled(bool enabled)
722{
723 m_safetyHelper->SetSafetyEnabled(enabled);
724}
725
726void RobotDrive::GetDescription(char *desc)
727{
728 sprintf(desc, "RobotDrive");
729}
730
731void RobotDrive::StopMotor()
732{
733 if (m_frontLeftMotor != NULL) m_frontLeftMotor->Disable();
734 if (m_frontRightMotor != NULL) m_frontRightMotor->Disable();
735 if (m_rearLeftMotor != NULL) m_rearLeftMotor->Disable();
736 if (m_rearRightMotor != NULL) m_rearRightMotor->Disable();
737}