| description | We will learn how to program an Elevator! |
|---|
{% hint style="danger" %} Mechanism classes are meant to be used with "tightly coupled" mechanisms where the Mechanism has 1 or more motor controlling it on a connected shaft, gearbox, or other linkage.
IF your mechanism is "loosely coupled", you CAN still use YAMS. HOWEVER you have to create and control the SmartMotorController directly as shown in how-do-i-control-a-mechanism-without-a-mechanism-class.md OR use SmartMotorControllerConfig.withLooselyCoupledFollowers(SmartMotorController...)
{% endhint %}
At the end of this tutorial you will have an Elevator that will work in both real life and simulation with the same code!
{% columns %} {% column %}
{% endcolumn %}{% column %}
{% embed url="https://www.youtube.com/shorts/XKmsW8-85Dg" %} {% endcolumn %} {% endcolumns %}
This Elevator will be using the following hardware specs and control details
SparkMaxcontrolling theElevator12:1GearBox on theElevator- Pressing
Awill make theElevatorgo to 0.5m - Pressing
Bwill make theElevatorgo to 1 - Pressing
Xwill make theElevatorgo up. - Pressing
Ywill make theElevatorgo down.
{% hint style="success" %}
IF you already have a project and know how to place the Elevator mechanism into your own subsystem please skip to #install-yams
{% endhint %}
Here we will follow WPILib's tutorial on how to create a Command-Based project.
Bring up the Visual Studio Code command palette with Ctrl+Shift+P. Then, type “WPILib” into the prompt. Since all WPILib commands start with “WPILib”, this will bring up the list of WPILib-specific VS Code commands. Now, select the “Create a new project” command:
This will bring up the “New Project Creator Window:”
- Click on Select a project type (Example or Template)
- Select Template then Java then Command Robot
- Click on Select a new project folder and select a folder to store your robot project in.
- Fill in Project Name with the name of your robot code project.
- Enter your Team Number in so you can deploy to your robot.
- Be sure to check Enable Desktop Support so we can run simulations!
If you followed these instructions it should look something like whats filled out below.
Congratulations! You now have a Command Based robot project!
Click on the WPILib logo on the left pane. Scroll down to Yet Another Mechanism System and click Install!
Congratulations you have now installed YAMS! 🎉
{% stepper %} {% step %}
We are going to start by configuring out motor controller.
// 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.
package frc.robot.subsystems;
import static edu.wpi.first.units.Units.Amps;
import static edu.wpi.first.units.Units.Inches;
import static edu.wpi.first.units.Units.MetersPerSecond;
import static edu.wpi.first.units.Units.MetersPerSecondPerSecond;
import static edu.wpi.first.units.Units.Seconds;
import edu.wpi.first.math.controller.ElevatorFeedforward;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import yams.mechanisms.SmartMechanism;
import yams.motorcontrollers.SmartMotorControllerConfig;
import yams.motorcontrollers.SmartMotorControllerConfig.ControlMode;
import yams.motorcontrollers.SmartMotorControllerConfig.MotorMode;
import yams.motorcontrollers.SmartMotorControllerConfig.TelemetryVerbosity;
public class ExampleSubsystem extends SubsystemBase {
private SmartMotorControllerConfig smcConfig = new SmartMotorControllerConfig(this)
.withControlMode(ControlMode.CLOSED_LOOP)
// Drum radius is required for elevators. Chain-driven: specify chain pitch and tooth count.
.withDrumRadius(Inches.of(0.25), 22)
// Feedback Constants (PID Constants)
.withClosedLoopController(4, 0, 0)
.withTrapezoidalProfile(MetersPerSecond.of(0.5), MetersPerSecondPerSecond.of(0.5))
.withSimClosedLoopController(4, 0, 0)
// Feedforward Constants
.withFeedforward(new ElevatorFeedforward(0, 0, 0))
.withSimFeedforward(new ElevatorFeedforward(0, 0, 0))
// Telemetry name and verbosity level
.withTelemetry("ElevatorMotor", TelemetryVerbosity.HIGH)
// Gearing from the motor rotor to final shaft.
// In this example GearBox.fromReductionStages(3,4) is the same as GearBox.fromStages("3:1","4:1") which corresponds to the gearbox attached to your motor.
// You could also use .withGearing(12) which does the same thing.
.withGearing(new MechanismGearing(GearBox.fromReductionStages(3, 4)))
// Motor properties to prevent over currenting.
.withMotorInverted(false)
.withIdleMode(MotorMode.BRAKE)
.withStatorCurrentLimit(Amps.of(40))
.withClosedLoopRampRate(Seconds.of(0.25))
.withOpenLoopRampRate(Seconds.of(0.25));
/** Creates a new ExampleSubsystem. */
public ExampleSubsystem() {}
/**
* Example command factory method.
*
* @return a command
*/
public Command exampleMethodCommand() {
// Inline construction of command goes here.
// Subsystem::RunOnce implicitly requires `this` subsystem.
return runOnce(
() -> {
/* one-time action goes here */
});
}
/**
* An example method querying a boolean state of the subsystem (for example, a digital sensor).
*
* @return value of some boolean subsystem state, such as a digital sensor.
*/
public boolean exampleCondition() {
// Query some boolean state, such as a digital sensor.
return false;
}
@Override
public void periodic() {
// This method will be called once per scheduler run
}
@Override
public void simulationPeriodic() {
// This method will be called once per scheduler run during simulation
}
}
{% hint style="info" %}
withDrumRadius is required for all elevators — it tells YAMS how far the mechanism travels per motor revolution.
Chain-driven elevator (sprocket + chain): pass the chain pitch and tooth count.
#25 chainhas a pitch of 0.25 in#35 chainhas a pitch of 0.375 in
.withDrumRadius(Inches.of(0.25), 22) // #25 chain, 22-tooth sprocket
.withDrumRadius(Inches.of(0.375), 16) // #35 chain, 16-tooth sprocketSpool or direct-drive drum: pass the physical radius of the drum.
.withDrumRadius(Inches.of(0.875)) // drum with 0.875" radiusCascading elevators: call .withCascadingElevatorStages(n) in addition to withDrumRadius. This divides the gearing by the number of stages so position tracking remains correct.
.withDrumRadius(Inches.of(0.25), 22)
.withCascadingElevatorStages(2) // 2-stage cascade; divides gearing by 2{% endhint %}
{% endstep %}
{% step %}
To control our Elevator motor we will create the vendor motor controller object.
First we install REVLib by clicking on the WPILib logo in the left bar.
Now we add it to the ExampleSubsystem.java
// 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.
package frc.robot.subsystems;
import static edu.wpi.first.units.Units.Amps;
import static edu.wpi.first.units.Units.Inches;
import static edu.wpi.first.units.Units.Meters;
import static edu.wpi.first.units.Units.MetersPerSecond;
import static edu.wpi.first.units.Units.MetersPerSecondPerSecond;
import static edu.wpi.first.units.Units.Seconds;
import com.revrobotics.spark.SparkLowLevel.MotorType;
import com.revrobotics.spark.SparkMax;
import edu.wpi.first.math.controller.ArmFeedforward;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import yams.mechanisms.SmartMechanism;
import yams.motorcontrollers.SmartMotorControllerConfig;
import yams.motorcontrollers.SmartMotorControllerConfig.ControlMode;
import yams.motorcontrollers.SmartMotorControllerConfig.MotorMode;
import yams.motorcontrollers.SmartMotorControllerConfig.TelemetryVerbosity;
public class ExampleSubsystem extends SubsystemBase {
private SmartMotorControllerConfig smcConfig = new SmartMotorControllerConfig(this)
.withControlMode(ControlMode.CLOSED_LOOP)
// Drum radius is required for elevators. Chain-driven: specify chain pitch and tooth count.
.withDrumRadius(Inches.of(0.25), 22)
// Feedback Constants (PID Constants)
.withClosedLoopController(4, 0, 0)
.withTrapezoidalProfile(MetersPerSecond.of(0.5), MetersPerSecondPerSecond.of(0.5))
.withSimClosedLoopController(4, 0, 0)
// Feedforward Constants
.withFeedforward(new ElevatorFeedforward(0, 0, 0))
.withSimFeedforward(new ElevatorFeedforward(0, 0, 0))
// Telemetry name and verbosity level
.withTelemetry("ElevatorMotor", TelemetryVerbosity.HIGH)
// Gearing from the motor rotor to final shaft.
// In this example GearBox.fromReductionStages(3,4) is the same as GearBox.fromStages("3:1","4:1") which corresponds to the gearbox attached to your motor.
// You could also use .withGearing(12) which does the same thing.
.withGearing(new MechanismGearing(GearBox.fromReductionStages(3, 4)))
// Motor properties to prevent over currenting.
.withMotorInverted(false)
.withIdleMode(MotorMode.BRAKE)
.withStatorCurrentLimit(Amps.of(40))
.withClosedLoopRampRate(Seconds.of(0.25))
.withOpenLoopRampRate(Seconds.of(0.25));
// Vendor motor controller object
private SparkMax spark = new SparkMax(4, MotorType.kBrushless);
/** Creates a new ExampleSubsystem. */
public ExampleSubsystem() {}
/**
* Example command factory method.
*
* @return a command
*/
public Command exampleMethodCommand() {
// Inline construction of command goes here.
// Subsystem::RunOnce implicitly requires `this` subsystem.
return runOnce(
() -> {
/* one-time action goes here */
});
}
/**
* An example method querying a boolean state of the subsystem (for example, a digital sensor).
*
* @return value of some boolean subsystem state, such as a digital sensor.
*/
public boolean exampleCondition() {
// Query some boolean state, such as a digital sensor.
return false;
}
@Override
public void periodic() {
// This method will be called once per scheduler run
}
@Override
public void simulationPeriodic() {
// This method will be called once per scheduler run during simulation
}
}
{% endstep %}
{% step %}
Our SmartMotorController will easily configure and interface with the vendor motor controller object.
// 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.
package frc.robot.subsystems;
import static edu.wpi.first.units.Units.Amps;
import static edu.wpi.first.units.Units.Inches;
import static edu.wpi.first.units.Units.Meters;
import static edu.wpi.first.units.Units.MetersPerSecond;
import static edu.wpi.first.units.Units.MetersPerSecondPerSecond;
import static edu.wpi.first.units.Units.Seconds;
import com.revrobotics.spark.SparkLowLevel.MotorType;
import com.revrobotics.spark.SparkMax;
import edu.wpi.first.math.controller.ElevatorFeedforward;
import edu.wpi.first.math.system.plant.DCMotor;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import yams.mechanisms.SmartMechanism;
import yams.motorcontrollers.SmartMotorController;
import yams.motorcontrollers.SmartMotorControllerConfig;
import yams.motorcontrollers.SmartMotorControllerConfig.ControlMode;
import yams.motorcontrollers.SmartMotorControllerConfig.MotorMode;
import yams.motorcontrollers.SmartMotorControllerConfig.TelemetryVerbosity;
import yams.motorcontrollers.local.SparkWrapper;
public class ExampleSubsystem extends SubsystemBase {
private SmartMotorControllerConfig smcConfig = new SmartMotorControllerConfig(this)
.withControlMode(ControlMode.CLOSED_LOOP)
// Drum radius is required for elevators. Chain-driven: specify chain pitch and tooth count.
.withDrumRadius(Inches.of(0.25), 22)
// Feedback Constants (PID Constants)
.withClosedLoopController(4, 0, 0)
.withTrapezoidalProfile(MetersPerSecond.of(0.5), MetersPerSecondPerSecond.of(0.5))
.withSimClosedLoopController(4, 0, 0)
// Feedforward Constants
.withFeedforward(new ElevatorFeedforward(0, 0, 0))
.withSimFeedforward(new ElevatorFeedforward(0, 0, 0))
// Telemetry name and verbosity level
.withTelemetry("ElevatorMotor", TelemetryVerbosity.HIGH)
// Gearing from the motor rotor to final shaft.
// In this example GearBox.fromReductionStages(3,4) is the same as GearBox.fromStages("3:1","4:1") which corresponds to the gearbox attached to your motor.
// You could also use .withGearing(12) which does the same thing.
.withGearing(new MechanismGearing(GearBox.fromReductionStages(3, 4)))
// Motor properties to prevent over currenting.
.withMotorInverted(false)
.withIdleMode(MotorMode.BRAKE)
.withStatorCurrentLimit(Amps.of(40))
.withClosedLoopRampRate(Seconds.of(0.25))
.withOpenLoopRampRate(Seconds.of(0.25));
// Vendor motor controller object
private SparkMax spark = new SparkMax(4, MotorType.kBrushless);
// Create our SmartMotorController from our Spark and config with the NEO.
private SmartMotorController sparkSmartMotorController = new SparkWrapper(spark, DCMotor.getNEO(1), smcConfig);
/** Creates a new ExampleSubsystem. */
public ExampleSubsystem() {}
/**
* Example command factory method.
*
* @return a command
*/
public Command exampleMethodCommand() {
// Inline construction of command goes here.
// Subsystem::RunOnce implicitly requires `this` subsystem.
return runOnce(
() -> {
/* one-time action goes here */
});
}
/**
* An example method querying a boolean state of the subsystem (for example, a digital sensor).
*
* @return value of some boolean subsystem state, such as a digital sensor.
*/
public boolean exampleCondition() {
// Query some boolean state, such as a digital sensor.
return false;
}
@Override
public void periodic() {
// This method will be called once per scheduler run
}
@Override
public void simulationPeriodic() {
// This method will be called once per scheduler run during simulation
}
}
{% endstep %}
{% step %}
Our Elevator will easily configure the SmartMotorController and create a simple and intuitive interface.
// 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.
package frc.robot.subsystems;
import static edu.wpi.first.units.Units.Amps;
import static edu.wpi.first.units.Units.Inches;
import static edu.wpi.first.units.Units.Meters;
import static edu.wpi.first.units.Units.MetersPerSecond;
import static edu.wpi.first.units.Units.MetersPerSecondPerSecond;
import static edu.wpi.first.units.Units.Feet;
import static edu.wpi.first.units.Units.Pounds;
import static edu.wpi.first.units.Units.Seconds;
import com.revrobotics.spark.SparkLowLevel.MotorType;
import com.revrobotics.spark.SparkMax;
import edu.wpi.first.math.controller.ArmFeedforward;
import edu.wpi.first.math.system.plant.DCMotor;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import yams.mechanisms.SmartMechanism;
import yams.mechanisms.config.ElevatorConfig;
import yams.mechanisms.positional.Elevator;
import yams.motorcontrollers.SmartMotorController;
import yams.motorcontrollers.SmartMotorControllerConfig;
import yams.motorcontrollers.SmartMotorControllerConfig.ControlMode;
import yams.motorcontrollers.SmartMotorControllerConfig.MotorMode;
import yams.motorcontrollers.SmartMotorControllerConfig.TelemetryVerbosity;
import yams.motorcontrollers.local.SparkWrapper;
public class ExampleSubsystem extends SubsystemBase {
private SmartMotorControllerConfig smcConfig = new SmartMotorControllerConfig(this)
.withControlMode(ControlMode.CLOSED_LOOP)
// Drum radius is required for elevators. Chain-driven: specify chain pitch and tooth count.
.withDrumRadius(Inches.of(0.25), 22)
// Feedback Constants (PID Constants)
.withClosedLoopController(4, 0, 0)
.withTrapezoidalProfile(MetersPerSecond.of(0.5), MetersPerSecondPerSecond.of(0.5))
.withSimClosedLoopController(4, 0, 0)
// Feedforward Constants
.withFeedforward(new ElevatorFeedforward(0, 0, 0))
.withSimFeedforward(new ElevatorFeedforward(0, 0, 0))
// Telemetry name and verbosity level
.withTelemetry("ElevatorMotor", TelemetryVerbosity.HIGH)
// Gearing from the motor rotor to final shaft.
// In this example GearBox.fromReductionStages(3,4) is the same as GearBox.fromStages("3:1","4:1") which corresponds to the gearbox attached to your motor.
// You could also use .withGearing(12) which does the same thing.
.withGearing(new MechanismGearing(GearBox.fromReductionStages(3, 4)))
// Motor properties to prevent over currenting.
.withMotorInverted(false)
.withIdleMode(MotorMode.BRAKE)
.withStatorCurrentLimit(Amps.of(40))
.withClosedLoopRampRate(Seconds.of(0.25))
.withOpenLoopRampRate(Seconds.of(0.25));
// Vendor motor controller object
private SparkMax spark = new SparkMax(4, MotorType.kBrushless);
// Create our SmartMotorController from our Spark and config with the NEO.
private SmartMotorController sparkSmartMotorController = new SparkWrapper(spark, DCMotor.getNEO(1), smcConfig);
private ElevatorConfig elevconfig = new ElevatorConfig()
.withHardLimits(Meters.of(0), Meters.of(3))
.withTelemetry("Elevator", TelemetryVerbosity.HIGH)
.withCarriageWeight(Pounds.of(16));
// Elevator Mechanism
private Elevator elevator = new Elevator(elevconfig, sparkSmartMotorController);
/** Creates a new ExampleSubsystem. */
public ExampleSubsystem() {}
/**
* Example command factory method.
*
* @return a command
*/
public Command exampleMethodCommand() {
// Inline construction of command goes here.
// Subsystem::RunOnce implicitly requires `this` subsystem.
return runOnce(
() -> {
/* one-time action goes here */
});
}
/**
* An example method querying a boolean state of the subsystem (for example, a digital sensor).
*
* @return value of some boolean subsystem state, such as a digital sensor.
*/
public boolean exampleCondition() {
// Query some boolean state, such as a digital sensor.
return false;
}
@Override
public void periodic() {
// This method will be called once per scheduler run
elevator.updateTelemetry();
}
@Override
public void simulationPeriodic() {
// This method will be called once per scheduler run during simulation
elevator.simIterate();
}
}
{% endstep %}
{% step %}
We use the Elevator class as a interface to create commands!
// 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.
package frc.robot.subsystems;
import static edu.wpi.first.units.Units.Amps;
import static edu.wpi.first.units.Units.Inches;
import static edu.wpi.first.units.Units.Meters;
import static edu.wpi.first.units.Units.MetersPerSecond;
import static edu.wpi.first.units.Units.MetersPerSecondPerSecond;
import static edu.wpi.first.units.Units.Feet;
import static edu.wpi.first.units.Units.Pounds;
import static edu.wpi.first.units.Units.Second;
import static edu.wpi.first.units.Units.Seconds;
import static edu.wpi.first.units.Units.Volts;
import com.revrobotics.spark.SparkLowLevel.MotorType;
import com.revrobotics.spark.SparkMax;
import edu.wpi.first.math.controller.ArmFeedforward;
import edu.wpi.first.math.system.plant.DCMotor;
import edu.wpi.first.units.measure.Distance;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import yams.mechanisms.SmartMechanism;
import yams.mechanisms.config.ElevatorConfig;
import yams.mechanisms.positional.Elevator;
import yams.motorcontrollers.SmartMotorController;
import yams.motorcontrollers.SmartMotorControllerConfig;
import yams.motorcontrollers.SmartMotorControllerConfig.ControlMode;
import yams.motorcontrollers.SmartMotorControllerConfig.MotorMode;
import yams.motorcontrollers.SmartMotorControllerConfig.TelemetryVerbosity;
import yams.motorcontrollers.local.SparkWrapper;
public class ExampleSubsystem extends SubsystemBase {
private SmartMotorControllerConfig smcConfig = new SmartMotorControllerConfig(this)
.withControlMode(ControlMode.CLOSED_LOOP)
// Drum radius is required for elevators. Chain-driven: specify chain pitch and tooth count.
.withDrumRadius(Inches.of(0.25), 22)
// Feedback Constants (PID Constants)
.withClosedLoopController(4, 0, 0)
.withTrapezoidalProfile(MetersPerSecond.of(0.5), MetersPerSecondPerSecond.of(0.5))
.withSimClosedLoopController(4, 0, 0)
// Feedforward Constants
.withFeedforward(new ElevatorFeedforward(0, 0, 0))
.withSimFeedforward(new ElevatorFeedforward(0, 0, 0))
// Telemetry name and verbosity level
.withTelemetry("ElevatorMotor", TelemetryVerbosity.HIGH)
// Gearing from the motor rotor to final shaft.
// In this example GearBox.fromReductionStages(3,4) is the same as GearBox.fromStages("3:1","4:1") which corresponds to the gearbox attached to your motor.
// You could also use .withGearing(12) which does the same thing.
.withGearing(new MechanismGearing(GearBox.fromReductionStages(3, 4)))
// Motor properties to prevent over currenting.
.withMotorInverted(false)
.withIdleMode(MotorMode.BRAKE)
.withStatorCurrentLimit(Amps.of(40))
.withClosedLoopRampRate(Seconds.of(0.25))
.withOpenLoopRampRate(Seconds.of(0.25));
// Vendor motor controller object
private SparkMax spark = new SparkMax(4, MotorType.kBrushless);
// Create our SmartMotorController from our Spark and config with the NEO.
private SmartMotorController sparkSmartMotorController = new SparkWrapper(spark, DCMotor.getNEO(1), smcConfig);
private ElevatorConfig elevconfig = new ElevatorConfig()
.withHardLimits(Meters.of(0), Meters.of(3))
.withTelemetry("Elevator", TelemetryVerbosity.HIGH)
.withCarriageWeight(Pounds.of(16));
// Elevator Mechanism
private Elevator elevator = new Elevator(elevconfig, sparkSmartMotorController);
/**
* Runs the elevator to the given height and does not end the command when reached.
* @param height Distance to go to.
* @return a Command
*/
public Command run(Distance height) { return elevator.run(height);}
/**
* Runs the elevator to the given height and ends the command when reached, but not the closed loop controller.
* @param height Distance to go to.
* @param tolerance Distance tolerance for completion.
* @return A Command
*/
public Command runTo(Distance height, Distance tolerance) { return elevator.runTo(height, tolerance);}
/**
* Set the elevators closed loop controller setpoint.
* @param angle Distance to go to.
*/
public void setHeightSetpoint(Distance height) { elevator.setMeasurementPositionSetpoint(height);}
/**
* Move the elevator up and down.
* @param dutycycle [-1, 1] speed to set the elevator too.
*/
public Command set(double dutycycle) { return elevator.set(dutycycle);}
/**
* Run sysId on the {@link Elevator}
*/
public Command sysId() { return elevator.sysId(Volts.of(7), Volts.of(2).per(Second), Seconds.of(4));}
/** Creates a new ExampleSubsystem. */
public ExampleSubsystem() {}
/**
* Example command factory method.
*
* @return a command
*/
public Command exampleMethodCommand() {
// Inline construction of command goes here.
// Subsystem::RunOnce implicitly requires `this` subsystem.
return runOnce(
() -> {
/* one-time action goes here */
});
}
/**
* An example method querying a boolean state of the subsystem (for example, a digital sensor).
*
* @return value of some boolean subsystem state, such as a digital sensor.
*/
public boolean exampleCondition() {
// Query some boolean state, such as a digital sensor.
return false;
}
@Override
public void periodic() {
// This method will be called once per scheduler run
elevator.updateTelemetry();
}
@Override
public void simulationPeriodic() {
// This method will be called once per scheduler run during simulation
elevator.simIterate();
}
}
{% endstep %}
{% step %}
We bind buttons to use the Command from our Elevator
// 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.
package frc.robot;
import frc.robot.Constants.OperatorConstants;
import frc.robot.commands.Autos;
import frc.robot.commands.ExampleCommand;
import frc.robot.subsystems.ExampleSubsystem;
import static edu.wpi.first.units.Units.Meters;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
import edu.wpi.first.wpilibj2.command.button.Trigger;
/**
* This class is where the bulk of the robot should be declared. Since Command-based is a
* "declarative" paradigm, very little robot logic should actually be handled in the {@link Robot}
* periodic methods (other than the scheduler calls). Instead, the structure of the robot (including
* subsystems, commands, and trigger mappings) should be declared here.
*/
public class RobotContainer {
// The robot's subsystems and commands are defined here...
private final ExampleSubsystem m_exampleSubsystem = new ExampleSubsystem();
// Replace with CommandPS4Controller or CommandJoystick if needed
private final CommandXboxController m_driverController =
new CommandXboxController(OperatorConstants.kDriverControllerPort);
/** The container for the robot. Contains subsystems, OI devices, and commands. */
public RobotContainer() {
// Configure the trigger bindings
configureBindings();
// Set the default command to force the elevator to go to 0.
m_exampleSubsystem.setDefaultCommand(m_exampleSubsystem.run(Meters.of(0)));
}
/**
* Use this method to define your trigger->command mappings. Triggers can be created via the
* {@link Trigger#Trigger(java.util.function.BooleanSupplier)} constructor with an arbitrary
* predicate, or via the named factories in {@link
* edu.wpi.first.wpilibj2.command.button.CommandGenericHID}'s subclasses for {@link
* CommandXboxController Xbox}/{@link edu.wpi.first.wpilibj2.command.button.CommandPS4Controller
* PS4} controllers or {@link edu.wpi.first.wpilibj2.command.button.CommandJoystick Flight
* joysticks}.
*/
private void configureBindings() {
// Schedule `run` when the Xbox controller's B button is pressed,
// cancelling on release.
m_driverController.a().whileTrue(m_exampleSubsystem.run(Meters.of(0.5)));
m_driverController.b().whileTrue(m_exampleSubsystem.run(Meters.of(1)));
// Schedule `set` when the Xbox controller's B button is pressed,
// cancelling on release.
m_driverController.x().whileTrue(m_exampleSubsystem.set(0.3));
m_driverController.y().whileTrue(m_exampleSubsystem.set(-0.3));
}
/**
* Use this to pass the autonomous command to the main {@link Robot} class.
*
* @return the command to run in autonomous
*/
public Command getAutonomousCommand() {
// An example command will be run in autonomous
return Autos.exampleAuto(m_exampleSubsystem);
}
}
{% endstep %}
{% step %}
We can use our Elevator in simulation, with the exact same code that will control the real robot!
Connect an Xbox controller to your system and drag and drop from System Joysticks to Joystick[0]
Open up the Simulated mechanism with NetworkTables -> SmartDashboard -> Elevator-> mechanism
Resize Elevator/mechanism to your liking
Press Teleoperated in Robot State then you can use your controller like its controlling the real robot!
Congratulations on successfully programming your Elevator!! 🎉🎉 {% endstep %} {% endstepper %}
{% hint style="info" %} Examples can be found in the YAMS repository on GitHub.
https://github.com/Yet-Another-Software-Suite/YAMS/tree/master/examples/simple_elevator {% endhint %}


.png)
.png)
.png)
.png)

.png)
.png)
