Skip to content

Commit 9253953

Browse files
authored
Sync ramsete example with java ramsete-command example (#96)
1 parent df09d17 commit 9253953

File tree

5 files changed

+108
-143
lines changed

5 files changed

+108
-143
lines changed

ramsete/constants.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,26 @@
3737
kEncoderCPR = 1024
3838
kWheelDiameterMeters = 0.15
3939

40-
# The following works assuming the encoders are directly mounted to the wheel shafts.
40+
# Assumes the encoders are directly mounted on the wheel shafts
4141
kEncoderDistancePerPulse = (kWheelDiameterMeters * math.pi) / kEncoderCPR
4242

43-
# NOTE: Please do NOT use these values on your robot. Rather, characterize your
44-
# drivetrain using the FRC Characterization tool. These are for demo purposes
45-
# only!
43+
# These are example values only - DO NOT USE THESE FOR YOUR OWN ROBOT!
44+
# These characterization values MUST be determined either experimentally or theoretically
45+
# for *your* robot's drive.
46+
# The Robot Characterization Toolsuite provides a convenient tool for obtaining these
47+
# values for your robot.
4648
ksVolts = 0.22
4749
kvVoltSecondsPerMeter = 1.98
4850
kaVoltSecondsSquaredPerMeter = 0.2
4951

50-
# The P gain for our turn controllers.
52+
# Example value only - as above, this must be tuned for your drive!
5153
kPDriveVel = 8.5
5254

5355
# The max velocity and acceleration for our autonomous.
5456
kMaxSpeedMetersPerSecond = 3
55-
kMaxAccelerationMetersPerSecondSquared = 3
57+
kMaxAccelerationMetersPerSecondSquared = 1
5658

57-
# Baseline values for a RAMSETE follower in units of meters
58-
# and seconds. These are recommended, but may be changes if wished.
59+
# Reasonable baseline values for a RAMSETE follower in units of meters and seconds.
5960
kRamseteB = 2
6061
kRamseteZeta = 0.7
6162

ramsete/physics.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@
2222
EncoderSim,
2323
AnalogGyroSim,
2424
)
25-
from wpimath.system import LinearSystemId
26-
from wpimath.system.plant import DCMotor
25+
from wpimath.system.plant import DCMotor, LinearSystemId
2726

2827
import constants
2928

@@ -74,10 +73,10 @@ def __init__(self, physics_controller: PhysicsInterface, robot: "MyRobot"):
7473
(constants.kWheelDiameterMeters / 2),
7574
)
7675

77-
self.leftEncoderSim = EncoderSim(robot.container.robotDrive.leftEncoder)
78-
self.rightEncoderSim = EncoderSim(robot.container.robotDrive.rightEncoder)
76+
self.leftEncoderSim = EncoderSim(robot.robotContainer.robotDrive.leftEncoder)
77+
self.rightEncoderSim = EncoderSim(robot.robotContainer.robotDrive.rightEncoder)
7978

80-
self.gyro = AnalogGyroSim(robot.container.robotDrive.gyro)
79+
self.gyro = AnalogGyroSim(robot.robotContainer.robotDrive.gyro)
8180

