|
| 1 | +#!/usr/bin/env python3 |
| 2 | +""" |
| 3 | + This is a sample program to demonstrate the use of a BangBangController with a flywheel to |
| 4 | + control RPM. |
| 5 | +""" |
| 6 | + |
| 7 | +import wpilib |
| 8 | +import wpilib.simulation |
| 9 | +import wpimath.controller |
| 10 | +from wpimath.system.plant import DCMotor |
| 11 | +import wpimath.units |
| 12 | + |
| 13 | +import math |
| 14 | + |
| 15 | + |
| 16 | +class MyRobot(wpilib.TimedRobot): |
| 17 | + |
| 18 | + MOTOR_PORT = 0 |
| 19 | + ENCODER_A_CHANNEL = 0 |
| 20 | + ENCODER_B_CHANNEL = 1 |
| 21 | + |
| 22 | + # Max setpoint for joystick control in RPM |
| 23 | + MAX_SETPOINT_VALUE = 6000.0 |
| 24 | + |
| 25 | + # Gains are for example purposes only - must be determined for your own robot! |
| 26 | + FLYWHEEL_KS = 0.0001 # V |
| 27 | + FLYWHEEL_KV = 0.000195 # V/RPM |
| 28 | + FLYWHEEL_KA = 0.0003 # V/(RPM/s) |
| 29 | + |
| 30 | + # Reduction between motors and encoder, as output over input. If the flywheel |
| 31 | + # spins slower than the motors, this number should be greater than one. |
| 32 | + FLYWHEEL_GEARING = 1.0 |
| 33 | + |
| 34 | + # 1/2 MR² |
| 35 | + FLYWHEEL_MOMENT_OF_INERTIA = 0.5 * wpimath.units.lbsToKilograms(1.5) * math.pow(wpimath.units.inchesToMeters(4), 2) |
| 36 | + |
| 37 | + def robotInit(self): |
| 38 | + """Robot initialization function""" |
| 39 | + |
| 40 | + self.feedforward = wpimath.controller.SimpleMotorFeedforwardMeters(self.FLYWHEEL_KS, self.FLYWHEEL_KV, self.FLYWHEEL_KA) |
| 41 | + |
| 42 | + # Joystick to control setpoint |
| 43 | + self.joystick = wpilib.Joystick(0) |
| 44 | + |
| 45 | + self.flywheelMotor = wpilib.PWMSparkMax(self.MOTOR_PORT) |
| 46 | + self.encoder = wpilib.Encoder(self.ENCODER_A_CHANNEL, self.ENCODER_B_CHANNEL) |
| 47 | + |
| 48 | + self.bangBangControler = wpimath.controller.BangBangController() |
| 49 | + |
| 50 | + # Simulation classes help us simulate our robot |
| 51 | + self.flywheelSim = wpilib.simulation.FlywheelSim(DCMotor.NEO(1), self.FLYWHEEL_GEARING, self.FLYWHEEL_MOMENT_OF_INERTIA); |
| 52 | + self.encoderSim = wpilib.simulation.EncoderSim(self.encoder) |
| 53 | + |
| 54 | + # Add bang-bang controler to SmartDashboard and networktables. |
| 55 | + wpilib.SmartDashboard.putData(self.bangBangControler) |
| 56 | + |
| 57 | + def teleopPeriodic(self): |
| 58 | + """Controls flywheel to a set speed (RPM) controlled by a joystick.""" |
| 59 | + |
| 60 | + # Scale setpoint value between 0 and maxSetpointValue |
| 61 | + setpoint = max( |
| 62 | + 0.0, |
| 63 | + self.joystick.getRawAxis(0) * wpimath.units.rotationsPerMinuteToRadiansPerSecond(self.MAX_SETPOINT_VALUE) |
| 64 | + ) |
| 65 | + |
| 66 | + # Set setpoint and measurement of the bang-bang controller |
| 67 | + bangOutput = self.bangBangControler.calculate(self.encoder.getRate(), setpoint) * 12.0 |
| 68 | + |
| 69 | + # Controls a motor with the output of the BangBang controller and a |
| 70 | + # feedforward. The feedforward is reduced slightly to avoid overspeeding |
| 71 | + # the shooter. |
| 72 | + self.flywheelMotor.setVoltage(bangOutput + 0.9 * self.feedforward.calculate(setpoint)) |
| 73 | + |
| 74 | + def _simulationPeriodic(self): |
| 75 | + """Update our simulation. This should be run every robot loop in simulation.""" |
| 76 | + |
| 77 | + # To update our simulation, we set motor voltage inputs, update the |
| 78 | + # simulation, and write the simulated velocities to our simulated encoder |
| 79 | + self.flywheelSim.setInputVoltage(self.flywheelMotor.get() * wpilib.RobotController.getInputVoltage()) |
| 80 | + self.flywheelSim.update(0.02) |
| 81 | + self.encoderSim.setRate(self.flywheelSim.getAngularVelocity()) |
| 82 | + |
| 83 | + |
| 84 | +if __name__ == "__main__": |
| 85 | + wpilib.run(MyRobot) |
0 commit comments