Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/arm 2024 #7

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open

Feature/arm 2024 #7

wants to merge 22 commits into from

Conversation

GaiaZano05
Copy link
Contributor

Changing the arm subsystem to work with phoenix 6.

@katzuv
Copy link
Member

katzuv commented Dec 8, 2023

The ArmIO is missing.

@katzuv katzuv self-requested a review December 11, 2023 00:14
Copy link
Member

@katzuv katzuv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure to add all files and use Phoenix 6 API only.

src/main/java/frc/robot/subsystems/arm/Arm.java Outdated Show resolved Hide resolved
src/main/java/frc/robot/subsystems/arm/ArmConstants.java Outdated Show resolved Hide resolved
import org.littletonrobotics.junction.LogTable;
import org.littletonrobotics.junction.inputs.LoggableInputs;

public class ArmInputsLogged implements LoggableInputs {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use @Autolog?

src/main/java/frc/robot/subsystems/arm/ArmIOReal.java Outdated Show resolved Hide resolved
src/main/java/frc/robot/subsystems/arm/ArmIOReal.java Outdated Show resolved Hide resolved

public boolean armIsOutOfFrame () {
Translation2d elbowJoint = getElbowJointPosition(), endPosition = getEndPosition();
return !(elbowJoint.getX() < 0) || !(endPosition.getX() < 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return !(elbowJoint.getX() < 0) || !(endPosition.getX() < 0);
return elbowJoint.getX() >= 0 || endPosition.getX() >= 0;

But is that true, though? Shouldn't positive values indicate "in frame"?

}

public boolean armIsOutOfFrame () {
Translation2d elbowJoint = getElbowJointPosition(), endPosition = getEndPosition();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What benefit does creating these variables have?

Comment on lines 315 to 318
@Override
public String getSubsystemName () {
return "Arm";
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is that needed?

src/main/java/frc/robot/subsystems/arm/ArmIOReal.java Outdated Show resolved Hide resolved
Copy link
Collaborator

@vichik123 vichik123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job!

Comment on lines +35 to -48

private Arm() {
if (Robot.isReal()) {
io = new ArmIOReal();
} else {
io = new ArmIOReal();
}
}

public static Arm getINSTANCE() {
if (INSTANCE == null) {
if (Robot.isReal()) {
INSTANCE = new Arm(new ArmIOSim(inputs));

} else {
INSTANCE = new Arm(new ArmIOSim(inputs));
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The arm object doesn't need to know whether or not it's real. In the future (already exists in the robot template), there is going to be a static initializing function for each subsystem, to which the robot mode will be passed. So for now, the creation of the io should be done in the getInstance function.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if there are more than 2 implementations? For example, Falcon 500 and NEO swerve implementations (Robotinyo? 👀).

io = new ArmIOReal();
} else {
io = new ArmIOReal();
}
}

public static Arm getINSTANCE() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public static Arm getINSTANCE() {
public static Arm getInstance() {




ArmIOReal() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ArmIOReal() {
public ArmIOReal() {

Comment on lines +72 to +73
elbowMainMotorConfig.CurrentLimits.SupplyCurrentLimit = ArmConstants.CURRENT_LIMIT;
elbowMainMotorConfig.CurrentLimits.StatorCurrentLimit = ArmConstants.CURRENT_LIMIT;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this constant 10 ampere?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we do that during the season?

.withKI(ArmConstants.elbowI)
.withKD(ArmConstants.elbowD);

public static final double SENSOR_TO_MECHANISM_RATIO= 1;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used to calculate gear ratio in the motor. When using the getPosition() function it's necessary, because it returns a position times the gear ratio. However, I believe that the parallel function used in the phoenix 5 version was getRotorPosition(), with the gear ratio taken into account later. Here https://pro.docs.ctr-electronics.com/en/latest/docs/migration/migration-guide/status-signals-guide.html#using-status-signals.

angle = AngleUtil.normalize(angle);
Rotation2d error = new Rotation2d(angle).minus(new Rotation2d(currentShoulderAngle));
if (elbowEncoder.isConnected()) {
motorControlRequest = new PositionVoltage(angle);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are both the shoulder and the elbow updating the same member?

Comment on lines +186 to +188
elbowMainMotor.setControl(new PositionDutyCycle(angle, velocity, true,
elbowFeedforward * ffMultiplier, 1, true)
.withEnableFOC(true));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here as before.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the appeal of the SingleJointedArmSim class. However, I recommend using the TalonFXSim class, because the "api" is the same as the TalonFX class, allowing us to find bugs in the real usage of the api before the robot comes.

Comment on lines -62 to +67
public void updateInputs() {
public void updateInputs(ArmInputs inputs) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't actually necessary. You could pass the inputs through the io constructor and have it as a member in the io class (both real and sim).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say to put this class in the io interface, but this is enormous, so I get it.

}


private void setShoulderJointAngle(double angle, double ffMultiplier, int velocity) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything in your code (including IO implementations, subsystem code, arm constants, etc) should work with Rotation2d objects. That way you won't need to cast back and forth everywhere.

Comment on lines +53 to +56
public static final Slot0Configs SHOULDER_PID= new Slot0Configs()
.withKP(ArmConstants.shoulderP)
.withKI(ArmConstants.shoulderI)
.withKD(ArmConstants.shoulderD);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to create the gains as separate gains. Just write them directly here.

@@ -29,27 +30,12 @@ default void setElbowP(double kP) {
default void updateInputs() {
}

String getSubsystemName();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary?

Comment on lines 52 to 68
this.shoulderEncoder = new DutyCycleEncoder(Ports.ArmPorts.SHOULDER_ENCODER);
this.elbowEncoder = new DutyCycleEncoder(Ports.ArmPorts.ELBOW_ENCODER);

this.shoulderMainMotor = new TalonFX(Ports.ArmPorts.SHOULDER_MAIN_MOTOR);

this.shoulderAuxMotor = new TalonFX(Ports.ArmPorts.SHOULDER_AUX_MOTOR);

this.elbowMainMotor = new TalonFX(Ports.ArmPorts.ELBOW_MAIN_MOTOR);

this.elbowAuxMotor = new TalonFX(Ports.ArmPorts.ELBOW_AUX_MOTOR);



shoulderAuxMotor.setControl(new StrictFollower(shoulderMainMotor.getDeviceID()));
elbowAuxMotor.setControl(new StrictFollower(elbowMainMotor.getDeviceID()));


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too much whitespace leads to tedious scrolling.

Comment on lines +69 to +87
shoulderMainMotorConfig.Voltage.PeakForwardVoltage = ArmConstants.VOLT_COMP_SATURATION;
shoulderMainMotorConfig.Voltage.PeakReverseVoltage = -ArmConstants.VOLT_COMP_SATURATION;
shoulderMainMotorConfig.Slot0 = SHOULDER_PID;
elbowMainMotorConfig.CurrentLimits.SupplyCurrentLimit = ArmConstants.CURRENT_LIMIT;
elbowMainMotorConfig.CurrentLimits.StatorCurrentLimit = ArmConstants.CURRENT_LIMIT;
shoulderMainMotorConfig.Feedback.SensorToMechanismRatio = SENSOR_TO_MECHANISM_RATIO;
shoulderMainMotorConfig.Feedback.RotorToSensorRatio = ROTOR_TO_SENSOR_RATIO;
shoulderMainMotor.getConfigurator().apply(shoulderMainMotorConfig);

shoulderMainMotor.setNeutralMode(NeutralModeValue.Brake);
shoulderMainMotor.setInverted(MAIN_CLOCKWISE);

elbowMainMotorConfig.Voltage.PeakForwardVoltage = ArmConstants.VOLT_COMP_SATURATION;
elbowMainMotorConfig.Voltage.PeakReverseVoltage = -ArmConstants.VOLT_COMP_SATURATION;
elbowMainMotorConfig.Slot1 = ELBOW_PID;
elbowMainMotorConfig.CurrentLimits.SupplyCurrentLimit = ArmConstants.CURRENT_LIMIT;
elbowMainMotorConfig.CurrentLimits.StatorCurrentLimit = ArmConstants.CURRENT_LIMIT;
elbowMainMotorConfig.Feedback.SensorToMechanismRatio = SENSOR_TO_MECHANISM_RATIO;
elbowMainMotorConfig.Feedback.RotorToSensorRatio = ROTOR_TO_SENSOR_RATIO;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of that should be in the constants file. Use the with* methods and remove the constants, this will be cleaner and shorter -- you won't need one line to define the constant and another to use it, you'll just have one line total.

angle = AngleUtil.normalize(angle);
Rotation2d error = new Rotation2d(angle).minus(new Rotation2d(currentShoulderAngle));
if (shoulderEncoder.isConnected()) {
motorControlRequest = new PositionVoltage(angle);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't instantiate a new object every time, create it only once and change it using withPosition().

Comment on lines +160 to +164
return Rotation2d.fromRotations(shoulderEncoder.getAbsolutePosition() - shoulderOffset);
}

public Rotation2d getElbowJointAngle() {
return Rotation2d.fromRotations(elbowEncoder.getAbsolutePosition() - elbowOffset);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to set the offset and ration once instead of calculating it yourself. You can find the relevant methods here.

Comment on lines +172 to +181
public void setElbowJointAngle(Rotation2d angle) {
setElbowJointAngle(angle.getRadians(), ELBOW_FEED_FORWARD, ELBOW_VELOCITY);
}

/**
* Sets the angle of the elbow joint.
*
* @param angle desired angle. [degrees]
*/
private void setElbowJointAngle(double angle, double ffMultiplier, int velocity) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two should accept the same types, hence the private method should also receive a Rotation2d.



@Override
public void toLog(LogTable table) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In your case you can remove toLog and fromLog and just use @AutoLog.

@@ -199,7 +193,7 @@ private void setElbowJointAngle(double angle, double ffMultiplier, int velocity)
public Translation2d getEndPosition() {
Rotation2d shoulderAngle = getShoulderJointAngle();
Rotation2d elbowAngle = getElbowJointAngle();
return kinematics.forwardKinematics(shoulderAngle.getRadians(),shoulderAngle.getRadians() + elbowAngle.getRadians() - Math.PI);
return kinematics.forwardKinematics(shoulderAngle.getRadians(), shoulderAngle.getRadians() + elbowAngle.getRadians() - Math.PI);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kinematics should work with Rotation2d too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants