Skip to content

Commit

Permalink
Update Cheese Stick to use servo and have simulation support.
Browse files Browse the repository at this point in the history
  • Loading branch information
JonahEMorgan committed Feb 8, 2025
1 parent bedeb8a commit f27d4c3
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 131 deletions.
115 changes: 115 additions & 0 deletions simgui-ds.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
{
"Keyboard 1 Settings": {
"window": {
"visible": true
}
},
"keyboardJoysticks": [
{
"axisConfig": [
{
"decKey": 65,
"incKey": 68
},
{
"decKey": 87,
"incKey": 83
},
{
"decKey": 69,
"decayRate": 0.0,
"incKey": 82,
"keyRate": 0.009999999776482582
}
],
"axisCount": 3,
"buttonCount": 4,
"buttonKeys": [
90,
88,
67,
86,
-1,
-1,
-1,
-1
],
"povConfig": [
{
"key0": 328,
"key135": 323,
"key180": 322,
"key225": 321,
"key270": 324,
"key315": 327,
"key45": 329,
"key90": 326
}
],
"povCount": 1
},
{
"axisConfig": [
{
"decKey": 74,
"incKey": 76
},
{
"decKey": 73,
"incKey": 75
}
],
"axisCount": 2,
"buttonCount": 8,
"buttonKeys": [
77,
44,
46,
47,
-1,
-1,
-1,
80,
-1,
-1
],
"povCount": 0
},
{
"axisConfig": [
{
"decKey": 263,
"incKey": 262
},
{
"decKey": 265,
"incKey": 264
}
],
"axisCount": 2,
"buttonCount": 6,
"buttonKeys": [
260,
268,
266,
261,
269,
267
],
"povCount": 0
},
{
"axisCount": 0,
"buttonCount": 0,
"povCount": 0
}
],
"robotJoysticks": [
{
"guid": "Keyboard0"
},
{
"guid": "Keyboard1"
}
]
}
22 changes: 9 additions & 13 deletions src/main/java/frc/robot/Constants.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package frc.robot;

import static edu.wpi.first.math.util.Units.*;
import static edu.wpi.first.units.Units.*;

import com.ctre.phoenix6.configs.TalonFXConfiguration;
import com.ctre.phoenix6.signals.NeutralModeValue;
import com.revrobotics.spark.config.SparkBaseConfig;
import com.revrobotics.spark.config.SparkMaxConfig;

import edu.wpi.first.math.geometry.Translation2d;
import edu.wpi.first.math.util.Units;
import edu.wpi.first.units.measure.Time;
import edu.wpi.first.units.measure.Distance;

