Changes between Version 10 and Version 11 of ControlSystems/SoftwareTeam/Training/WPILib/CommandBasedProgramming
- Timestamp:
- Feb 23, 2020, 3:30:44 PM (5 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
ControlSystems/SoftwareTeam/Training/WPILib/CommandBasedProgramming
v10 v11 11 11 === Creating a Command-Based Program === 12 12 Create a new project in VSCode (WPILib Icon->Create a new project->Template->Java->Command Robot). Notice that in the project src folder, addition to the Main.java and Robot.java we're used to seeing, the project also has: [[Image(CommandBasedFiles.jpg,align=right,margin=10)]] 13 * OI.java - where the Operator Interface isdefined14 * !RobotMap.java - where global constants are defined (e.g. motor controller addresses)13 * RobotContainer.java - where the subsystems, commands, and button bindings are defined 14 * Constants.java - where global constants are defined (e.g. motor controller addresses) - may be called !RobotMap 15 15 * commands folder - where your Commands will be stored 16 16 * subsystems folder - where your Subsystems will be stored 17 Robot.java still extends !TimedRobot (the framework we've been using until now) and the methods robotInit(), robotPeriodic(), autonomousInit(), autonomousPeriodic(), teleopInit(), teleopPeriodic(). However, it now includes an example subsystem and an instance of the OI (Operator Interface) that represents the driver station; the OI helps bind the controls on the driver station (e.g. joystick, xbox controller) to the activities (commands, command groups) that your robot will be performing. For example, the OI allows you to connect a button on your controller to an activity like launchinga frisbee.17 Robot.java still extends !TimedRobot (the framework we've been using until now) and the methods robotInit(), robotPeriodic(), autonomousInit(), autonomousPeriodic(), teleopInit(), teleopPeriodic(). However, it now creates and instance of the !RobotContainer class that creates the robot subsystems, user interface objects(xbox controller, joysticks, etc.) and binds button presses to the activities (commands, command groups) that your robot will be performing. For example, when the X button is pressed on your controller run a command to launch a frisbee. 18 18 19 19 === Example Code === … … 22 22 The following is an example of a very simple Command Based Robot that has a single subsystem consisting of a servo motor with two positions: Open, Closed and they are selected using the A and B buttons on a gamepad. The servo motor should be connected to PWM port 0 and the code uses a Logitech F310 for the operator interface. Replace the template files with: 23 23 24 !RobotMap.java:24 Constants.java: 25 25 {{{ 26 26 package frc.robot; 27 public class RobotMap { 28 public static int SERVO_PORT = 0; // PWM port for servo motor 29 public static int OPEN_BUTTON = 1; // A button opens mechanism 30 public static int CLOSE_BUTTON = 2; // B button closes mechanism 27 28 public final class Constants { 29 public static int SERVO_PORT = 0; // PWM port for servo motor 30 public static int OPEN_BUTTON = 1; // A button opens mechanism 31 public static int CLOSE_BUTTON = 2; // B button closes mechanism 31 32 } 32 33 }}} … … 36 37 package frc.robot.subsystems; 37 38 38 import edu.wpi.first.wpilibj .command.Subsystem;39 import frc.robot. RobotMap;39 import edu.wpi.first.wpilibj2.command.SubsystemBase; 40 import frc.robot.Constants; 40 41 import edu.wpi.first.wpilibj.Servo; 41 42 42 public class ServoSubsystem extends Subsystem {43 public class ServoSubsystem extends SubsystemBase { 43 44 private Servo servo; 44 45 … … 46 47 47 48 private ServoSubsystem() { 48 servo = new Servo( RobotMap.SERVO_PORT);49 servo = new Servo(Constants.SERVO_PORT); 49 50 } 50 51 … … 59 60 public void setAngle(double degrees) { 60 61 servo.setAngle(degrees); 61 }62 63 @Override64 public void initDefaultCommand() {65 62 } 66 63 } … … 94 91 package frc.robot.commands; 95 92 96 import edu.wpi.first.wpilibj.command.Command; 97 import frc.robot.Robot; 93 import edu.wpi.first.wpilibj2.command.CommandBase; 94 import edu.wpi.first.wpilibj2.command.SubsystemBase; 95 import frc.robot.subsystems.ServoSubsystem; 98 96 99 public class CloseCommand extends Command { 100 public CloseCommand() { 101 requires(Robot.m_servo); // servo must be available 102 } 97 public class CloseCommand extends CommandBase { 103 98 104 @Override 105 protected boolean isFinished() { 106 System.out.println("Close Pressed."); 107 Robot.m_servo.setAngle(120); // set servo to closed position 108 return true; // and then finish 109 } 99 public CloseCommand(SubsystemBase servoSubsystem) { 100 addRequirements(servoSubsystem); 101 } 102 103 @Override 104 public boolean isFinished() { 105 System.out.println("Close Pressed."); 106 ServoSubsystem.getInstance().setAngle(120); // set servo to closed position 107 return true; // and then finish 108 } 110 109 } 111 110 }}} 112 111 113 OI.java:112 RobotContainer.java: 114 113 {{{ 115 114 package frc.robot; 116 115 117 116 import edu.wpi.first.wpilibj.XboxController; 118 import edu.wpi.first.wpilibj.buttons.Button; 119 import edu.wpi.first.wpilibj.buttons.JoystickButton; 120 import frc.robot.RobotMap; 121 import frc.robot.commands.*; 117 import edu.wpi.first.wpilibj2.command.button.Button; 118 import edu.wpi.first.wpilibj2.command.button.JoystickButton; 119 import edu.wpi.first.wpilibj2.command.Command; 120 import frc.robot.subsystems.ServoSubsystem; 121 import frc.robot.commands.OpenCommand; 122 import frc.robot.commands.CloseCommand; 122 123 123 public class OI{124 XboxController xbox = new XboxController(0);125 Button openButton = new JoystickButton(xbox, RobotMap.OPEN_BUTTON);126 Button closeButton = new JoystickButton(xbox, RobotMap.CLOSE_BUTTON);124 public class RobotContainer { 125 private final ServoSubsystem m_servo = ServoSubsystem.getInstance(); 126 private final XboxController xbox; 127 private final Button openButton, closeButton; 127 128 128 public OI() { 129 openButton.whenPressed(new OpenCommand()); 130 closeButton.whenPressed(new CloseCommand()); 129 public RobotContainer() { 130 xbox = new XboxController(0); 131 openButton = new JoystickButton(xbox, Constants.OPEN_BUTTON); 132 closeButton = new JoystickButton(xbox, Constants.CLOSE_BUTTON); 133 134 // Configure the button bindings 135 configureButtonBindings(); 136 } 137 138 private void configureButtonBindings() { 139 openButton.whenPressed(new OpenCommand(m_servo)); 140 closeButton.whenPressed(new CloseCommand(m_servo)); 141 } 142 143 public Command getAutonomousCommand() { 144 return null; 131 145 } 132 146 } … … 138 152 139 153 import edu.wpi.first.wpilibj.TimedRobot; 140 import edu.wpi.first.wpilibj.command.Scheduler; 141 import frc.robot.subsystems.ServoSubsystem; 154 import edu.wpi.first.wpilibj2.command.CommandScheduler; 142 155 143 156 public class Robot extends TimedRobot { 144 public static ServoSubsystem m_servo = ServoSubsystem.getInstance(); 145 public static OI m_oi; // operator interface 157 private RobotContainer m_robotContainer; 146 158 147 159 @Override 148 160 public void robotInit() { 149 m_ oi = new OI();161 m_robotContainer = new RobotContainer(); 150 162 } 151 163 152 164 @Override 153 public void disabledPeriodic() { 154 Scheduler.getInstance().run(); // run enabled commands 155 } 156 157 @Override 158 public void autonomousPeriodic() { 159 Scheduler.getInstance().run(); // run enabled commands 160 } 161 162 @Override 163 public void teleopPeriodic() { 164 Scheduler.getInstance().run(); // run enabled commands 165 public void robotPeriodic() { 166 CommandScheduler.getInstance().run(); 165 167 } 166 168 } … … 168 170 169 171 === How it works === 170 Command-based programming is built on top of the ! IterativeRobot template. In each of the template's periodic() methods,Scheduler.getInstance().run() is called. This takes all currently running Commands -- which behave like threads, but can't include waits like typical threads because it's a type of threading known as "cooperative" multitasking -- and runs them, first initializing any new ones and checking whether each one has completed yet. It's useful because these Commands can be easily joined together in CommandGroups to make autonomous modes, or can be mapped to buttons to easily allow complex teleop actions, etc.172 Command-based programming is built on top of the !TimedRobot template. In each of the template's periodic() methods, !CommandScheduler.getInstance().run() is called. This takes all currently running Commands -- which behave like threads, but can't include waits like typical threads because it's a type of threading known as "cooperative" multitasking -- and runs them, first initializing any new ones and checking whether each one has completed yet. It's useful because these Commands can be easily joined together in CommandGroups to make autonomous modes, or can be mapped to buttons to easily allow complex teleop actions, etc. 171 173 172 174 * [https://docs.google.com/document/d/1JHHRGrhe96rJXw6lIM-X3WJKoD14_8PwqjjP45UI0tg/ Intro to Command Based Programming]