// 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.Degrees;
import static edu.wpi.first.units.Units.DegreesPerSecond;
import static edu.wpi.first.units.Units.DegreesPerSecondPerSecond;
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.Angle;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import yams.mechanisms.SmartMechanism;
import yams.mechanisms.config.ArmConfig;
import yams.mechanisms.positional.Arm;
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;
import yams.gearing.GearBox;
import yams.gearing.MechanismGearing;
public class ExampleSubsystem extends SubsystemBase {
private SmartMotorControllerConfig smcConfig = new SmartMotorControllerConfig(this)
.withControlMode(ControlMode.CLOSED_LOOP)
// Feedback Constants (PID Constants)
.withClosedLoopController(50, 0, 0, DegreesPerSecond.of(90), DegreesPerSecondPerSecond.of(45))
.withSimClosedLoopController(50, 0, 0, DegreesPerSecond.of(90), DegreesPerSecondPerSecond.of(45))
// Feedforward Constants
.withFeedforward(new ArmFeedforward(0, 0, 0))
.withSimFeedforward(new ArmFeedforward(0, 0, 0))
// Telemetry name and verbosity level
.withTelemetry("ArmMotor", TelemetryVerbosity.HIGH)
// Gearing from the motor rotor to final shaft.
// In this example gearbox(3,4) is the same as gearbox("3:1","4:1") which corresponds to the gearbox attached to your motor.
.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 ArmConfig armCfg = new ArmConfig(sparkSmartMotorController)
// Soft limit is applied to the SmartMotorControllers PID
.withSoftLimits(Degrees.of(-20), Degrees.of(10))
// Hard limit is applied to the simulation.
.withHardLimit(Degrees.of(-30), Degrees.of(40))
// Starting position is where your arm starts
.withStartingPosition(Degrees.of(-5))
// Length and mass of your arm for sim.
.withLength(Feet.of(3))
.withMass(Pounds.of(1))
// Telemetry name and verbosity for the arm.
.withTelemetry("Arm", TelemetryVerbosity.HIGH);
// Arm Mechanism
private Arm arm = new Arm(armCfg);
/**
* Move the arm up and down.
* @param dutycycle [-1, 1] speed to set the arm too.
*/
public Command set(double dutycycle) { return arm.set(dutycycle);}
/**
* Run sysId on the {@link Arm}
*/
public Command sysId() {
// Our Static test will run the arm up and down with 7v.
// Our Dynamic test will run the arm up and down going from 0v to 7v inreasing at 2v per second.
// The test will last 4 seconds at most.
return arm.sysId(Volts.of(7), Volts.of(2).per(Second), Seconds.of(4));
}
/** Creates a new ExampleSubsystem. */
public ExampleSubsystem() {}
@Override
public void periodic() {
// This method will be called once per scheduler run
arm.updateTelemetry();
}
@Override
public void simulationPeriodic() {
// This method will be called once per scheduler run during simulation
arm.simIterate();
}
}
RobotContainer.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;
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.Degrees;
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 arm to release.
m_exampleSubsystem.setDefaultCommand(m_exampleSubsystem.set(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 `sysId` while the Xbox controller's A button is pressed,
// cancelling on release.
m_driverController.a().whileTrue(m_exampleSubsystem.sysId());
m_driverController.b().whileTrue(m_exampleSubsystem.set(0));
// 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);
}
}