Exemple #1
0
class DriveTrain(Subsystem):
    '''
    'Tank Drive' system set up with 2 motors per side, one a "master"
    with a mag encoder attached and the other "slave" controller set
    to follow the "master".
    '''
    def __init__(self):

        # Initialize all controllers
        self.driveLeftMaster = Talon(kDriveTrain.lmId)
        self.driveLeftSlave = Talon(kDriveTrain.lsId)
        self.driveRightMaster = Talon(kDriveTrain.rmId)
        self.driveRightSlave = Talon(kDriveTrain.rsId)

        # Connect the slaves to the masters on each side
        self.driveLeftSlave.follow(self.driveLeftMaster)
        self.driveRightSlave.follow(self.driveRightMaster)

        # Makes sure both sides' controllers show green and use positive
        # values to move the bot forward.
        # CURRENTLY DISABLED WHEN USING WITH DifferentialDrive
        # self.driveLeftSlave.setInverted(False)
        # self.driveLeftMaster.setInverted(False)
        self.driveRightSlave.setInverted(True)
        self.driveRightMaster.setInverted(True)

        # Configures each master to use the attached Mag Encoders
        self.driveLeftMaster.configSelectedFeedbackSensor(
            ctre.FeedbackDevice.CTRE_MagEncoder_Relative, 0, 0)
        self.driveRightMaster.configSelectedFeedbackSensor(
            ctre.FeedbackDevice.CTRE_MagEncoder_Relative, 0, 0)

        # Reverses the encoder direction so forward movement always
        # results in a positive increase in the encoder ticks.
        self.driveLeftMaster.setSensorPhase(True)
        self.driveRightMaster.setSensorPhase(True)

        # Throw data on the SmartDashboard so we can work with it.
        SD.putNumber('Left Quad Pos.',
                     self.driveLeftMaster.getQuadraturePosition())
        SD.putNumber('Right Quad Pos.',
                     self.driveRightMaster.getQuadraturePosition())

        # these may give the derivitive an integral of the PID once
        # they are set.  For now, they just show 0
        SD.putNumber('Left Derivative',
                     self.driveLeftMaster.getErrorDerivative(0))
        SD.putNumber('Left Integral',
                     self.driveLeftMaster.getIntegralAccumulator(0))

        self.leftVel = None
        self.leftPos = None
        self.rightVel = None
        self.rightPos = None

        # self.driveLeftMaster.config_kP(0, .3, 10)
        # kP = self.driveLeftMaster.configGetParameter(
        #     self.driveLeftMaster.ParamEnum.eProfileParamSlot_P, 0, 10)

        # SmartDashboard.putNumber('Left Proportional', kP)

        self.driveControllerLeft = SpeedControllerGroup(self.driveLeftMaster)
        self.driveControllerRight = SpeedControllerGroup(self.driveRightMaster)
        self.driveControllerRight.setInverted(True)
        self.drive = DifferentialDrive(self.driveControllerLeft,
                                       self.driveControllerRight)

    def moveToPosition(self, position, side='left'):

        if side == 'left':
            self.driveLeftMaster.setSafetyEnabled(False)
            self.driveLeftMaster.set(Talon.ControlMode.Position, position)
        else:
            self.driveRightMaster.set(Talon.ControlMode.Position, position)

    def stop(self):
        # self.driveLeftMaster.set(0)
        # self.driveRightMaster.set(0)
        self.drive.stopMotor()

    def arcade(self, speed, rotation):
        self.updateSD()
        self.drive.arcadeDrive(speed, rotation, True)

    def updateSD(self):

        leftVel = self.driveLeftMaster.getSelectedSensorVelocity(0)
        leftPos = self.driveLeftMaster.getSelectedSensorPosition(0)

        rightVel = self.driveRightMaster.getSelectedSensorVelocity(0)
        rightPos = self.driveRightMaster.getSelectedSensorPosition(0)

        # calculate side deltas
        if self.leftVel:
            leftVelDelta = leftVel - self.leftVel
        else:
            leftVelDelta = 0

        if self.leftPos:
            leftPosDelta = leftPos - self.leftPos
        else:
            leftPosDelta = 0

        if self.rightVel:
            rightVelDelta = rightVel - self.rightVel
        else:
            rightVelDelta = 0

        if self.rightPos:
            rightPosDelta = rightPos - self.rightPos
        else:
            rightPosDelta = 0

        # calculate delta of delta
        differenceVel = leftVelDelta - rightVelDelta
        differencePos = leftPosDelta - rightPosDelta

        SD.putNumber("LeftSensorVel", leftVel)
        SD.putNumber("LeftSensorPos", leftPos)

        SD.putNumber("RightSensorVel", rightVel)
        SD.putNumber("RightSensorPos", rightPos)

        SD.putNumber('LeftVelDelta', leftVelDelta)
        SD.putNumber('LeftPosDelta', leftPosDelta)

        SD.putNumber('RightVelDelta', rightVelDelta)
        SD.putNumber('RightPosDelta', rightPosDelta)

        SD.putNumber('DifferenceVel', differenceVel)
        SD.putNumber('DifferencePos', differencePos)

        self.leftVel = leftVel
        self.leftPos = leftPos
        self.rightVel = rightVel
        self.rightPos = rightPos
