This repository was archived by the owner on May 3, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 58
Added example SwerveControllerCommand #108
Open
ryanabraham1
wants to merge
52
commits into
robotpy:main
Choose a base branch
from
ryanabraham1:SwerveControllerCommand
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
52 commits
Select commit
Hold shift + click to select a range
5857476
Added example SwerveControllerCommand
ryanabraham1 18fc1ae
added docstrings
ryanabraham1 c27dc3a
Update run_tests.sh
Suave101 7921298
Merge pull request #1 from Suave101/patch-1
ryanabraham1 0fff226
Lowercased all files and folders, reformmated code with black, fixed …
ryanabraham1 f126455
Converted header docstrings into comments
ryanabraham1 10a7f17
remove unnecessary files
ryanabraham1 8b66ef6
fixed the renaming of files and directories
ryanabraham1 5ecb389
reran black on directory
ryanabraham1 9df1182
Removed m_ in variables
ryanabraham1 09a1e17
add file header for robot.py
ryanabraham1 07b0365
fixed module import error when import drivesubsystem
ryanabraham1 b4d684d
removed Top-level constants class
ryanabraham1 4e6053b
Update test.yml
ryanabraham1 cac6b9c
Update drivesubsystems.py
ryanabraham1 b384b48
swervecontroller to 3
ryanabraham1 67347ef
Update constants.py
ryanabraham1 d2ecead
Update drivesubsystems.py
ryanabraham1 d97a8a7
Update constants.py
ryanabraham1 c2d71eb
made everything 4
ryanabraham1 1390c7e
added setdefault command
ryanabraham1 0ebecf6
Update drivesubsystems.py
ryanabraham1 cc0789a
Update robotcontainer.py
ryanabraham1 d52d93f
Update drivesubsystems.py
ryanabraham1 8c34f73
Update robotcontainer.py
ryanabraham1 5d82e0d
Update robotcontainer.py
ryanabraham1 8a73f7e
Update robotcontainer.py
ryanabraham1 1de8d65
Update robotcontainer.py
ryanabraham1 3285c47
Update robotcontainer.py
ryanabraham1 bdc25a1
Update robotcontainer.py
ryanabraham1 d3ec49c
Update robotcontainer.py
ryanabraham1 ee841a5
Update robotcontainer.py
ryanabraham1 4dc8861
Update robotcontainer.py
ryanabraham1 954bbe1
Update robotcontainer.py
ryanabraham1 d6e2c1e
Update robotcontainer.py
ryanabraham1 c985aba
Update robot.py
ryanabraham1 9d1550a
Update robotcontainer.py
ryanabraham1 bae17cd
Update robot.py
ryanabraham1 3e60dc8
Update robotcontainer.py
ryanabraham1 2da1b6d
Update robotcontainer.py
ryanabraham1 d3b154e
fixed changes
ryanabraham1 a48c32f
Update robotcontainer.py
ryanabraham1 8de3ce8
Update robot.py
ryanabraham1 3139e04
Update drivesubsystems.py
ryanabraham1 6851048
Update swervemodule.py
ryanabraham1 ebeef3a
Merge branch 'SwerveControllerCommand' of https://github.com/ChaoticC…
ryanabraham1 73b42cd
fixed naming eror
ryanabraham1 d2f2248
fixed swerve controller command
ryanabraham1 0110bac
fixed changes
ryanabraham1 67be4bf
fixed some changes
ryanabraham1 4c99767
fixed docstring
ryanabraham1 6066bec
Merge branch 'SwerveControllerCommand' of https://github.com/ChaoticC…
ryanabraham1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,166 @@ | ||
| """ | ||
| Copyright (c) FIRST and other WPILib contributors. | ||
| Open Source Software; you can modify and/or share it under the terms of | ||
| the WPILib BSD license file in the root directory of this project. | ||
| """ | ||
|
|
||
| from wpilib import ADXRS450_Gyro | ||
| import Subsystems.SwerveModule | ||
| from wpimath.kinematics import ChassisSpeeds | ||
| from wpimath.kinematics import SwerveDrive3Kinematics, SwerveDrive3Odometry | ||
| from wpimath.geometry import Pose2d, Rotation2d | ||
| import constants as Constants | ||
|
|
||
| class DriveSubsystem: | ||
| def __init__(self): | ||
| """ | ||
| Robot swerve modules | ||
| """ | ||
| self.m_frontLeft = SwerveModule( | ||
| Constants.DriveConstants.kFrontLeftDriveMotorPort, | ||
| Constants.DriveConstants.kFrontLeftTurningMotorPort, | ||
| Constants.DriveConstants.kFrontLeftDriveEncoderPorts, | ||
| Constants.DriveConstants.kFrontLeftTurningEncoderPorts, | ||
| Constants.DriveConstants.kFrontLeftDriveEncoderReversed, | ||
| Constants.DriveConstants.kFrontLeftTurningEncoderReversed | ||
| ) | ||
|
|
||
| self.m_rearLeft = SwerveModule( | ||
| Constants.DriveConstants.kRearLeftDriveMotorPort, | ||
| Constants.DriveConstants.kRearLeftTurningMotorPort, | ||
| Constants.DriveConstants.kRearLeftDriveEncoderPorts, | ||
| Constants.DriveConstants.kRearLeftTurningEncoderPorts, | ||
| Constants.DriveConstants.kRearLeftDriveEncoderReversed, | ||
| Constants.DriveConstants.kRearLeftTurningEncoderReversed | ||
| ) | ||
|
|
||
| self.m_frontRight = SwerveModule( | ||
| Constants.DriveConstants.kFrontRightDriveMotorPort, | ||
| Constants.DriveConstants.kFrontRightTurningMotorPort, | ||
| Constants.DriveConstants.kFrontRightDriveEncoderPorts, | ||
| Constants.DriveConstants.kFrontRightTurningEncoderPorts, | ||
| Constants.DriveConstants.kFrontRightDriveEncoderReversed, | ||
| Constants.DriveConstants.kFrontRightTurningEncoderReversed | ||
| ) | ||
|
|
||
| self.m_rearRight = SwerveModule( | ||
| Constants.DriveConstants.kRearRightDriveMotorPort, | ||
| Constants.DriveConstants.kRearRightTurningMotorPort, | ||
| Constants.DriveConstants.kRearRightDriveEncoderPorts, | ||
| Constants.DriveConstants.kRearRightTurningEncoderPorts, | ||
| Constants.DriveConstants.kRearRightDriveEncoderReversed, | ||
| Constants.DriveConstants.kRearRightTurningEncoderReversed | ||
| ) | ||
|
|
||
| """ | ||
| The gyro sensor | ||
| """ | ||
| self.m_gyro = ADXRS450_Gyro() | ||
|
|
||
| """ | ||
| Odometry class for tracking robot pose | ||
| """ | ||
| self.m_odometry = SwerveDrive3Odometry( | ||
| Constants.DriveConstants.kDriveKinematics, | ||
| self.m_gyro.getRotation2d(), | ||
| [ | ||
| self.m_frontLeft.getPosition(), | ||
| self.m_frontRight.getPosition(), | ||
| self.m_rearLeft.getPosition(), | ||
| self.m_rearRight.getPosition() | ||
| ] | ||
| ) | ||
|
|
||
| def periodic(self): | ||
| """ | ||
| Update the odometry in the periodic block | ||
| """ | ||
| self.m_odometry.update( | ||
| self.m_gyro.getRotation2d(), | ||
| [ | ||
| self.m_frontLeft.getPosition(), | ||
| self.m_frontRight.getPosition(), | ||
| self.m_rearLeft.getPosition(), | ||
| self.m_rearRight.getPosition() | ||
| ] | ||
| ) | ||
|
|
||
| def getPose(self): | ||
| """ | ||
| Returns the currently-estimated pose of the robot. | ||
| """ | ||
| return self.m_odometry.getPoseMeters() | ||
|
|
||
| def resetOdometry(self, pose): | ||
| """ | ||
| Resets the odometry to the specified pose. | ||
| """ | ||
| self.m_odometry.resetPosition( | ||
| self.m_gyro.getRotation2d(), | ||
| [ | ||
| self.m_frontLeft.getPosition(), | ||
| self.m_frontRight.getPosition(), | ||
| self.m_rearLeft.getPosition(), | ||
| self.m_rearRight.getPosition() | ||
| ], | ||
| pose | ||
| ) | ||
|
|
||
| def drive(self, xSpeed, ySpeed, rot, fieldRelative): | ||
| """ | ||
| Method to drive the robot using joystick info. | ||
| """ | ||
| swerveModuleStates = Constants.DriveConstants.kDriveKinematics.toSwerveModuleStates( | ||
| ChassisSpeeds.discretize( | ||
| ChassisSpeeds.fromFieldRelativeSpeeds( | ||
| xSpeed, ySpeed, rot, self.m_gyro.getRotation2d() | ||
| ) if fieldRelative else ChassisSpeeds(xSpeed, ySpeed, rot), | ||
| Constants.DriveConstants.kDrivePeriod | ||
| ) | ||
| ) | ||
| SwerveDrive3Kinematics.desaturateWheelSpeeds( | ||
| swerveModuleStates, Constants.DriveConstants.kMaxSpeedMetersPerSecond | ||
| ) | ||
| self.m_frontLeft.setDesiredState(swerveModuleStates[0]) | ||
| self.m_frontRight.setDesiredState(swerveModuleStates[1]) | ||
| self.m_rearLeft.setDesiredState(swerveModuleStates[2]) | ||
| self.m_rearRight.setDesiredState(swerveModuleStates[3]) | ||
|
|
||
| def setModuleStates(self, desiredStates): | ||
| """ | ||
| Sets the swerve ModuleStates. | ||
| """ | ||
| SwerveDrive3Kinematics.desaturateWheelSpeeds( | ||
| desiredStates, Constants.DriveConstants.kMaxSpeedMetersPerSecond | ||
| ) | ||
| self.m_frontLeft.setDesiredState(desiredStates[0]) | ||
| self.m_frontRight.setDesiredState(desiredStates[1]) | ||
| self.m_rearLeft.setDesiredState(desiredStates[2]) | ||
| self.m_rearRight.setDesiredState(desiredStates[3]) | ||
| def resetEncoders(self): | ||
| """ | ||
| Resets the drive encoders to currently read a position of 0. | ||
| """ | ||
| self.m_frontLeft.resetEncoders() | ||
| self.m_rearLeft.resetEncoders() | ||
| self.m_frontRight.resetEncoders() | ||
| self.m_rearRight.resetEncoders() | ||
|
|
||
| def zeroHeading(self): | ||
| """ | ||
| Zeroes the heading of the robot. | ||
| """ | ||
| self.m_gyro.reset() | ||
|
|
||
| def getHeading(self): | ||
| """ | ||
| Returns the heading of the robot. | ||
| """ | ||
| return self.m_gyro.getRotation2d().getDegrees() | ||
|
|
||
| def getTurnRate(self): | ||
| """ | ||
| Returns the turn rate of the robot. | ||
| """ | ||
| return self.m_gyro.getRate() * (-1.0 if Constants.DriveConstants.kGyroReversed else 1.0) | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| from wpilib import Encoder, Spark | ||
| from wpimath.geometry import Rotation2d | ||
| from wpimath.kinematics import SwerveModulePosition, SwerveModuleState | ||
| from wpimath.trajectory import TrapezoidProfile | ||
| from wpimath.controller import PIDController, ProfiledPIDController | ||
| import constants | ||
|
|
||
| class SwerveModule: | ||
| def __init__( | ||
| self, | ||
| driveMotorChannel, | ||
| turningMotorChannel, | ||
| driveEncoderChannels, | ||
| turningEncoderChannels, | ||
| driveEncoderReversed, | ||
| turningEncoderReversed, | ||
| ): | ||
| self.m_driveMotor = Spark(driveMotorChannel) | ||
| self.m_turningMotor = Spark(turningMotorChannel) | ||
|
|
||
| self.m_driveEncoder = Encoder(*driveEncoderChannels) | ||
| self.m_turningEncoder = Encoder(*turningEncoderChannels) | ||
|
|
||
| self.m_drivePIDController = PIDController( | ||
| constants.ModuleConstants.kPModuleDriveController, 0, 0 | ||
| ) | ||
|
|
||
| self.m_turningPIDController = ProfiledPIDController( | ||
| constants.ModuleConstants.kPModuleTurningController, | ||
| 0, | ||
| 0, | ||
| TrapezoidProfile.Constraints( | ||
| constants.ModuleConstants.kMaxModuleAngularSpeedRadiansPerSecond, | ||
| constants.ModuleConstants.kMaxModuleAngularAccelerationRadiansPerSecondSquared, | ||
| ), | ||
| ) | ||
|
|
||
| """ | ||
| Set the distance per pulse for the drive encoder. | ||
| """ | ||
| self.m_driveEncoder.setDistancePerPulse( | ||
| constants.ModuleConstants.kDriveEncoderDistancePerPulse | ||
| ) | ||
| self.m_driveEncoder.setReverseDirection(driveEncoderReversed) | ||
|
|
||
| """ | ||
| Set the distance in radians per pulse for the turning encoder. | ||
| """ | ||
| self.m_turningEncoder.setDistancePerPulse( | ||
| constants.ModuleConstants.kTurningEncoderDistancePerPulse | ||
| ) | ||
| self.m_turningEncoder.setReverseDirection(turningEncoderReversed) | ||
|
|
||
| """ | ||
| Limit the PID Controller's input range between -pi and pi and set the input | ||
| to be continuous. | ||
| """ | ||
| self.m_turningPIDController.enableContinuousInput(-3.14159, 3.14159) | ||
|
|
||
| def getState(self): | ||
| return SwerveModuleState( | ||
| self.m_driveEncoder.getRate(), | ||
| Rotation2d(self.m_turningEncoder.getDistance()), | ||
| ) | ||
|
|
||
| def getPosition(self): | ||
| return SwerveModulePosition( | ||
| self.m_driveEncoder.getDistance(), | ||
| Rotation2d(self.m_turningEncoder.getDistance()), | ||
| ) | ||
|
|
||
| def setDesiredState(self, desiredState): | ||
| encoderRotation = Rotation2d(self.m_turningEncoder.getDistance()) | ||
|
|
||
| """ | ||
| Optimize the reference state to avoid spinning further than 90 degrees | ||
| """ | ||
| state = SwerveModuleState.optimize(desiredState, encoderRotation) | ||
|
|
||
| """ | ||
| Scale speed by cosine of angle error. | ||
| """ | ||
| state.speedMetersPerSecond *= state.angle.minus(encoderRotation).getCos() | ||
|
|
||
| """ | ||
| Calculate the drive output from the drive PID controller. | ||
| """ | ||
| driveOutput = self.m_drivePIDController.calculate( | ||
| self.m_driveEncoder.getRate(), state.speedMetersPerSecond | ||
| ) | ||
|
|
||
| """ | ||
| Calculate the turning motor output from the turning PID controller. | ||
| """ | ||
| turnOutput = self.m_turningPIDController.calculate( | ||
| self.m_turningEncoder.getDistance(), state.angle.getRadians() | ||
| ) | ||
|
|
||
| """ | ||
| Set motor outputs | ||
| """ | ||
| self.m_driveMotor.set(driveOutput) | ||
| self.m_turningMotor.set(turnOutput) | ||
|
|
||
| def resetEncoders(self): | ||
| self.m_driveEncoder.reset() | ||
| self.m_turningEncoder.reset() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| """ | ||
| Copyright (c) FIRST and other WPILib contributors. | ||
| Open Source Software; you can modify and/or share it under the terms of | ||
| the WPILib BSD license file in the root directory of this project. | ||
| """ | ||
|
|
||
| from wpilib import TimedRobot | ||
| from wpimath.geometry import Translation2d | ||
| from wpimath.kinematics import SwerveDrive4Kinematics | ||
| from wpimath.trajectory import TrapezoidProfile | ||
| import math | ||
|
|
||
| class Constants: | ||
|
ryanabraham1 marked this conversation as resolved.
Outdated
|
||
| class DriveConstants: | ||
| kFrontLeftDriveMotorPort = 0 | ||
| kRearLeftDriveMotorPort = 2 | ||
| kFrontRightDriveMotorPort = 4 | ||
| kRearRightDriveMotorPort = 6 | ||
|
|
||
| kFrontLeftTurningMotorPort = 1 | ||
| kRearLeftTurningMotorPort = 3 | ||
| kFrontRightTurningMotorPort = 5 | ||
| kRearRightTurningMotorPort = 7 | ||
|
|
||
| kFrontLeftTurningEncoderPorts = [0, 1] | ||
| kRearLeftTurningEncoderPorts = [2, 3] | ||
| kFrontRightTurningEncoderPorts = [4, 5] | ||
| kRearRightTurningEncoderPorts = [6, 7] | ||
|
|
||
| kFrontLeftTurningEncoderReversed = False | ||
| kRearLeftTurningEncoderReversed = True | ||
| kFrontRightTurningEncoderReversed = False | ||
| kRearRightTurningEncoderReversed = True | ||
|
|
||
| kFrontLeftDriveEncoderPorts = [8, 9] | ||
| kRearLeftDriveEncoderPorts = [10, 11] | ||
| kFrontRightDriveEncoderPorts = [12, 13] | ||
| kRearRightDriveEncoderPorts = [14, 15] | ||
|
|
||
| kFrontLeftDriveEncoderReversed = False | ||
| kRearLeftDriveEncoderReversed = True | ||
| kFrontRightDriveEncoderReversed = False | ||
| kRearRightDriveEncoderReversed = True | ||
|
|
||
| kDrivePeriod = TimedRobot.kDefaultPeriod | ||
|
|
||
| kTrackWidth = 0.5 | ||
| kWheelBase = 0.7 | ||
| kDriveKinematics = SwerveDrive4Kinematics( | ||
| Translation2d(kWheelBase / 2, kTrackWidth / 2), | ||
| Translation2d(kWheelBase / 2, -kTrackWidth / 2), | ||
| Translation2d(-kWheelBase / 2, kTrackWidth / 2), | ||
| Translation2d(-kWheelBase / 2, -kTrackWidth / 2) | ||
| ) | ||
|
|
||
| kGyroReversed = False | ||
|
|
||
| ksVolts = 1 | ||
| kvVoltSecondsPerMeter = 0.8 | ||
| kaVoltSecondsSquaredPerMeter = 0.15 | ||
|
|
||
| kMaxSpeedMetersPerSecond = 3 | ||
|
|
||
| class ModuleConstants: | ||
| kMaxModuleAngularSpeedRadiansPerSecond = 2 * math.pi | ||
| kMaxModuleAngularAccelerationRadiansPerSecondSquared = 2 * math.pi | ||
|
|
||
| kEncoderCPR = 1024 | ||
| kWheelDiameterMeters = 0.15 | ||
| kDriveEncoderDistancePerPulse = (kWheelDiameterMeters * math.pi) / kEncoderCPR | ||
|
|
||
| kTurningEncoderDistancePerPulse = (2 * math.pi) / kEncoderCPR | ||
|
|
||
| kPModuleTurningController = 1 | ||
| kPModuleDriveController = 1 | ||
|
|
||
| class OIConstants: | ||
| kDriverControllerPort = 0 | ||
|
|
||
| class AutoConstants: | ||
| kMaxSpeedMetersPerSecond = 3 | ||
| kMaxAccelerationMetersPerSecondSquared = 3 | ||
| kMaxAngularSpeedRadiansPerSecond = math.pi | ||
| kMaxAngularSpeedRadiansPerSecondSquared = math.pi | ||
|
|
||
| kPXController = 1 | ||
| kPYController = 1 | ||
| kPThetaController = 1 | ||
|
|
||
| kThetaControllerConstraints = TrapezoidProfile.Constraints( | ||
| kMaxAngularSpeedRadiansPerSecond, kMaxAngularSpeedRadiansPerSecondSquared | ||
| ) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.