public class Constants {
public static final class ControllerConstants {
Expand All @@ -20,14 +18,12 @@ public static final class ControllerConstants {
}

public static final class CheeseStickConstants {
public static final int kMotorPort = 0; // TODO: Figure out what motor port is needed
public static final SparkBaseConfig kMotorConfig = new SparkMaxConfig().inverted(false);
public static final Time kResetLength = Second.of(0); // TODO: Figure out how long it takes for the springs to
// reset
public static final double kOpenDistance = .25;
public static final double kP = 0; // TODO: Figure out what grip speed is needed
public static final double kTolerance = 0; // TODO: Figure out what grip tolerance is needed
public static final Time kGripTimeout = Second.of(0); // TODO: Figure out what grip timeout is needed
public static final int kServoPort = 0;
public static final int kMaxRotation = 270;
/**
* Set this value to how far the cheese stick wheels extend beyond the lexan.
*/
public static final Distance kExtensionLength = Inch.of(.5);
}

public static final class DriveConstants {
Expand Down Expand Up @@ -57,7 +53,7 @@ public static final class DriveConstants {
public static final double kTeleopMaxTurnVoltage = 7.2;
public static final double kDriveGearRatio = 6.12;
public static final double kSteerGearRatio = 150.0 / 7;
public static final double kWheelDiameter = Units.inchesToMeters(4);
public static final double kWheelDiameter = inchesToMeters(4);
public static final double kWheelCircumference = Math.PI * kWheelDiameter;

public static final double kMetersPerMotorRotation = kWheelCircumference / kDriveGearRatio;
Expand Down
25 changes: 21 additions & 4 deletions src/main/java/frc/robot/Robot.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

package frc.robot;

import static edu.wpi.first.math.util.Units.*;
import static edu.wpi.first.wpilibj2.command.Commands.*;
import static frc.robot.Constants.ControllerConstants.*;

import java.util.Map;

import org.littletonrobotics.urcl.URCL;
Expand All @@ -12,28 +16,34 @@
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.PowerDistribution;
import edu.wpi.first.wpilibj.TimedRobot;
import edu.wpi.first.wpilibj.smartdashboard.Mechanism2d;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.CommandScheduler;
import edu.wpi.first.wpilibj2.command.button.CommandPS4Controller;
import frc.robot.Constants.ControllerConstants;
import edu.wpi.first.wpilibj2.command.button.CommandPS5Controller;
import frc.robot.subsystems.CheeseStickSubsystem;
import frc.robot.subsystems.DriveSubsystem;

public class Robot extends TimedRobot {
private Command m_autonomousCommand;
private final Mechanism2d m_mechanism = new Mechanism2d(inchesToMeters(35), inchesToMeters(100));
private final DriveSubsystem m_driveSubsystem = new DriveSubsystem();
private final CommandPS4Controller m_driverController = new CommandPS4Controller(
ControllerConstants.kDriverControllerPort);
private final CheeseStickSubsystem m_cheeseStickSubsystem = new CheeseStickSubsystem(
m_mechanism.getRoot("anchor", inchesToMeters(20), inchesToMeters(50)));
private final CommandPS5Controller m_driverController = new CommandPS5Controller(kDriverControllerPort);
private final CommandPS5Controller m_operatorController = new CommandPS5Controller(kOperatorControllerPort);
private final PowerDistribution m_pdh = new PowerDistribution();

public Robot() {
SmartDashboard.putData("Superstructure", m_mechanism);
SmartDashboard.putData(m_pdh);
SmartDashboard.putData(CommandScheduler.getInstance());
DataLogManager.start();
DataLogManager.logNetworkTables(true);
URCL.start(Map.of(11, "FR Turn", 21, "BR Turn", 31, "BL Turn", 41, "FL Turn"));
DriverStation.startDataLog(DataLogManager.getLog());
bindDriveControls();
bindCheeseStickControls();
}

public void bindDriveControls() {
Expand All @@ -45,6 +55,13 @@ public void bindDriveControls() {
m_driverController.getHID()::getSquareButton));
}

public void bindCheeseStickControls() {
// Need to figure out what left and right actually mean
m_operatorController.R2().whileFalse(m_cheeseStickSubsystem.extend());
m_operatorController.R2().whileTrue(m_cheeseStickSubsystem.retract());
m_operatorController.R2().whileTrue(print("hi"));
}

@Override
public void robotPeriodic() {
CommandScheduler.getInstance().run();
Expand Down
145 changes: 31 additions & 114 deletions src/main/java/frc/robot/subsystems/CheeseStickSubsystem.java
Original file line number Diff line number Diff line change
@@ -1,139 +1,56 @@
package frc.robot.subsystems;

import static com.revrobotics.spark.SparkBase.PersistMode.*;
import static com.revrobotics.spark.SparkBase.ResetMode.*;
import static com.revrobotics.spark.SparkLowLevel.MotorType.*;
import static com.revrobotics.spark.config.SparkBaseConfig.IdleMode.*;
import static edu.wpi.first.wpilibj2.command.Commands.*;
import static edu.wpi.first.units.Units.*;
import static frc.robot.Constants.CheeseStickConstants.*;

import java.util.function.BooleanSupplier;
import java.util.function.DoubleSupplier;

import com.revrobotics.RelativeEncoder;
import com.revrobotics.spark.SparkMax;

import edu.wpi.first.math.controller.PIDController;
import edu.wpi.first.wpilibj.Servo;
import edu.wpi.first.wpilibj.simulation.PWMSim;
import edu.wpi.first.wpilibj.smartdashboard.MechanismLigament2d;
import edu.wpi.first.wpilibj.smartdashboard.MechanismObject2d;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.SubsystemBase;

/**
* This subsystem is for the cheese stick gripper.
*/
public class CheeseStickSubsystem extends SubsystemBase {
private SparkMax m_motor;
private RelativeEncoder m_encoder;
private DoubleSupplier m_position;

public CheeseStickSubsystem() {
m_motor = new SparkMax(kMotorPort, kBrushless);
m_motor.configure(kMotorConfig, kResetSafeParameters, kNoPersistParameters);
m_encoder = m_motor.getEncoder();
m_position = () -> m_encoder.getPosition();
}

/**
* Resets the subsystem to the default state based on the springs.
*
* @return The command.
*/
public Command resetPositionCommand() {
return runOnce(
() -> m_motor.configure(kMotorConfig.idleMode(kCoast), kResetSafeParameters, kNoPersistParameters))
.andThen(waitTime(kResetLength)).andThen(() -> {
m_motor.configure(
kMotorConfig.idleMode(kBrake), kResetSafeParameters, kNoPersistParameters);
m_encoder.setPosition(0);
});
}

/**
* Resturns a supplier for the cheese stick position. This might be useful in
* the future.
*
* @return The supplier.
*/
public DoubleSupplier getPosition() {
return m_position;
}

/**
* Creates a command which opens the cheese stick in order to insert into the
* coral.
*
* @return The command.
*/
public Command createOpenCommand() {
return createMoveCommand(kOpenDistance);
private final Servo m_servo = new Servo(kServoPort);
private final PWMSim m_sim = new PWMSim(m_servo);
private final MechanismLigament2d m_ligament = new MechanismLigament2d("Cheeese Stick", 0, 90);

public CheeseStickSubsystem(MechanismObject2d attachment) {
// https://docs.revrobotics.com/rev-crossover-products/servo/srs#electrical-specifications
m_servo.setBoundsMicroseconds(2500, 0, 0, 0, 500);
m_servo.setZeroLatch();
attachment.append(m_ligament);
}

/**
* Creates a command which grips the coral.
*
* @return The command.
* Logs data to the smart dashboard. Displays the simulated mechanism.
*/
public Command createGripCommand() {
return createMoveCommand(0);
public void periodic() {
double position = m_sim.getPosition();
SmartDashboard.putNumber("Cheese Stick Position", position);
m_ligament.setLength(kExtensionLength.in(Meters) * position);
}

/**
* Creates a command which moves the cheese stick to the specified position.
* Returns a command to command the servo to rotate anti-clockwise. This pulls
* against springs and retracts the cheese stick. Does not wait
* for it to finish.
*
* @param distance The position to go to.
* @return The command.
*/
private Command createMoveCommand(double distance) {
PIDController PID = new PIDController(kP, 0, 0);
PID.setTolerance(kTolerance);
return new Command() {
/**
* Evaluate the PID controller.
*/
public void execute() {
m_motor.set(PID.calculate(m_position.getAsDouble()));
}

/**
* Checks if the position is within tolerance or if the timeout has ocurred.
*/
public boolean isFinished() {
return PID.atSetpoint();
}

/**
* Stops the motor from moving.
*/
public void end(boolean interrupted) {
m_motor.set(0);
PID.close();
}
}.withTimeout(kGripTimeout);
public Command retract() {
return runOnce(() -> m_servo.set(0)).withName("Servo Retract");
}

/**
* Creates a command which controls the cheese stick based on an activator
* (likely a button)
* Returns a command to command the servo to rotate clockwise. This is pushed by
* springs and extends the cheese stock. Does not wait
* for it to finish.
*
* @param activator The supplier which defines when the cheese stick is open.
* @return The command.
*/
public Command createManualCommand(BooleanSupplier activator) {
Command open = createOpenCommand();
Command grip = createGripCommand();
return new Command() {
public void execute() {
if (activator.getAsBoolean()) {
if (!open.isScheduled())
open.schedule();
if (grip.isScheduled())
grip.cancel();
} else {
if (open.isScheduled())
open.cancel();
if (!grip.isScheduled())
grip.schedule();
}
}
};
public Command extend() {
return runOnce(() -> m_servo.set(1)).withName("Servo Extend");
}
}
}

0 comments on commit f27d4c3

Please sign in to comment.