Exemple #2
0
class DriveTrain(Subsystem):
    '''
    'Tank Drive' system set up with 2 motors per side, one a "master"
    with a mag encoder attached and the other "slave" controller set
    to follow the "master".
    '''
    def __init__(self, robot):

        self.robot = robot

        # Initialize all controllers
        self.driveLeftMaster = Talon(self.robot.kDriveTrain['left_master'])
        self.driveLeftSlave = Talon(self.robot.kDriveTrain['left_slave'])
        self.driveRightMaster = Talon(self.robot.kDriveTrain['right_master'])
        self.driveRightSlave = Talon(self.robot.kDriveTrain['right_slave'])

        wpilib.LiveWindow.addActuator("DriveTrain", "LeftMaster",
                                      self.driveLeftMaster)
        wpilib.LiveWindow.addActuator("DriveTrain", "RightMaster",
                                      self.driveRightMaster)

        # Connect the slaves to the masters on each side
        self.driveLeftSlave.follow(self.driveLeftMaster)
        self.driveRightSlave.follow(self.driveRightMaster)

        # Makes sure both sides' controllers show green and use positive
        # values to move the bot forward.
        self.driveLeftSlave.setInverted(False)
        self.driveLeftMaster.setInverted(False)
        self.driveRightSlave.setInverted(True)
        self.driveRightMaster.setInverted(True)
        """
        Initializes the count for toggling which side of the 
        robot will be considered the front when driving.
        """
        self.robotFrontToggleCount = 2

        # Configures each master to use the attached Mag Encoders
        self.driveLeftMaster.configSelectedFeedbackSensor(
            ctre.talonsrx.TalonSRX.FeedbackDevice.CTRE_MagEncoder_Relative, 0,
            0)
        self.driveRightMaster.configSelectedFeedbackSensor(
            ctre.talonsrx.TalonSRX.FeedbackDevice.CTRE_MagEncoder_Relative, 0,
            0)

        # Reverses the encoder direction so forward movement always
        # results in a positive increase in the encoder ticks.
        self.driveLeftMaster.setSensorPhase(True)
        self.driveRightMaster.setSensorPhase(True)

        # these supposedly aren't part of the WPI_TalonSRX class
        # self.driveLeftMaster.setSelectedSensorPostion(0, 0, 10)
        # self.driveRightMaster.setSelectedSensorPosition(0, 0, 10)

        # Throw data on the SmartDashboard so we can work with it.
        # SD.putNumber(
        #     'Left Quad Pos.',
        #     self.driveLeftMaster.getQuadraturePosition())
        # SD.putNumber(
        #     'Right Quad Pos.',
        #     self.driveRightMaster.getQuadraturePosition())

        self.leftVel = None
        self.leftPos = None
        self.rightVel = None
        self.rightPos = None
        self.leftMaxVel = 0
        self.rightMaxVel = 0
        self.leftMinVel = 0
        self.rightMinVel = 0

        # self.driveLeftMaster.config_kP(0, .3, 10)

        self.driveControllerLeft = SpeedControllerGroup(self.driveLeftMaster)
        self.driveControllerRight = SpeedControllerGroup(self.driveRightMaster)
        self.driveControllerRight.setInverted(True)
        self.drive = DifferentialDrive(self.driveControllerLeft,
                                       self.driveControllerRight)

        super().__init__()

    def moveToPosition(self, position, side='left'):

        if side == 'left':
            self.driveLeftMaster.setSafetyEnabled(False)
            self.driveLeftMaster.set(
                ctre.talonsrx.TalonSRX.ControlMode.Position, position)
        else:
            self.driveRightMaster.set(
                ctre.talonsrx.TalonSRX.ControlMode.Position, position)

    def stop(self):
        self.drive.stopMotor()

    def arcade(self, speed, rotation):
        self.updateSD()

        if self.robot.dStick.getRawButtonReleased(3):
            self.robotFrontToggleCount += 1
        """
        This if statement acts as a toggle to change which motors are 
        inverted, completely changing the "front" of the robot. This is
        useful for when we are about to climb.
        """
        if self.robotFrontToggleCount % 2 == 0:
            self.drive.arcadeDrive(speed, rotation, True)
        else:
            self.drive.arcadeDrive(-speed, rotation, True)

    def arcadeWithRPM(self, speed, rotation, maxRPM):

        if self.robot.dStick.getRawButtonReleased(3):
            self.robotFrontToggleCount += 1

        self.driveLeftMaster.setSafetyEnabled(False)

        XSpeed = wpilib.RobotDrive.limit(speed)
        XSpeed = self.applyDeadband(XSpeed, .02)

        ZRotation = wpilib.RobotDrive.limit(rotation)
        ZRotation = self.applyDeadband(ZRotation, .02)

        if self.robotFrontToggleCount % 2 == 1:
            XSpeed = -XSpeed

        XSpeed = math.copysign(XSpeed * XSpeed, XSpeed)
        ZRotation = math.copysign(ZRotation * ZRotation, ZRotation)

        maxInput = math.copysign(max(abs(XSpeed), abs(ZRotation)), XSpeed)

        if XSpeed >= 0.0:
            if ZRotation >= 0.0:
                leftMotorSpeed = maxInput
                rightMotorSpeed = XSpeed - ZRotation
            else:
                leftMotorSpeed = XSpeed + ZRotation
                rightMotorSpeed = maxInput
        else:
            if ZRotation >= 0.0:
                leftMotorSpeed = XSpeed + ZRotation
                rightMotorSpeed = maxInput
            else:
                leftMotorSpeed = maxInput
                rightMotorSpeed = XSpeed - ZRotation

        leftMotorSpeed = wpilib.RobotDrive.limit(leftMotorSpeed)
        rightMotorSpeed = wpilib.RobotDrive.limit(rightMotorSpeed)

        leftMotorRPM = leftMotorSpeed * maxRPM
        rightMotorRPM = rightMotorSpeed * maxRPM

        self.driveLeftMaster.set(ctre.talonsrx.TalonSRX.ControlMode.Velocity,
                                 leftMotorRPM)
        self.driveRightMaster.set(ctre.talonsrx.TalonSRX.ControlMode.Velocity,
                                  rightMotorRPM)

    def updateSD(self):

        leftVel = self.driveLeftMaster.getSelectedSensorVelocity(0)
        leftPos = self.driveLeftMaster.getSelectedSensorPosition(0)

        rightVel = self.driveRightMaster.getSelectedSensorVelocity(0)
        rightPos = self.driveRightMaster.getSelectedSensorPosition(0)

        # keep the biggest velocity values
        if self.leftMaxVel < leftVel:
            self.leftMaxVel = leftVel

        if self.rightMaxVel < rightVel:
            self.rightMaxVel = rightVel

        # keep the smallest velocity values
        if self.leftMinVel > leftVel:
            self.leftMinVel = leftVel

        if self.rightMinVel > rightVel:
            self.rightMinVel = rightVel

        # calculate side deltas
        if self.leftVel:
            leftVelDelta = leftVel - self.leftVel
        else:
            leftVelDelta = 0

        if self.leftPos:
            leftPosDelta = leftPos - self.leftPos
        else:
            leftPosDelta = 0

        if self.rightVel:
            rightVelDelta = rightVel - self.rightVel
        else:
            rightVelDelta = 0

        if self.rightPos:
            rightPosDelta = rightPos - self.rightPos
        else:
            rightPosDelta = 0

        # calculate delta of delta
        differenceVel = leftVelDelta - rightVelDelta
        differencePos = leftPosDelta - rightPosDelta

        SD.putNumber("LeftSensorVel", leftVel)
        SD.putNumber("LeftSensorPos", leftPos)

        SD.putNumber("RightSensorVel", rightVel)
        SD.putNumber("RightSensorPos", rightPos)

        SD.putNumber('LeftVelDelta', leftVelDelta)
        SD.putNumber('LeftPosDelta', leftPosDelta)

        SD.putNumber('RightVelDelta', rightVelDelta)
        SD.putNumber('RightPosDelta', rightPosDelta)

        SD.putNumber('DifferenceVel', differenceVel)
        SD.putNumber('DifferencePos', differencePos)

        SD.putNumber('Left Max Vel', self.leftMaxVel)
        SD.putNumber('Right Max Vel', self.rightMaxVel)

        SD.putNumber('Left Min Vel', self.leftMinVel)
        SD.putNumber('Right Min Vel', self.rightMinVel)

        self.leftVel = leftVel
        self.leftPos = leftPos
        self.rightVel = rightVel
        self.rightPos = rightPos

        # kP = self.driveLeftMaster.configGetParameter(
        #     self.driveLeftMaster.ParamEnum.eProfileParamSlot_P, 0, 10)

        # SmartDashboard.putNumber('Left Proportional', kP)

        # these may give the derivitive an integral of the PID once
        # they are set.  For now, they just show 0
        #SD.putNumber(
        #    'Left Derivative',
        #    self.driveLeftMaster.getErrorDerivative(0))
        #SD.putNumber(
        #    'Left Integral',
        #    self.driveLeftMaster.getIntegralAccumulator(0))
    def applyDeadband(self, value, deadband):
        """Returns 0.0 if the given value is within the specified range around zero. The remaining range
        between the deadband and 1.0 is scaled from 0.0 to 1.0.

        :param value: value to clip
        :param deadband: range around zero
        """
        if abs(value) > deadband:
            if value < 0.0:
                return (value - deadband) / (1.0 - deadband)
            else:
                return (value + deadband) / (1.0 - deadband)
        return 0.0
