diff --git a/wpilibc/src/main/native/cpp/Drive/RobotDriveBase.cpp b/wpilibc/src/main/native/cpp/Drive/RobotDriveBase.cpp index 3f0067d2a0..f30955f5f8 100644 --- a/wpilibc/src/main/native/cpp/Drive/RobotDriveBase.cpp +++ b/wpilibc/src/main/native/cpp/Drive/RobotDriveBase.cpp @@ -20,11 +20,18 @@ using namespace frc; RobotDriveBase::RobotDriveBase() { m_safetyHelper.SetSafetyEnabled(true); } +/** + * Change the default value for deadband scaling. The default value is + * 0.02. Values smaller then the deadband are set to 0, while values + * larger then the deadband are scaled from 0.0 to 1.0. See ApplyDeadband(). + * + * @param deadband The deadband to set. + */ void RobotDriveBase::SetDeadband(double deadband) { m_deadband = deadband; } /** * Configure the scaling factor for using RobotDrive with motor controllers in a - * mode other than PercentVbus. + * mode other than PercentVbus or to limit the maximum output. * * @param maxOutput Multiplied with the output percentage computed by the drive * functions. diff --git a/wpilibc/src/main/native/include/Drive/DifferentialDrive.h b/wpilibc/src/main/native/include/Drive/DifferentialDrive.h index 4a367b0475..ca1afc4169 100644 --- a/wpilibc/src/main/native/include/Drive/DifferentialDrive.h +++ b/wpilibc/src/main/native/include/Drive/DifferentialDrive.h @@ -81,6 +81,20 @@ class SpeedController; * The positive X axis points ahead, the positive Y axis points to the right, * and the positive Z axis points down. Rotations follow the right-hand rule, so * clockwise rotation around the Z axis is positive. + * + * Inputs smaller then 0.02 will be set to 0, and larger values will be scaled + * so that the full range is still used. This deadband value can be changed + * with SetDeadband(). + * + *

RobotDrive porting guide: + *
TankDrive(double, double, bool) is equivalent to + * RobotDrive#TankDrive(double, double, bool) if a deadband of 0 is used. + *
ArcadeDrive(double, double, bool) is equivalent to + * RobotDrive#ArcadeDrive(double, double, bool) if a deadband of 0 is used + * and the the rotation input is inverted eg ArcadeDrive(y, -rotation, false) + *
CurvatureDrive(double, double, bool) is similar in concept to + * RobotDrive#Drive(double, double) with the addition of a quick turn + * mode. However, it is not designed to give exactly the same response. */ class DifferentialDrive : public RobotDriveBase { public: diff --git a/wpilibc/src/main/native/include/Drive/MecanumDrive.h b/wpilibc/src/main/native/include/Drive/MecanumDrive.h index e9860709bf..33be8dff23 100644 --- a/wpilibc/src/main/native/include/Drive/MecanumDrive.h +++ b/wpilibc/src/main/native/include/Drive/MecanumDrive.h @@ -44,6 +44,23 @@ class SpeedController; * The positive X axis points ahead, the positive Y axis points to the right, * and the positive Z axis points down. Rotations follow the right-hand rule, so * clockwise rotation around the Z axis is positive. + * + * Inputs smaller then 0.02 will be set to 0, and larger values will be scaled + * so that the full range is still used. This deadband value can be changed + * with SetDeadband(). + * + * RobotDrive porting guide: + *
In MecanumDrive, the right side speed controllers are automatically + * inverted, while in RobotDrive, no speed controllers are automatically + * inverted. + *
DriveCartesian(double, double, double, double) is equivalent to + * RobotDrive#MecanumDrive_Cartesian(double, double, double, double) + * if a deadband of 0 is used, and the ySpeed and gyroAngle values are inverted + * compared to RobotDrive (eg DriveCartesian(xSpeed, -ySpeed, zRotation, + * -gyroAngle). + *
DrivePolar(double, double, double) is equivalent to + * RobotDrive#MecanumDrive_Polar(double, double, double) if a + * deadband of 0 is used. */ class MecanumDrive : public RobotDriveBase { public: diff --git a/wpilibcIntegrationTests/src/FRCUserProgram/cpp/RobotDriveTest.cpp b/wpilibcIntegrationTests/src/FRCUserProgram/cpp/RobotDriveTest.cpp new file mode 100644 index 0000000000..6f12ac4751 --- /dev/null +++ b/wpilibcIntegrationTests/src/FRCUserProgram/cpp/RobotDriveTest.cpp @@ -0,0 +1,191 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2014-2017 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "Drive/DifferentialDrive.h" +#include "Drive/MecanumDrive.h" +#include "MockSpeedController.h" +#include "RobotDrive.h" +#include "TestBench.h" +#include "gtest/gtest.h" + +using namespace frc; + +class RobotDriveTest : public testing::Test { + protected: + MockSpeedController m_rdFrontLeft; + MockSpeedController m_rdRearLeft; + MockSpeedController m_rdFrontRight; + MockSpeedController m_rdRearRight; + MockSpeedController m_frontLeft; + MockSpeedController m_rearLeft; + MockSpeedController m_frontRight; + MockSpeedController m_rearRight; + frc::RobotDrive m_robotDrive{m_rdFrontLeft, m_rdRearLeft, m_rdFrontRight, + m_rdRearRight}; + frc::DifferentialDrive m_differentialDrive{m_frontLeft, m_frontRight}; + frc::MecanumDrive m_mecanumDrive{m_frontLeft, m_rearLeft, m_frontRight, + m_rearRight}; + + double m_testJoystickValues[9] = {-1.0, -0.9, -0.5, -0.01, 0.0, + 0.01, 0.5, 0.9, 1.0}; + double m_testGyroValues[19] = {0, 45, 90, 135, 180, 225, 270, + 305, 360, 540, -45, -90, -135, -180, + -225, -270, -305, -360, -540}; +}; + +TEST_F(RobotDriveTest, TankDrive) { + int joystickSize = sizeof(m_testJoystickValues) / sizeof(double); + double leftJoystick, rightJoystick; + m_differentialDrive.SetDeadband(0.0); + m_differentialDrive.SetSafetyEnabled(false); + m_mecanumDrive.SetSafetyEnabled(false); + m_robotDrive.SetSafetyEnabled(false); + for (int i = 0; i < joystickSize; i++) { + for (int j = 0; j < joystickSize; j++) { + leftJoystick = m_testJoystickValues[i]; + rightJoystick = m_testJoystickValues[j]; + m_robotDrive.TankDrive(leftJoystick, rightJoystick, false); + m_differentialDrive.TankDrive(leftJoystick, rightJoystick, false); + ASSERT_NEAR(m_rdFrontLeft.Get(), m_frontLeft.Get(), 0.01); + ASSERT_NEAR(m_rdFrontRight.Get(), m_frontRight.Get(), 0.01); + } + } +} + +TEST_F(RobotDriveTest, TankDriveSquared) { + int joystickSize = sizeof(m_testJoystickValues) / sizeof(double); + double leftJoystick, rightJoystick; + m_differentialDrive.SetDeadband(0.0); + m_differentialDrive.SetSafetyEnabled(false); + m_mecanumDrive.SetSafetyEnabled(false); + m_robotDrive.SetSafetyEnabled(false); + for (int i = 0; i < joystickSize; i++) { + for (int j = 0; j < joystickSize; j++) { + leftJoystick = m_testJoystickValues[i]; + rightJoystick = m_testJoystickValues[j]; + m_robotDrive.TankDrive(leftJoystick, rightJoystick, true); + m_differentialDrive.TankDrive(leftJoystick, rightJoystick, true); + ASSERT_NEAR(m_rdFrontLeft.Get(), m_frontLeft.Get(), 0.01); + ASSERT_NEAR(m_rdFrontRight.Get(), m_frontRight.Get(), 0.01); + } + } +} + +TEST_F(RobotDriveTest, ArcadeDriveSquared) { + int joystickSize = sizeof(m_testJoystickValues) / sizeof(double); + double moveJoystick, rotateJoystick; + m_differentialDrive.SetDeadband(0.0); + m_differentialDrive.SetSafetyEnabled(false); + m_mecanumDrive.SetSafetyEnabled(false); + m_robotDrive.SetSafetyEnabled(false); + for (int i = 0; i < joystickSize; i++) { + for (int j = 0; j < joystickSize; j++) { + moveJoystick = m_testJoystickValues[i]; + rotateJoystick = m_testJoystickValues[j]; + m_robotDrive.ArcadeDrive(moveJoystick, rotateJoystick, true); + m_differentialDrive.ArcadeDrive(moveJoystick, -rotateJoystick, true); + ASSERT_NEAR(m_rdFrontLeft.Get(), m_frontLeft.Get(), 0.01); + ASSERT_NEAR(m_rdFrontRight.Get(), m_frontRight.Get(), 0.01); + } + } +} + +TEST_F(RobotDriveTest, ArcadeDrive) { + int joystickSize = sizeof(m_testJoystickValues) / sizeof(double); + double moveJoystick, rotateJoystick; + m_differentialDrive.SetDeadband(0.0); + m_differentialDrive.SetSafetyEnabled(false); + m_mecanumDrive.SetSafetyEnabled(false); + m_robotDrive.SetSafetyEnabled(false); + for (int i = 0; i < joystickSize; i++) { + for (int j = 0; j < joystickSize; j++) { + moveJoystick = m_testJoystickValues[i]; + rotateJoystick = m_testJoystickValues[j]; + m_robotDrive.ArcadeDrive(moveJoystick, rotateJoystick, false); + m_differentialDrive.ArcadeDrive(moveJoystick, -rotateJoystick, false); + ASSERT_NEAR(m_rdFrontLeft.Get(), m_frontLeft.Get(), 0.01); + ASSERT_NEAR(m_rdFrontRight.Get(), m_frontRight.Get(), 0.01); + } + } +} + +TEST_F(RobotDriveTest, MecanumCartesian) { + int joystickSize = sizeof(m_testJoystickValues) / sizeof(double); + int gyroSize = sizeof(m_testGyroValues) / sizeof(double); + double xJoystick, yJoystick, rotateJoystick, gyroValue; + m_mecanumDrive.SetDeadband(0.0); + m_mecanumDrive.SetSafetyEnabled(false); + m_differentialDrive.SetSafetyEnabled(false); + m_robotDrive.SetSafetyEnabled(false); + for (int i = 0; i < joystickSize; i++) { + for (int j = 0; j < joystickSize; j++) { + for (int k = 0; k < joystickSize; k++) { + for (int l = 0; l < gyroSize; l++) { + xJoystick = m_testJoystickValues[i]; + yJoystick = m_testJoystickValues[j]; + rotateJoystick = m_testJoystickValues[k]; + gyroValue = m_testGyroValues[l]; + m_robotDrive.MecanumDrive_Cartesian(xJoystick, yJoystick, + rotateJoystick, gyroValue); + m_mecanumDrive.DriveCartesian(xJoystick, -yJoystick, rotateJoystick, + -gyroValue); + ASSERT_NEAR(m_rdFrontLeft.Get(), m_frontLeft.Get(), 0.01) + << "X: " << xJoystick << " Y: " << yJoystick + << " Rotate: " << rotateJoystick << " Gyro: " << gyroValue; + ASSERT_NEAR(m_rdFrontRight.Get(), -m_frontRight.Get(), 0.01) + << "X: " << xJoystick << " Y: " << yJoystick + << " Rotate: " << rotateJoystick << " Gyro: " << gyroValue; + ASSERT_NEAR(m_rdRearLeft.Get(), m_rearLeft.Get(), 0.01) + << "X: " << xJoystick << " Y: " << yJoystick + << " Rotate: " << rotateJoystick << " Gyro: " << gyroValue; + ASSERT_NEAR(m_rdRearRight.Get(), -m_rearRight.Get(), 0.01) + << "X: " << xJoystick << " Y: " << yJoystick + << " Rotate: " << rotateJoystick << " Gyro: " << gyroValue; + } + } + } + } +} + +TEST_F(RobotDriveTest, MecanumPolar) { + int joystickSize = sizeof(m_testJoystickValues) / sizeof(double); + int gyroSize = sizeof(m_testGyroValues) / sizeof(double); + double magnitudeJoystick, directionJoystick, rotateJoystick; + m_mecanumDrive.SetDeadband(0.0); + m_mecanumDrive.SetSafetyEnabled(false); + m_differentialDrive.SetSafetyEnabled(false); + m_robotDrive.SetSafetyEnabled(false); + for (int i = 0; i < joystickSize; i++) { + for (int j = 0; j < gyroSize; j++) { + for (int k = 0; k < joystickSize; k++) { + magnitudeJoystick = m_testJoystickValues[i]; + directionJoystick = m_testGyroValues[j]; + rotateJoystick = m_testJoystickValues[k]; + m_robotDrive.MecanumDrive_Polar(magnitudeJoystick, directionJoystick, + rotateJoystick); + m_mecanumDrive.DrivePolar(magnitudeJoystick, directionJoystick, + rotateJoystick); + ASSERT_NEAR(m_rdFrontLeft.Get(), m_frontLeft.Get(), 0.01) + << "Magnitude: " << magnitudeJoystick + << " Direction: " << directionJoystick + << " Rotate: " << rotateJoystick; + ASSERT_NEAR(m_rdFrontRight.Get(), -m_frontRight.Get(), 0.01) + << "Magnitude: " << magnitudeJoystick + << " Direction: " << directionJoystick + << " Rotate: " << rotateJoystick; + ASSERT_NEAR(m_rdRearLeft.Get(), m_rearLeft.Get(), 0.01) + << "Magnitude: " << magnitudeJoystick + << " Direction: " << directionJoystick + << " Rotate: " << rotateJoystick; + ASSERT_NEAR(m_rdRearRight.Get(), -m_rearRight.Get(), 0.01) + << "Magnitude: " << magnitudeJoystick + << " Direction: " << directionJoystick + << " Rotate: " << rotateJoystick; + } + } + } +} diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotDrive.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotDrive.java index 15f38d9ab7..90dd0c7a2b 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotDrive.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotDrive.java @@ -200,7 +200,8 @@ public class RobotDrive implements MotorSafety { /** * Provide tank steering using the stored robot configuration. drive the robot using two joystick - * inputs. The Y-axis will be selected from each Joystick object. + * inputs. The Y-axis will be selected from each Joystick object. The calculated values will be + * squared to decrease sensitivity at low speeds. * * @param leftStick The joystick to control the left side of the robot. * @param rightStick The joystick to control the right side of the robot. @@ -229,7 +230,8 @@ public class RobotDrive implements MotorSafety { /** * Provide tank steering using the stored robot configuration. This function lets you pick the - * axis to be used on each Joystick object for the left and right sides of the robot. + * axis to be used on each Joystick object for the left and right sides of the robot. The + * calculated values will be squared to decrease sensitivity at low speeds. * * @param leftStick The Joystick object to use for the left side of the robot. * @param leftAxis The axis to select on the left side Joystick object. @@ -292,7 +294,8 @@ public class RobotDrive implements MotorSafety { /** * Provide tank steering using the stored robot configuration. This function lets you directly - * provide joystick values from any source. + * provide joystick values from any source. The calculated values will be squared to decrease + * sensitivity at low speeds. * * @param leftValue The value of the left stick. * @param rightValue The value of the right stick. @@ -304,7 +307,8 @@ public class RobotDrive implements MotorSafety { /** * Arcade drive implements single stick driving. Given a single Joystick, the class assumes the Y * axis for the move value and the X axis for the rotate value. (Should add more information here - * regarding the way that arcade drive works.) + * regarding the way that arcade drive works.) The calculated values will be squared to decrease + * sensitivity at low speeds. * * @param stick The joystick to use for Arcade single-stick driving. The Y-axis will be * selected for forwards/backwards and the X-axis will be selected for @@ -319,7 +323,8 @@ public class RobotDrive implements MotorSafety { /** * Arcade drive implements single stick driving. Given a single Joystick, the class assumes the Y * axis for the move value and the X axis for the rotate value. (Should add more information here - * regarding the way that arcade drive works.) + * regarding the way that arcade drive works.) The calculated values will be squared to decrease + * sensitivity at low speeds. * * @param stick The joystick to use for Arcade single-stick driving. The Y-axis will be selected * for forwards/backwards and the X-axis will be selected for rotation rate. @@ -350,7 +355,8 @@ public class RobotDrive implements MotorSafety { /** * Arcade drive implements single stick driving. Given two joystick instances and two axis, - * compute the values to send to either two or four motors. + * compute the values to send to either two or four motors. The calculated values will be + * squared to decrease sensitivity at low speeds. * * @param moveStick The Joystick object that represents the forward/backward direction * @param moveAxis The axis on the moveStick object to use for forwards/backwards (typically @@ -418,7 +424,8 @@ public class RobotDrive implements MotorSafety { /** * Arcade drive implements single stick driving. This function lets you directly provide - * joystick values from any source. + * joystick values from any source. The calculated values will be squared to decrease + * sensitivity at low speeds. * * @param moveValue The value to use for forwards/backwards * @param rotateValue The value to use for the rotate right/left @@ -486,9 +493,9 @@ public class RobotDrive implements MotorSafety { * so that the front and back wheels are toed in 45 degrees. When looking at the wheels from the * top, the roller axles should form an X across the robot. * - * @param magnitude The speed that the robot should drive in a given direction. - * @param direction The direction the robot should drive in degrees. The direction and magnitude - * are independent of the rotation rate. + * @param magnitude The speed that the robot should drive in a given direction. [-1.0..1.0] + * @param direction The angle the robot should drive in degrees. The direction and magnitude + * are independent of the rotation rate. [-180.0..180.0] * @param rotation The rate of rotation for the robot that is completely independent of the * magnitude or direction. [-1.0..1.0] */ @@ -501,7 +508,7 @@ public class RobotDrive implements MotorSafety { // Normalized for full power along the Cartesian axes. magnitude = limit(magnitude) * Math.sqrt(2.0); // The rollers are at 45 degree angles. - double dirInRad = (direction + 45.0) * 3.14159 / 180.0; + double dirInRad = (direction + 45.0) * Math.PI / 180.0; double cosD = Math.cos(dirInRad); double sinD = Math.sin(dirInRad); @@ -529,7 +536,7 @@ public class RobotDrive implements MotorSafety { *

This is an alias to mecanumDrive_Polar() for backward compatibility * * @param magnitude The speed that the robot should drive in a given direction. [-1.0..1.0] - * @param direction The direction the robot should drive. The direction and maginitute are + * @param direction The direction the robot should drive. The direction and maginitude are * independent of the rotation rate. * @param rotation The rate of rotation for the robot that is completely independent of the * magnitute or direction. [-1.0..1.0] @@ -601,8 +608,8 @@ public class RobotDrive implements MotorSafety { */ @SuppressWarnings("ParameterName") protected static double[] rotateVector(double x, double y, double angle) { - double cosA = Math.cos(angle * (3.14159 / 180.0)); - double sinA = Math.sin(angle * (3.14159 / 180.0)); + double cosA = Math.cos(angle * (Math.PI / 180.0)); + double sinA = Math.sin(angle * (Math.PI / 180.0)); double[] out = new double[2]; out[0] = x * cosA - y * sinA; out[1] = x * sinA + y * cosA; diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java index df8c87fd42..0ab58598be 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java @@ -18,7 +18,8 @@ import edu.wpi.first.wpilibj.hal.HAL; * *

These drive bases typically have drop-center / skid-steer with two or more wheels per side * (e.g., 6WD or 8WD). This class takes a SpeedController per side. For four and - * six motor drivetrains, construct and pass in {@link SpeedControllerGroup} instances as follows. + * six motor drivetrains, construct and pass in {@link edu.wpi.first.wpilibj.SpeedControllerGroup} + * instances as follows. * *

Four motor drivetrain: *


@@ -73,6 +74,20 @@ import edu.wpi.first.wpilibj.hal.HAL;
  * 

The positive X axis points ahead, the positive Y axis points right, and the positive Z axis * points down. Rotations follow the right-hand rule, so clockwise rotation around the Z axis is * positive. + * + *

Inputs smaller then {@value edu.wpi.first.wpilibj.drive.RobotDriveBase#kDefaultDeadband} will + * be set to 0, and larger values will be scaled so that the full range is still used. This + * deadband value can be changed with {@link #setDeadband}. + * + *

RobotDrive porting guide: + *
{@link #tankDrive(double, double)} is equivalent to + * {@link edu.wpi.first.wpilibj.RobotDrive#tankDrive(double, double)} if a deadband of 0 is used. + *
{@link #arcadeDrive(double, double)} is equivalent to + * {@link edu.wpi.first.wpilibj.RobotDrive#arcadeDrive(double, double)} if a deadband of 0 is used + * and the the rotation input is inverted eg arcadeDrive(y, -rotation) + *
{@link #curvatureDrive(double, double, boolean)} is similar in concept to + * {@link edu.wpi.first.wpilibj.RobotDrive#drive(double, double)} with the addition of a quick turn + * mode. However, it is not designed to give exactly the same response. */ public class DifferentialDrive extends RobotDriveBase { public static final double kDefaultQuickStopThreshold = 0.2; @@ -99,6 +114,7 @@ public class DifferentialDrive extends RobotDriveBase { /** * Arcade drive method for differential drive platform. + * The calculated values will be squared to decrease sensitivity at low speeds. * * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive. * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is @@ -246,6 +262,7 @@ public class DifferentialDrive extends RobotDriveBase { /** * Tank drive method for differential drive platform. + * The calculated values will be squared to decrease sensitivity at low speeds. * * @param leftSpeed The robot's left side speed along the X axis [-1.0..1.0]. Forward is * positive. diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java index 87b9a380e6..592738bc8b 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java @@ -39,6 +39,21 @@ import edu.wpi.first.wpilibj.hal.HAL; *

The positive X axis points ahead, the positive Y axis points right, and the positive Z axis * points down. Rotations follow the right-hand rule, so clockwise rotation around the Z axis is * positive. + * + *

Inputs smaller then {@value edu.wpi.first.wpilibj.drive.RobotDriveBase#kDefaultDeadband} will + * be set to 0, and larger values will be scaled so that the full range is still used. This + * deadband value can be changed with {@link #setDeadband}. + * + *

RobotDrive porting guide: + *
In MecanumDrive, the right side speed controllers are automatically inverted, while in + * RobotDrive, no speed controllers are automatically inverted. + *
{@link #driveCartesian(double, double, double, double)} is equivalent to + * {@link edu.wpi.first.wpilibj.RobotDrive#mecanumDrive_Cartesian(double, double, double, double)} + * if a deadband of 0 is used, and the ySpeed and gyroAngle values are inverted compared to + * RobotDrive (eg driveCartesian(xSpeed, -ySpeed, zRotation, -gyroAngle). + *
{@link #drivePolar(double, double, double)} is equivalent to + * {@link edu.wpi.first.wpilibj.RobotDrive#mecanumDrive_Polar(double, double, double)} if a + * deadband of 0 is used. */ public class MecanumDrive extends RobotDriveBase { private SpeedController m_frontLeftMotor; diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/RobotDriveBase.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/RobotDriveBase.java index 89494e23c2..2b438cb8d2 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/RobotDriveBase.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/RobotDriveBase.java @@ -14,8 +14,11 @@ import edu.wpi.first.wpilibj.MotorSafetyHelper; * Common base class for drive platforms. */ public abstract class RobotDriveBase implements MotorSafety { - protected double m_deadband = 0.02; - protected double m_maxOutput = 1.0; + public static final double kDefaultDeadband = 0.02; + public static final double kDefaultMaxOutput = 1.0; + + protected double m_deadband = kDefaultDeadband; + protected double m_maxOutput = kDefaultMaxOutput; protected MotorSafetyHelper m_safetyHelper = new MotorSafetyHelper(this); /** @@ -37,13 +40,22 @@ public abstract class RobotDriveBase implements MotorSafety { m_safetyHelper.setSafetyEnabled(true); } + /** + * Change the default value for deadband scaling. The default value is + * {@value #kDefaultDeadband}. Values smaller then the deadband are set to 0, while values + * larger then the deadband are scaled from 0.0 to 1.0. See {@link #applyDeadband}. + * + * @param deadband The deadband to set. + */ public void setDeadband(double deadband) { m_deadband = deadband; } /** - * Configure the scaling factor for using RobotDrive with motor controllers in a mode other than - * PercentVbus. + * Configure the scaling factor for using drive methods with motor controllers in a mode other + * than PercentVbus or to limit the maximum output. + * + *

The default value is {@value #kDefaultMaxOutput}. * * @param maxOutput Multiplied with the output percentage computed by the drive functions. */ diff --git a/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/RobotDriveTest.java b/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/RobotDriveTest.java new file mode 100644 index 0000000000..7a3d4b7536 --- /dev/null +++ b/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/RobotDriveTest.java @@ -0,0 +1,183 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2008-2017 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +package edu.wpi.first.wpilibj; + +import org.junit.BeforeClass; +import org.junit.Test; + +import edu.wpi.first.wpilibj.drive.DifferentialDrive; +import edu.wpi.first.wpilibj.drive.MecanumDrive; + +import edu.wpi.first.wpilibj.test.AbstractComsSetup; + +import java.util.logging.Logger; + +import static org.junit.Assert.assertEquals; + +/** + * Tests the eqivilance of RobotDrive and DifferentialDrive/MecanumDrive. + */ +public class RobotDriveTest extends AbstractComsSetup { + private static final Logger logger = Logger.getLogger(RobotDriveTest.class.getName()); + + private static MockSpeedController m_rdFrontLeft = new MockSpeedController(); + private static MockSpeedController m_rdRearLeft = new MockSpeedController(); + private static MockSpeedController m_rdFrontRight = new MockSpeedController(); + private static MockSpeedController m_rdRearRight = new MockSpeedController(); + private static MockSpeedController m_frontLeft = new MockSpeedController(); + private static MockSpeedController m_rearLeft = new MockSpeedController(); + private static MockSpeedController m_frontRight = new MockSpeedController(); + private static MockSpeedController m_rearRight = new MockSpeedController(); + private static RobotDrive m_robotDrive = + new RobotDrive(m_rdFrontLeft, m_rdRearLeft, m_rdFrontRight, m_rdRearRight); + private static DifferentialDrive m_differentialDrive = + new DifferentialDrive(m_frontLeft, m_frontRight); + private static MecanumDrive m_mecanumDrive = + new MecanumDrive(m_frontLeft, m_rearLeft, m_frontRight, m_rearRight); + + private final double[] m_testJoystickValues = {1.0, 0.9, 0.5, 0.01, 0.0, -0.01, -0.5, -0.9, + -1.0}; + private final double[] m_testGyroValues = {0, 30, 45, 90, 135, 180, 225, 270, 305, 360, 540, + -45, -90, -135, -180, -225, -270, -305, -360, -540}; + + @BeforeClass + public static void before() { + m_differentialDrive.setDeadband(0.0); + m_differentialDrive.setSafetyEnabled(false); + m_mecanumDrive.setDeadband(0.0); + m_mecanumDrive.setSafetyEnabled(false); + m_robotDrive.setSafetyEnabled(false); + } + + @Test + public void testTankDriveSquared() { + for (double leftJoystick : m_testJoystickValues) { + for (double rightJoystick : m_testJoystickValues) { + m_robotDrive.tankDrive(leftJoystick, rightJoystick); + m_differentialDrive.tankDrive(leftJoystick, rightJoystick); + assertEquals("Left Motor squared didn't match. Left Joystick: " + leftJoystick + + " Right Joystick: " + rightJoystick + " ", m_rdFrontLeft.get(), m_frontLeft.get(), + 0.01); + assertEquals("Right Motor squared didn't match. Left Joystick: " + leftJoystick + + " Right Joystick: " + rightJoystick + " ", m_rdFrontRight.get(), m_frontRight.get(), + 0.01); + } + } + } + + @Test + public void testTankDrive() { + for (double leftJoystick : m_testJoystickValues) { + for (double rightJoystick : m_testJoystickValues) { + m_robotDrive.tankDrive(leftJoystick, rightJoystick, false); + m_differentialDrive.tankDrive(leftJoystick, rightJoystick, false); + assertEquals("Left Motor didn't match. Left Joystick: " + leftJoystick + + " Right Joystick: " + rightJoystick + " ", m_rdFrontLeft.get(), m_frontLeft.get(), + 0.01); + assertEquals("Right Motor didn't match. Left Joystick: " + leftJoystick + + " Right Joystick: " + rightJoystick + " ", m_rdFrontRight.get(), m_frontRight.get(), + 0.01); + } + } + } + + @Test + public void testArcadeDriveSquared() { + for (double moveJoystick : m_testJoystickValues) { + for (double rotateJoystick : m_testJoystickValues) { + m_robotDrive.arcadeDrive(moveJoystick, rotateJoystick); + m_differentialDrive.arcadeDrive(moveJoystick, -rotateJoystick); + assertEquals("Left Motor squared didn't match. Move Joystick: " + moveJoystick + + " Rotate Joystick: " + rotateJoystick + " ", m_rdFrontLeft.get(), m_frontLeft.get(), + 0.01); + assertEquals("Right Motor squared didn't match. Move Joystick: " + moveJoystick + + " Rotate Joystick: " + rotateJoystick + " ", m_rdFrontRight.get(), + m_frontRight.get(), 0.01); + } + } + } + + @Test + public void testArcadeDrive() { + for (double moveJoystick : m_testJoystickValues) { + for (double rotateJoystick : m_testJoystickValues) { + m_robotDrive.arcadeDrive(moveJoystick, rotateJoystick, false); + m_differentialDrive.arcadeDrive(moveJoystick, -rotateJoystick, false); + assertEquals("Left Motor didn't match. Move Joystick: " + moveJoystick + + " Rotate Joystick: " + rotateJoystick + " ", m_rdFrontLeft.get(), m_frontLeft.get(), + 0.01); + assertEquals("Right Motor didn't match. Move Joystick: " + moveJoystick + + " Rotate Joystick: " + rotateJoystick + " ", m_rdFrontRight.get(), + m_frontRight.get(), 0.01); + } + } + } + + @Test + public void testMecanumPolar() { + System.out.println("magnitudeJoystick, directionJoystick , rotationJoystick, " + + "m_rdFrontLeft, m_frontLeft, m_rdFrontRight, m_frontRight, m_rdRearLeft, " + + "m_rearLeft, m_rdRearRight, m_rearRight"); + for (double magnitudeJoystick : m_testJoystickValues) { + for (double directionJoystick : m_testGyroValues) { + for (double rotationJoystick : m_testJoystickValues) { + m_robotDrive.mecanumDrive_Polar(magnitudeJoystick, directionJoystick, rotationJoystick); + m_mecanumDrive.drivePolar(magnitudeJoystick, directionJoystick, rotationJoystick); + assertEquals("Left Front Motor didn't match. Magnitude Joystick: " + magnitudeJoystick + + " Direction Joystick: " + directionJoystick + " RotationJoystick: " + + rotationJoystick, m_rdFrontLeft.get(), m_frontLeft.get(), 0.01); + assertEquals("Right Front Motor didn't match. Magnitude Joystick: " + magnitudeJoystick + + " Direction Joystick: " + directionJoystick + " RotationJoystick: " + + rotationJoystick, m_rdFrontRight.get(), -m_frontRight.get(), 0.01); + assertEquals("Left Rear Motor didn't match. Magnitude Joystick: " + magnitudeJoystick + + " Direction Joystick: " + directionJoystick + " RotationJoystick: " + + rotationJoystick, m_rdRearLeft.get(), m_rearLeft.get(), 0.01); + assertEquals("Right Rear Motor didn't match. Magnitude Joystick: " + magnitudeJoystick + + " Direction Joystick: " + directionJoystick + " RotationJoystick: " + + rotationJoystick, m_rdRearRight.get(), -m_rearRight.get(), 0.01); + } + } + } + } + + @Test + @SuppressWarnings("checkstyle:LocalVariableName") + public void testMecanumCartesian() { + for (double x_Joystick : m_testJoystickValues) { + for (double y_Joystick : m_testJoystickValues) { + for (double rotationJoystick : m_testJoystickValues) { + for (double gyroValue : m_testGyroValues) { + m_robotDrive.mecanumDrive_Cartesian(x_Joystick, y_Joystick, rotationJoystick, + gyroValue); + m_mecanumDrive.driveCartesian(x_Joystick, -y_Joystick, rotationJoystick, -gyroValue); + assertEquals("Left Front Motor didn't match. X Joystick: " + x_Joystick + + " Y Joystick: " + y_Joystick + " RotationJoystick: " + + rotationJoystick + " Gyro: " + gyroValue, m_rdFrontLeft.get(), + m_frontLeft.get(), 0.01); + assertEquals("Right Front Motor didn't match. X Joystick: " + x_Joystick + + " Y Joystick: " + y_Joystick + " RotationJoystick: " + + rotationJoystick + " Gyro: " + gyroValue, m_rdFrontRight.get(), + -m_frontRight.get(), 0.01); + assertEquals("Left Rear Motor didn't match. X Joystick: " + x_Joystick + + " Y Joystick: " + y_Joystick + " RotationJoystick: " + + rotationJoystick + " Gyro: " + gyroValue, m_rdRearLeft.get(), + m_rearLeft.get(), 0.01); + assertEquals("Right Rear Motor didn't match. X Joystick: " + x_Joystick + + " Y Joystick: " + y_Joystick + " RotationJoystick: " + + rotationJoystick + " Gyro: " + gyroValue, m_rdRearRight.get(), + -m_rearRight.get(), 0.01); + } + } + } + } + } + + protected Logger getClassLogger() { + return logger; + } +} diff --git a/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/WpiLibJTestSuite.java b/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/WpiLibJTestSuite.java index a913e93799..d96e99dfd2 100644 --- a/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/WpiLibJTestSuite.java +++ b/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/WpiLibJTestSuite.java @@ -25,6 +25,6 @@ import edu.wpi.first.wpilibj.test.AbstractTestSuite; EncoderTest.class, FilterNoiseTest.class, FilterOutputTest.class, GyroTest.class, MotorEncoderTest.class, MotorInvertingTest.class, PCMTest.class, PDPTest.class, PIDTest.class, PIDToleranceTest.class, PreferencesTest.class, RelayCrossConnectTest.class, - SampleTest.class, TimerTest.class}) + RobotDriveTest.class, SampleTest.class, TimerTest.class}) public class WpiLibJTestSuite extends AbstractTestSuite { }