8281
def update_sim(self, now: float, tm_diff: float) -> None:
8382
"""

ramsete/robot.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,19 @@ def robotInit(self) -> None:
3030

3131
# Instantiate our RobotContainer. This will perform all our button bindings, and put our
3232
# autonomous chooser on the dashboard.
33-
self.container = RobotContainer()
33+
self.robotContainer = RobotContainer()
3434

3535
def disabledInit(self) -> None:
3636
"""This function is called once each time the robot enters Disabled mode."""
37-
if self.autonomousCommand:
38-
self.autonomousCommand.cancel()
3937

4038
def disabledPeriodic(self) -> None:
4139
"""This function is called periodically when disabled"""
4240

4341
def autonomousInit(self) -> None:
4442
"""This autonomous runs the autonomous command selected by your RobotContainer class."""
45-
self.autonomousCommand = self.container.getAutonomousCommand()
43+
self.autonomousCommand = self.robotContainer.getAutonomousCommand()
4644

45+
# schedule the autonomous command (example)
4746
if self.autonomousCommand:
4847
self.autonomousCommand.schedule()
4948

@@ -65,6 +64,9 @@ def testInit(self) -> None:
6564
# Cancels all running commands at the start of test mode
6665
commands2.CommandScheduler.getInstance().cancelAll()
6766

67+
def testPeriodic(self) -> None:
68+
"""This function is called periodically during test mode"""
69+
6870

6971
if __name__ == "__main__":
7072
wpilib.run(MyRobot)

ramsete/robotcontainer.py

Lines changed: 55 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4,66 +4,73 @@
44
# the WPILib BSD license file in the root directory of this project.
55
#
66

7-
from commands2 import RunCommand, RamseteCommand
8-
from commands2.button import JoystickButton, Button
9-
107
from wpilib import XboxController
118
from wpimath.controller import (
129
RamseteController,
1310
PIDController,
1411
SimpleMotorFeedforwardMeters,
1512
)
16-
17-
from wpimath.kinematics import ChassisSpeeds
18-
19-
from wpilib.interfaces import GenericHID
20-
21-
from wpimath.trajectory.constraint import DifferentialDriveVoltageConstraint
22-
from wpimath.trajectory import TrajectoryConfig, TrajectoryGenerator, Trajectory
23-
2413
from wpimath.geometry import Pose2d, Rotation2d, Translation2d
14+
from wpimath.trajectory.constraint import DifferentialDriveVoltageConstraint
15+
from wpimath.trajectory import TrajectoryConfig, TrajectoryGenerator
2516

26-
from subsystems.drivetrain import Drivetrain
17+
from commands2 import InstantCommand, RunCommand, RamseteCommand, cmd
18+
from commands2.button import JoystickButton
2719

20+
from subsystems.driveSubsystem import DriveSubsystem
2821
import constants
2922

3023

3124
class RobotContainer:
32-
3325
"""
34-
This class hosts the bulk of the robot's functions. Little robot logic needs to be
35-
handled here or in the robot periodic methods, as this is a command-based system.
36-
The structure (commands, subsystems, and button mappings) should be done here.
26+
This class is where the bulk of the robot should be declared. Since Command-based is a
27+
"declarative" paradigm, very little robot logic should actually be handled in the {@link Robot}
28+
periodic methods (other than the scheduler calls). Instead, the structure of the robot (including
29+
subsystems, commands, and button mappings) should be declared here.
3730
"""
3831

3932
def __init__(self):
40-
# Create the driver's controller.
41-
self.driverController = XboxController(constants.kDriverControllerPort)
33+
# The robot's subsystems
34+
self.robotDrive = DriveSubsystem()
4235

43-
# Create an instance of the drivetrain subsystem.
44-
self.robotDrive = Drivetrain()
36+
# The driver's controller.
37+
self.driverController = XboxController(constants.kDriverControllerPort)
4538

46-
# Configure and set the button bindings for the driver's controller.
39+
# Configure the button bindings
4740
self.configureButtons()
4841

49-
# Set the default command for the drive subsystem. It's default command will allow
50-
# the robot to drive with the controller.
51-
42+
# Configure default commands
43+
# Set the default drive command to split-stick arcade drive
5244
self.robotDrive.setDefaultCommand(
45+
# A split-stick arcade command, with forward/backward controlled by the left
46+
# hand, and turning controlled by the right.
5347
RunCommand(
5448
lambda: self.robotDrive.arcadeDrive(
55-
-self.driverController.getRawAxis(1),
56-
self.driverController.getRawAxis(2) * 0.65,
49+
-self.driverController.getLeftY(),
50+
-self.driverController.getRightX(),
5751
),
5852
self.robotDrive,
5953
)
6054
)
6155

56+
def configureButtons(self):
57+
"""
58+
Use this method to define your button->command mappings. Buttons can be created by
59+
instantiating a GenericHID or one of its subclasses (Joystick or XboxController),
60+
and then calling passing it to a JoystickButton.
61+
"""
62+
63+
# Drive at half speed when the right bumper is held
64+
(
65+
JoystickButton(self.driverController, XboxController.Button.kRightBumper)
66+
.onTrue(InstantCommand(lambda: self.robotDrive.setMaxOutput(0.5)))
67+
.onFalse(InstantCommand(lambda: self.robotDrive.setMaxOutput(1)))
68+
)
69+
6270
def getAutonomousCommand(self):
63-
"""Returns the command to be ran during the autonomous period."""
71+
"""Use this to pass the autonomous command to the main {@link Robot} class."""
6472

6573
# Create a voltage constraint to ensure we don't accelerate too fast.
66-
6774
autoVoltageConstraint = DifferentialDriveVoltageConstraint(
6875
SimpleMotorFeedforwardMeters(
6976
constants.ksVolts,
@@ -74,84 +81,54 @@ def getAutonomousCommand(self):
7481
maxVoltage=10, # 10 volts max.
7582
)
7683

77-
# Below will generate the trajectory using a set of programmed configurations
78-
79-
# Create a configuration for the trajctory. This tells the trajectory its constraints
80-
# as well as its resources, such as the kinematics object.
84+
# Create config for trajectory
8185
config = TrajectoryConfig(
8286
constants.kMaxSpeedMetersPerSecond,
8387
constants.kMaxAccelerationMetersPerSecondSquared,
8488
)
85-
86-
# Ensures that the max speed is actually obeyed.
89+
# Add kinematics to ensure max speed is actually obeyed
8790
config.setKinematics(constants.kDriveKinematics)
88-
89-
# Apply the previously defined voltage constraint.
91+
# Apply the voltage constraint
9092
config.addConstraint(autoVoltageConstraint)
9193

92-
# Start at the origin facing the +x direction.
93-
initialPosition = Pose2d(0, 0, Rotation2d(0))
94-
95-
# Here are the movements we also want to make during this command.
96-
# These movements should make an "S" like curve.
97-
movements = [Translation2d(1, 1), Translation2d(2, -1)]
98-
99-
# End at this position, three meters straight ahead of us, facing forward.
100-
finalPosition = Pose2d(3, 0, Rotation2d(0))
101-
10294
# An example trajectory to follow. All of these units are in meters.
10395
self.exampleTrajectory = TrajectoryGenerator.generateTrajectory(
104-
initialPosition,
105-
movements,
106-
finalPosition,
96+
# Start at the origin facing the +x direction.
97+
Pose2d(0, 0, Rotation2d(0)),
98+
# Pass through these two interior waypoints, making an 's' curve path
99+
[Translation2d(1, 1), Translation2d(2, -1)],
100+
# End 3 meters straight ahead of where we started, facing forward
101+
Pose2d(3, 0, Rotation2d(0)),
102+
# Pass config
107103
config,
108104
)
109105

110-
# Below creates the RAMSETE command
111-
112106
ramseteCommand = RamseteCommand(
113-
# The trajectory to follow.
114107
self.exampleTrajectory,
115-
# A reference to a method that will return our position.
116108
self.robotDrive.getPose,
117-
# Our RAMSETE controller.
118109
RamseteController(constants.kRamseteB, constants.kRamseteZeta),
119-
# A feedforward object for the robot.
120110
SimpleMotorFeedforwardMeters(
121111
constants.ksVolts,
122112
constants.kvVoltSecondsPerMeter,
123113
constants.kaVoltSecondsSquaredPerMeter,
124114
),
125-
# Our drive kinematics.
126115
constants.kDriveKinematics,
127-
# A reference to a method which will return a DifferentialDriveWheelSpeeds object.
128116
self.robotDrive.getWheelSpeeds,
129-
# The turn controller for the left side of the drivetrain.
130117
PIDController(constants.kPDriveVel, 0, 0),
131-
# The turn controller for the right side of the drivetrain.
132118
PIDController(constants.kPDriveVel, 0, 0),
133-
# A reference to a method which will set a specified
134-
# voltage to each motor. The command will pass the two parameters.
119+
# RamseteCommand passes volts to the callback
135120
self.robotDrive.tankDriveVolts,
136-
# The subsystems the command should require.
137121
[self.robotDrive],
138122
)
139123

140-
# Reset the robot's position to the starting position of the trajectory.
141-
self.robotDrive.resetOdometry(self.exampleTrajectory.initialPose())
142-
143-
# Return the command to schedule. The "andThen()" will halt the robot after
144-
# the command finishes.
145-
return ramseteCommand.andThen(lambda: self.robotDrive.tankDriveVolts(0, 0))
146-
147-
def configureButtons(self):
148-
"""Configure the buttons for the driver's controller"""
149-
150-
# We won't do anything with this button itself, so we don't need to
151-
# define a variable.
152-
124+
# Reset odometry to the initial pose of the trajectory, run path following
125+
# command, then stop at the end.
153126
(
154-
JoystickButton(self.driverController, XboxController.Button.kRightBumper)
155-
.whenPressed(lambda: self.robotDrive.setSlowMaxOutput(0.5))
156-
.whenReleased(lambda: self.robotDrive.setNormalMaxOutput(1))
127+
cmd.runOnce(
128+
lambda: self.robotDrive.resetOdometry(
129+
self.exampleTrajectory.initialPose()
130+
)
131+
)
132+
.andThen(ramseteCommand)
133+
.andThen(cmd.runOnce(lambda: self.robotDrive.tankDriveVolts(0, 0)))
157134
)

0 commit comments

Comments
 (0)