Exemple #3
0
class DriveTrain(Subsystem):
    '''
    'Tank Drive' system set up with 2 motors per side, one a "master"
    with a mag encoder attached and the other "slave" controller set
    to follow the "master".
    '''
    def __init__(self, robot):

        self.robot = robot

        # Initialize all controllers
        self.driveLeftMaster = Talon(self.robot.kDriveTrain['left_master'])
        self.driveLeftSlave = Talon(self.robot.kDriveTrain['left_slave'])
        self.driveRightMaster = Talon(self.robot.kDriveTrain['right_master'])
        self.driveRightSlave = Talon(self.robot.kDriveTrain['right_slave'])

        wpilib.LiveWindow.addActuator("DriveTrain", "LeftMaster",
                                      self.driveLeftMaster)
        wpilib.LiveWindow.addActuator("DriveTrain", "RightMaster",
                                      self.driveRightMaster)

        # Connect the slaves to the masters on each side
        self.driveLeftSlave.follow(self.driveLeftMaster)
        self.driveRightSlave.follow(self.driveRightMaster)

        # Makes sure both sides' controllers show green and use positive
        # values to move the bot forward.
        self.driveLeftSlave.setInverted(False)
        self.driveLeftMaster.setInverted(False)
        self.driveRightSlave.setInverted(True)
        self.driveRightMaster.setInverted(True)

        # Configures each master to use the attached Mag Encoders
        self.driveLeftMaster.configSelectedFeedbackSensor(
            ctre.talonsrx.TalonSRX.FeedbackDevice.CTRE_MagEncoder_Relative, 0,
            0)
        self.driveRightMaster.configSelectedFeedbackSensor(
            ctre.talonsrx.TalonSRX.FeedbackDevice.CTRE_MagEncoder_Relative, 0,
            0)

        # Reverses the encoder direction so forward movement always
        # results in a positive increase in the encoder ticks.
        self.driveLeftMaster.setSensorPhase(True)
        self.driveRightMaster.setSensorPhase(True)

        self.driveLeftMaster.setQuadraturePosition(0, 0)
        self.driveRightMaster.setQuadraturePosition(0, 0)

        # Throw data on the SmartDashboard so we can work with it.
        # SD.putNumber(
        #     'Left Quad Pos.',
        #     self.driveLeftMaster.getQuadraturePosition())
        # SD.putNumber(
        #     'Right Quad Pos.',
        #     self.driveRightMaster.getQuadraturePosition())

        self.leftVel = None
        self.leftPos = None
        self.rightVel = None
        self.rightPos = None
        self.leftMaxVel = 0
        self.rightMaxVel = 0

        # self.driveLeftMaster.config_kP(0, .3, 10)

        self.driveControllerLeft = SpeedControllerGroup(self.driveLeftMaster)
        self.driveControllerRight = SpeedControllerGroup(self.driveRightMaster)
        self.driveControllerRight.setInverted(True)
        self.drive = DifferentialDrive(self.driveControllerLeft,
                                       self.driveControllerRight)
        # self.drive = DifferentialDrive(self.driveLeftMaster,
        #                               self.driveRightMaster)

        wpilib.LiveWindow.addActuator("DriveTrain", "Left Master",
                                      self.driveLeftMaster)
        wpilib.LiveWindow.addActuator("DriveTrain", "Right Master",
                                      self.driveRightMaster)
        #wpilib.LiveWindow.add(self.driveLeftSlave)
        #wpilib.LiveWindow.add(self.driveRightSlave)
        #wpilib.Sendable.setName(self.drive, 'Drive')
        #wpilib.LiveWindow.add(self.drive)
        #wpilib.Sendable.setName(self.driveLeftMaster, 'driveLeftMaster')
        #wpilib.LiveWindow.add(self.driveRightMaster)

        super().__init__()

    def moveToPosition(self, position, side='left'):

        if side == 'left':
            self.driveLeftMaster.setSafetyEnabled(False)
            self.driveLeftMaster.set(
                ctre.talonsrx.TalonSRX.ControlMode.Position, position)
        else:
            self.driveRightMaster.set(
                ctre.talonsrx.TalonSRX.ControlMode.Position, position)

    def stop(self):
        self.drive.stopMotor()

    def arcade(self, speed, rotation):
        self.updateSD()
        self.drive.arcadeDrive(speed, rotation, True)

    def updateSD(self):

        leftVel = self.driveLeftMaster.getSelectedSensorVelocity(0)
        leftPos = self.driveLeftMaster.getSelectedSensorPosition(0)

        rightVel = self.driveRightMaster.getSelectedSensorVelocity(0)
        rightPos = self.driveRightMaster.getSelectedSensorPosition(0)

        # keep the biggest velocity values
        if self.leftMaxVel < leftVel:
            self.leftMaxVel = leftVel

        if self.rightMaxVel < rightVel:
            self.rightMaxVel = rightVel

        # calculate side deltas
        if self.leftVel:
            leftVelDelta = leftVel - self.leftVel
        else:
            leftVelDelta = 0

        if self.leftPos:
            leftPosDelta = leftPos - self.leftPos
        else:
            leftPosDelta = 0

        if self.rightVel:
            rightVelDelta = rightVel - self.rightVel
        else:
            rightVelDelta = 0

        if self.rightPos:
            rightPosDelta = rightPos - self.rightPos
        else:
            rightPosDelta = 0

        # calculate delta of delta
        differenceVel = leftVelDelta - rightVelDelta
        differencePos = leftPosDelta - rightPosDelta

        SD.putNumber("LeftSensorVel", leftVel)
        SD.putNumber("LeftSensorPos", leftPos)

        SD.putNumber("RightSensorVel", rightVel)
        SD.putNumber("RightSensorPos", rightPos)

        SD.putNumber('LeftVelDelta', leftVelDelta)
        SD.putNumber('LeftPosDelta', leftPosDelta)

        SD.putNumber('RightVelDelta', rightVelDelta)
        SD.putNumber('RightPosDelta', rightPosDelta)

        SD.putNumber('DifferenceVel', differenceVel)
        SD.putNumber('DifferencePos', differencePos)

        SD.putNumber('Left Max Vel', self.leftMaxVel)
        SD.putNumber('Right Max Vel', self.rightMaxVel)

        self.leftVel = leftVel
        self.leftPos = leftPos
        self.rightVel = rightVel
        self.rightPos = rightPos
