2026-01-27 18:16:23 -08:00
|
|
|
package frc4388.robot.subsystems.intake;
|
|
|
|
|
|
2026-02-27 20:19:01 -08:00
|
|
|
import static edu.wpi.first.units.Units.Rotations;
|
2026-02-16 15:57:24 -07:00
|
|
|
|
|
|
|
|
import com.ctre.phoenix6.controls.DutyCycleOut;
|
2026-01-27 18:16:23 -08:00
|
|
|
import com.ctre.phoenix6.controls.PositionDutyCycle;
|
2026-02-27 20:19:01 -08:00
|
|
|
import com.ctre.phoenix6.controls.PositionVoltage;
|
2026-01-27 18:16:23 -08:00
|
|
|
import com.ctre.phoenix6.hardware.TalonFX;
|
|
|
|
|
|
2026-02-27 20:19:01 -08:00
|
|
|
import edu.wpi.first.math.trajectory.TrapezoidProfile;
|
|
|
|
|
import edu.wpi.first.math.util.Units;
|
|
|
|
|
import edu.wpi.first.units.measure.Acceleration;
|
|
|
|
|
import edu.wpi.first.units.measure.Angle;
|
|
|
|
|
import edu.wpi.first.units.measure.Velocity;
|
2026-02-14 15:57:33 -07:00
|
|
|
import edu.wpi.first.wpilibj.DigitalInput;
|
2026-01-27 18:16:23 -08:00
|
|
|
|
|
|
|
|
public class IntakeReal implements IntakeIO {
|
|
|
|
|
|
|
|
|
|
TalonFX m_armMotor;
|
|
|
|
|
TalonFX m_rollerMotor;
|
2026-02-14 15:57:33 -07:00
|
|
|
DigitalInput m_armLimitSwitch;
|
2026-01-27 18:16:23 -08:00
|
|
|
|
2026-02-09 16:03:48 -08:00
|
|
|
PositionDutyCycle armPosition = new PositionDutyCycle(0);
|
2026-02-22 14:02:31 -07:00
|
|
|
DutyCycleOut armPercentOutput = new DutyCycleOut(0);
|
2026-02-09 16:03:48 -08:00
|
|
|
|
2026-01-27 18:16:23 -08:00
|
|
|
public IntakeReal(
|
2026-02-14 15:57:33 -07:00
|
|
|
DigitalInput armLimitSwitch,
|
2026-01-27 18:16:23 -08:00
|
|
|
TalonFX armMotor,
|
|
|
|
|
TalonFX rollerMotor
|
|
|
|
|
) {
|
|
|
|
|
// m_angleMotor = angleMotor;
|
|
|
|
|
// m_pitchMotor = pitchMotor;
|
|
|
|
|
m_armMotor = armMotor;
|
|
|
|
|
m_rollerMotor = rollerMotor;
|
2026-02-14 15:57:33 -07:00
|
|
|
m_armLimitSwitch = armLimitSwitch;
|
2026-01-27 18:16:23 -08:00
|
|
|
|
|
|
|
|
// Apply the configs
|
|
|
|
|
m_armMotor.getConfigurator().apply(IntakeConstants.ARM_PID);
|
|
|
|
|
m_armMotor.getConfigurator().apply(IntakeConstants.ARM_MOTOR_CONFIG);
|
|
|
|
|
m_rollerMotor.getConfigurator().apply(IntakeConstants.ROLLER_MOTOR_CONFIG);
|
2026-02-09 16:03:48 -08:00
|
|
|
|
|
|
|
|
armPosition.Slot = 0;
|
2026-02-17 18:53:26 -08:00
|
|
|
// rollerVelocity.Slot = 0;
|
2026-01-27 18:16:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Angle clampAng(Angle x, Angle min, Angle max){
|
|
|
|
|
if(x.gt(max)) {
|
|
|
|
|
return max;
|
|
|
|
|
}else if(x.lt(min)) {
|
|
|
|
|
return min;
|
|
|
|
|
}else{
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
2026-02-17 18:53:26 -08:00
|
|
|
public void setRollerOutput(IntakeState state, double rollerOutput) {
|
|
|
|
|
state.rollerTargetOutput = rollerOutput;
|
2026-02-27 20:19:01 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
if(rollerOutput == 0) {
|
|
|
|
|
m_rollerMotor.set(0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-02-17 18:53:26 -08:00
|
|
|
m_rollerMotor.set(rollerOutput);
|
2026-01-27 18:16:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setArmAngle(IntakeState state, Angle angle) {
|
2026-02-16 15:57:24 -07:00
|
|
|
|
2026-01-27 18:16:23 -08:00
|
|
|
state.armTargetAngle = angle;
|
|
|
|
|
// Assume that the angle is always accurate, because I think we will use a shaft encoder
|
|
|
|
|
// Assume that 0 degrees = forwards. Might need an offset here
|
2026-02-09 16:03:48 -08:00
|
|
|
|
2026-02-10 18:42:47 -08:00
|
|
|
// angle = clampAng(angle, IntakeConstants.ARM_LIMIT_RETRACTED, IntakeConstants.ARM_LIMIT_EXTENDED);
|
2026-02-09 16:03:48 -08:00
|
|
|
|
2026-01-27 18:16:23 -08:00
|
|
|
// (REAL_ROT) * (MOTOR_ROT / REAL_ROT) = MOTOR_ROT
|
2026-02-10 17:33:39 -08:00
|
|
|
Angle motorAngle = angle.times(IntakeConstants.ARM_MOTOR_GEAR_RATIO);
|
2026-02-09 16:03:48 -08:00
|
|
|
|
|
|
|
|
// PositionDutyCycle posRequest = new PositionDutyCycle(motorTargetAngle);
|
2026-02-16 15:57:24 -07:00
|
|
|
m_armMotor.setControl(
|
|
|
|
|
armPosition
|
|
|
|
|
.withPosition(motorAngle)
|
|
|
|
|
.withLimitReverseMotion(!m_armLimitSwitch.get())
|
|
|
|
|
);
|
2026-02-21 12:54:16 -08:00
|
|
|
|
2026-01-27 18:16:23 -08:00
|
|
|
}
|
2026-02-16 15:57:24 -07:00
|
|
|
|
2026-02-27 20:19:01 -08:00
|
|
|
@Override
|
|
|
|
|
public void testSetArmAgle(IntakeState state, Angle angle){
|
|
|
|
|
state.armTargetAngle = angle;
|
|
|
|
|
Angle motorAngle = angle.times(IntakeConstants.ARM_MOTOR_GEAR_RATIO);
|
|
|
|
|
|
|
|
|
|
final TrapezoidProfile m_profile = new TrapezoidProfile(
|
|
|
|
|
new TrapezoidProfile.Constraints(80, 160)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Final target of motorAngle rot, 0 rps
|
|
|
|
|
// Convert the Angle to a numeric degree value before creating the profile state
|
|
|
|
|
TrapezoidProfile.State m_goal = new TrapezoidProfile.State(motorAngle.in(Rotations), 0);
|
|
|
|
|
TrapezoidProfile.State m_setpoint = new TrapezoidProfile.State();
|
|
|
|
|
|
|
|
|
|
// create a position closed-loop request, voltage output, slot 0 configs
|
|
|
|
|
final PositionVoltage m_request = new PositionVoltage(0).withSlot(0);
|
|
|
|
|
|
|
|
|
|
// calculate the next profile setpoint
|
|
|
|
|
m_setpoint = m_profile.calculate(0.020, m_setpoint, m_goal);
|
|
|
|
|
|
|
|
|
|
// send the request to the device
|
|
|
|
|
m_request.Position = m_setpoint.position;
|
|
|
|
|
m_request.Velocity = m_setpoint.velocity;
|
|
|
|
|
m_armMotor.setControl(m_request);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-14 10:55:51 -08:00
|
|
|
@Override
|
|
|
|
|
public void stopArm(){
|
|
|
|
|
m_armMotor.set(0);
|
2026-02-18 16:36:02 -08:00
|
|
|
// m_rollerMotor.set(0);
|
2026-02-14 10:55:51 -08:00
|
|
|
}
|
2026-02-16 16:19:51 -07:00
|
|
|
|
2026-02-14 15:00:40 -07:00
|
|
|
@Override
|
2026-02-16 15:57:24 -07:00
|
|
|
public void armOutput(double percentOutput){
|
|
|
|
|
m_armMotor.setControl(
|
2026-02-22 14:02:31 -07:00
|
|
|
armPercentOutput.withOutput(percentOutput)
|
2026-02-16 15:57:24 -07:00
|
|
|
.withLimitReverseMotion(!m_armLimitSwitch.get())
|
|
|
|
|
);
|
2026-02-14 15:00:40 -07:00
|
|
|
}
|
2026-01-27 18:16:23 -08:00
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void updateInputs(IntakeState state) {
|
2026-02-10 17:33:39 -08:00
|
|
|
state.armAngle = m_armMotor.getPosition().getValue().div(IntakeConstants.ARM_MOTOR_GEAR_RATIO);
|
|
|
|
|
state.armMotorCurrent = m_armMotor.getStatorCurrent().getValue();
|
2026-02-17 18:53:26 -08:00
|
|
|
state.rollerOutput = m_rollerMotor.get();
|
2026-01-27 18:16:23 -08:00
|
|
|
state.rollerMotorCurrent = m_rollerMotor.getStatorCurrent().getValue();
|
2026-02-17 18:53:26 -08:00
|
|
|
state.retractedLimit = !m_armLimitSwitch.get();
|
2026-02-27 20:19:01 -08:00
|
|
|
|
2026-02-27 20:38:24 -08:00
|
|
|
state.armMotorVelocity = m_armMotor.getVelocity().getValue();
|
|
|
|
|
state.armMotorAcceleration = m_armMotor.getAcceleration().getValue();
|
2026-02-17 18:53:26 -08:00
|
|
|
|
|
|
|
|
if(state.retractedLimit) {
|
|
|
|
|
// Set the arm motor to be zero if the limit switch is pressed
|
|
|
|
|
m_armMotor.setPosition(0., 0);
|
|
|
|
|
}
|
2026-02-09 17:18:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void updateGains() {
|
2026-02-09 16:03:48 -08:00
|
|
|
|
2026-02-09 18:38:55 -08:00
|
|
|
IntakeConstants.ARM_PID.kP = IntakeConstants.arm_kP.get();
|
|
|
|
|
IntakeConstants.ARM_PID.kI = IntakeConstants.arm_kI.get();
|
|
|
|
|
IntakeConstants.ARM_PID.kD = IntakeConstants.arm_kD.get();
|
2026-02-10 17:33:39 -08:00
|
|
|
m_armMotor.getConfigurator().apply(IntakeConstants.ARM_PID);
|
2026-02-09 16:03:48 -08:00
|
|
|
|
2026-01-27 18:16:23 -08:00
|
|
|
}
|
2026-01-27 16:46:12 -07:00
|
|
|
}
|