Exemple #4
0
class Stanley(magicbot.MagicRobot):
    # Magic components
    drive: drive.Drive
    lift: lift.Lift
    intake: intake.Intake
    grabber: grabber.Grabber

    # Control modes
    joystick_control: control.Joystick
    # Gamepad or "Zach" controls
    gamepad_control: control.Gamepad
    mateo_control: control.Mateo
    trevor_control: control.Trevor
    lift_override_control: control.LiftOverride

    angle_ctrl: AngleController

    def createObjects(self):
        # Inputs
        # TODO: Update these dynamically
        self.stick = wpilib.Joystick(2)
        # self.gamepad = wpilib.XboxController(1)
        # self.gamepad_alt = wpilib.XboxController(2)
        self.gamepad = wpilib.XboxController(0)
        self.gamepad_alt = wpilib.XboxController(1)

        # Drive motors
        self.left_motor = wpilib.Spark(0)
        self.right_motor = wpilib.Spark(1)

        self.drive_train = wpilib.drive.DifferentialDrive(
            self.left_motor, self.right_motor)
        self.drive_train.deadband = .04

        # Elevator encoder (gearbox)
        self.lift_encoder = ExternalEncoder(0, 1)
        # TODO: Fix the pid
        # self.lift_encoder.encoder.setDistancePerPulse(WHEEL_REVOLUTION)

        # Drive encoders
        self.left_encoder = ExternalEncoder(2, 3)
        self.right_encoder = ExternalEncoder(4, 5, True)
        self.left_encoder.encoder.setDistancePerPulse(WHEEL_REVOLUTION)
        self.right_encoder.encoder.setDistancePerPulse(WHEEL_REVOLUTION)

        # Elevator motors
        self.lift_master = CANTalon(2)
        self.lift_follower1 = CANTalon(3)
        self.lift_follower2 = CANTalon(4)
        self.lift_follower1.follow(self.lift_master)
        self.lift_follower2.follow(self.lift_master)

        # Intake motors
        self.left_intake_motor = wpilib.Spark(2)
        self.right_intake_motor = wpilib.Spark(3)
        self.right_intake_motor.setInverted(True)

        # Intake grabbers
        self.grabber_solenoid = wpilib.DoubleSolenoid(1, 0, 1)

        # PDP
        self.pdp = wpilib.PowerDistributionPanel(0)
        wpilib.SmartDashboard.putData("PowerDistributionPanel", self.pdp)

        # Misc
        self.navx = navx.AHRS.create_spi()

        self.net_table = NetworkTables.getTable("SmartDashboard")
        self.vision_table = NetworkTables.getTable("limelight")
        self.limelight_x = self.vision_table.getEntry("tx")
        self.limelight_valid = self.vision_table.getEntry("tv")
        self.dashboard_has_target = self.vision_table.getEntry("hastarget")

        # Launch camera server
        wpilib.CameraServer.launch()

    def autonomous(self):
        """Prepare for autonomous mode"""

        magicbot.MagicRobot.autonomous(self)
Exemple #5
0
class DriveTrain(Subsystem):
    '''
    'Tank Drive' system set up with 2 motors per side, one a "master"
    with a mag encoder attached and the other "slave" controller set
    to follow the "master".
    '''
    def __init__(self, robot):

        self.robot = robot

        self.ahrs = AHRS.create_spi()
        self.ahrs.reset()

        #         self.angleAdjustment = self.ahrs.getAngle()
        #         self.ahrs.setAngleAdjustment(self.angleAdjustment)
        # Initialize all controllers
        self.driveLeftMaster = Talon(self.robot.kDriveTrain['left_master'])
        self.driveLeftSlave = Talon(self.robot.kDriveTrain['left_slave'])
        self.driveRightMaster = Talon(self.robot.kDriveTrain['right_master'])
        self.driveRightSlave = Talon(self.robot.kDriveTrain['right_slave'])

        wpilib.LiveWindow.addActuator("DriveTrain", "LeftMaster",
                                      self.driveLeftMaster)
        wpilib.LiveWindow.addActuator("DriveTrain", "RightMaster",
                                      self.driveRightMaster)

        # Connect the slaves to the masters on each side
        self.driveLeftSlave.follow(self.driveLeftMaster)
        self.driveRightSlave.follow(self.driveRightMaster)

        self.driveLeftMaster.configNominalOutputForward(0, 0)
        self.driveLeftMaster.configNominalOutputReverse(0, 0)

        self.driveRightMaster.configNominalOutputForward(0, 0)
        self.driveRightMaster.configNominalOutputReverse(0, 0)

        self.speed = .4
        self.driveLeftMaster.configPeakOutputForward(self.speed, 0)
        self.driveLeftMaster.configPeakOutputReverse(-self.speed, 0)

        self.driveRightMaster.configPeakOutputForward(self.speed, 0)
        self.driveRightMaster.configPeakOutputReverse(-self.speed, 0)

        self.driveLeftMaster.configClosedLoopRamp(.2, 0)
        self.driveRightMaster.configClosedLoopRamp(.2, 0)

        self.driveLeftMaster.setSafetyEnabled(False)
        self.driveRightMaster.setSafetyEnabled(False)

        # Makes sure both sides' controllers show green and use positive
        # values to move the bot forward.
        self.driveLeftSlave.setInverted(False)
        self.driveLeftMaster.setInverted(False)
        self.driveRightSlave.setInverted(True)
        self.driveRightMaster.setInverted(True)

        self.PID()
        """
        Initializes the count for toggling which side of the 
        robot will be considered the front when driving.
        """
        self.robotFrontToggleCount = 2

        # Configures each master to use the attached Mag Encoders
        self.driveLeftMaster.configSelectedFeedbackSensor(
            ctre.talonsrx.TalonSRX.FeedbackDevice.CTRE_MagEncoder_Relative, 0,
            0)
        self.driveRightMaster.configSelectedFeedbackSensor(
            ctre.talonsrx.TalonSRX.FeedbackDevice.CTRE_MagEncoder_Relative, 0,
            0)

        # Reverses the encoder direction so forward movement always
        # results in a positive increase in the encoder ticks.
        self.driveLeftMaster.setSensorPhase(True)
        self.driveRightMaster.setSensorPhase(True)

        self.driveLeftMaster.setSelectedSensorPosition(0, 0, 0)
        self.driveRightMaster.setSelectedSensorPosition(0, 0, 0)

        # these supposedly aren't part of the WPI_TalonSRX class
        # self.driveLeftMaster.setSelectedSensorPostion(0, 0, 10)
        # self.driveRightMaster.setSelectedSensorPosition(0, 0, 10)

        # Throw data on the SmartDashboard so we can work with it.
        # SD.putNumber(
        #     'Left Quad Pos.',
        #     self.driveLeftMaster.getQuadraturePosition())
        # SD.putNumber(
        #     'Right Quad Pos.',
        #     self.driveRightMaster.getQuadraturePosition())

        self.leftVel = None
        self.leftPos = None
        self.rightVel = None
        self.rightPos = None

        # self.driveLeftMaster.config_kP(0, .3, 10)

        self.driveControllerLeft = SpeedControllerGroup(self.driveLeftMaster)
        self.driveControllerRight = SpeedControllerGroup(self.driveRightMaster)
        self.driveControllerRight.setInverted(True)
        self.drive = DifferentialDrive(self.driveControllerLeft,
                                       self.driveControllerRight)
        self.drive.setSafetyEnabled(False)

        self.previousError = 0

        super().__init__()

    def autoInit(self):
        self.speed = .5
        self.driveLeftMaster.configPeakOutputForward(self.speed, 0)
        self.driveLeftMaster.configPeakOutputReverse(-self.speed, 0)

        self.driveRightMaster.configPeakOutputForward(self.speed, 0)
        self.driveRightMaster.configPeakOutputReverse(-self.speed, 0)

        self.driveLeftMaster.config_kP(0, .115, 0)
        self.driveRightMaster.config_kP(0, .115, 0)

        #         self.driveLeftMaster.config_kP(0, .185, 0)
        #         self.driveRightMaster.config_kP(0, .185, 0)

        #         self.driveLeftMaster.config_kP(0, 20, 0)
        #         self.driveRightMaster.config_kP(0, 20, 0)

        self.driveLeftMaster.config_kF(0, 0.0, 0)
        self.driveRightMaster.config_kF(0, 0.0, 0)

    def teleInit(self):
        self.speed = .55
        self.driveLeftMaster.configPeakOutputForward(self.speed, 0)
        self.driveLeftMaster.configPeakOutputReverse(-self.speed, 0)

        self.driveRightMaster.configPeakOutputForward(self.speed, 0)
        self.driveRightMaster.configPeakOutputReverse(-self.speed, 0)

        self.driveLeftMaster.config_kP(0, 0.0, 0)
        self.driveRightMaster.config_kP(0, 0.0, 0)

        self.driveLeftMaster.config_kF(0, 0.313, 0)
        self.driveRightMaster.config_kF(0, 0.313, 0)

    def moveToPosition(self, position):
        self.driveLeftMaster.set(ctre.talonsrx.TalonSRX.ControlMode.Position,
                                 position)

        self.driveRightMaster.set(ctre.talonsrx.TalonSRX.ControlMode.Position,
                                  position)

    def stop(self):
        self.drive.stopMotor()

    def arcade(self, speed, rotation):
        #         self.updateSD()

        if self.robot.dStick.getRawButtonReleased(3):
            self.robotFrontToggleCount += 1
        """
        This if statement acts as a toggle to change which motors are 
        inverted, completely changing the "front" of the robot. This is
        useful for when we are about to climb.
        """
        if self.robotFrontToggleCount % 2 == 0:
            self.drive.arcadeDrive(speed, rotation, True)
        else:
            self.drive.arcadeDrive(-speed, rotation, True)

    def arcadeWithRPM(self, speed, rotation, maxRPM):
        #         self.updateSD()
        self.driveLeftMaster.setSafetyEnabled(False)

        if self.robot.dStick.getRawButtonReleased(3):
            self.robotFrontToggleCount += 1

        if self.robotFrontToggleCount % 2 == 0:
            XSpeed = wpilib.RobotDrive.limit(speed)
        else:
            XSpeed = wpilib.RobotDrive.limit(-speed)

        XSpeed = self.applyDeadband(XSpeed, .02)

        ZRotation = wpilib.RobotDrive.limit(rotation)
        ZRotation = self.applyDeadband(ZRotation, .02)

        XSpeed = math.copysign(XSpeed * XSpeed, XSpeed)
        ZRotation = math.copysign(ZRotation * ZRotation, ZRotation)

        maxInput = math.copysign(max(abs(XSpeed), abs(ZRotation)), XSpeed)

        if XSpeed >= 0.0:
            if ZRotation >= 0.0:
                leftMotorSpeed = maxInput
                rightMotorSpeed = XSpeed - ZRotation
            else:
                leftMotorSpeed = XSpeed + ZRotation
                rightMotorSpeed = maxInput
        else:
            if ZRotation >= 0.0:
                leftMotorSpeed = XSpeed + ZRotation
                rightMotorSpeed = maxInput
            else:
                leftMotorSpeed = maxInput
                rightMotorSpeed = XSpeed - ZRotation

        leftMotorSpeed = wpilib.RobotDrive.limit(leftMotorSpeed)
        rightMotorSpeed = wpilib.RobotDrive.limit(rightMotorSpeed)

        leftMotorRPM = leftMotorSpeed * maxRPM
        rightMotorRPM = rightMotorSpeed * maxRPM

        self.driveLeftMaster.set(ctre.talonsrx.TalonSRX.ControlMode.Velocity,
                                 leftMotorRPM)
        self.driveRightMaster.set(ctre.talonsrx.TalonSRX.ControlMode.Velocity,
                                  rightMotorRPM)

    def updateSD(self):

        leftVel = self.driveLeftMaster.getSelectedSensorVelocity(0)
        leftPos = self.driveLeftMaster.getSelectedSensorPosition(0)

        rightVel = self.driveRightMaster.getSelectedSensorVelocity(0)
        rightPos = self.driveRightMaster.getSelectedSensorPosition(0)

        # calculate side deltas
        if self.leftVel:
            leftVelDelta = leftVel - self.leftVel
        else:
            leftVelDelta = 0

        if self.leftPos:
            leftPosDelta = leftPos - self.leftPos
        else:
            leftPosDelta = 0

        if self.rightVel:
            rightVelDelta = rightVel - self.rightVel
        else:
            rightVelDelta = 0

        if self.rightPos:
            rightPosDelta = rightPos - self.rightPos
        else:
            rightPosDelta = 0

        # calculate delta of delta
        differenceVel = leftVelDelta - rightVelDelta
        differencePos = leftPosDelta - rightPosDelta

        SD.putNumber("LeftSensorVel", leftVel)
        SD.putNumber("LeftSensorPos", leftPos)

        SD.putNumber("RightSensorVel", rightVel)
        SD.putNumber("RightSensorPos", rightPos)

        SD.putNumber('LeftVelDelta', leftVelDelta)
        SD.putNumber('LeftPosDelta', leftPosDelta)

        SD.putNumber('RightVelDelta', rightVelDelta)
        SD.putNumber('RightPosDelta', rightPosDelta)

        SD.putNumber('DifferenceVel', differenceVel)
        SD.putNumber('DifferencePos', differencePos)

        SD.putNumber('Angle', self.ahrs.getAngle())
        SD.putNumber('Angle Adjustment', self.ahrs.getAngleAdjustment())

        self.leftVel = leftVel
        self.leftPos = leftPos
        self.rightVel = rightVel
        self.rightPos = rightPos

        # kP = self.driveLeftMaster.configGetParameter(
        #     self.driveLeftMaster.ParamEnum.eProfileParamSlot_P, 0, 10)

        # SmartDashboard.putNumber('Left Proportional', kP)

        # these may give the derivitive an integral of the PID once
        # they are set.  For now, they just show 0
        #SD.putNumber(
        #    'Left Derivative',
        #    self.driveLeftMaster.getErrorDerivative(0))
        #SD.putNumber(
        #    'Left Integral',
        #    self.driveLeftMaster.getIntegralAccumulator(0))

    def applyDeadband(self, value, deadband):
        """Returns 0.0 if the given value is within the specified range around zero. The remaining range
        between the deadband and 1.0 is scaled from 0.0 to 1.0.

        :param value: value to clip
        :param deadband: range around zero
        """
        if abs(value) > deadband:
            if value < 0.0:
                return (value - deadband) / (1.0 - deadband)
            else:
                return (value + deadband) / (1.0 - deadband)
        return 0.0

    def setAngle(self, angle, tolerance):
        #self.tolerance = tolerance
        #self.calculateAdjustedSetpoint(angle)
        self.turnController.setSetpoint(angle)

        if ((self.ahrs.getYaw() <= (angle + tolerance))
                and (self.ahrs.getYaw() >= (angle - tolerance))):
            self.turnController.disable()

            self.driveLeftMaster.set(0)
            self.driveRightMaster.set(0)

        else:
            self.turnController.enable()

            self.drive.arcadeDrive(0, self.output)

            #self.leftTurnController.setSetpoint(angle)

    def isInGyroPosition(self):
        SD.putNumber('Is in gyro position',
                     ((self.ahrs.getYaw() <=
                       (self.turnController.getSetpoint() +
                        self.robot.autonomous.ANGLE_TOLERANCE)) and
                      (self.ahrs.getYaw() >=
                       (self.turnController.getSetpoint() -
                        self.robot.autonomous.ANGLE_TOLERANCE))))
        return ((self.ahrs.getYaw() <= (self.turnController.getSetpoint() +
                                        self.robot.autonomous.ANGLE_TOLERANCE))
                and (self.ahrs.getYaw() >=
                     (self.turnController.getSetpoint() -
                      self.robot.autonomous.ANGLE_TOLERANCE)))

    def calculateAdjustedSetpoint(self, angle):
        self.startingYaw = self.robot.autonomous.startingYaw
        adjustedAngle = angle + self.startingYaw

        if adjustedAngle < -180:
            undershot = adjustedAngle + 180
            adjustedAngle = 180 + undershot

        elif adjustedAngle > 180:
            overshot = adjustedAngle - 180
            adjustedAngle = -180 + overshot

        self.adjustedSetpoint = adjustedAngle

    def PID(self):
        self.kP = .045
        self.kI = 0.00
        self.kD = 0.00
        self.kF = 0.00

        self.turnController = wpilib.PIDController(self.kP,
                                                   self.kI,
                                                   self.kD,
                                                   self.kF,
                                                   self.ahrs,
                                                   output=self)

        self.turnController.setInputRange(-180, 180)
        self.turnController.setOutputRange(-0.55, 0.55)

        self.turnController.disable()

    def pidWrite(self, output):
        self.output = output