2024 Migration

Sorry if it’s been asked before but I can’t find any useful info of this issue. We are preparing for the season by updating all software to 2024. We first updated WPILib to 2024 beta to find that we need to update Gradle. After upgrading Gradle, it won’t build complaining all Vendor Libraries must be 2024. Doing lots of web searches hunting down 2024 versions of Vendor Libraries fixed almost all problems with a few exceptions: 1) Laser Shark has no 2024 library. We don’t really use it, so we drop the support from our library; 2) CTRE wants us to migrate to Phoenix 6 because all our Phoenix 5 API calls are marked deprecated and resulted in tons of compiler warning. I know we can live with deprecated APIs for one more year, but I would like to fix them now. Reading through CTRE migration guides, it’s not clear to me how to fix some of the warnings. For example, TalonFX is marked deprecated, but nowhere can I find what I need to replace it with? The header comment in TalonFX just said this is deprecated and point us to the Migration guide which I can’t find any mention of what I should use instead of TalonFX. This is only my first question on CTRE migration, but I need to get past this one first. I’d appreciate any pointer on this one. Thanks.

2 Likes

The first thing you’ll want to do is ensure your imports are all in the phoenix6 package/namespace.

com.ctre.phoenix6....

From there, you can follow the migration guide for any corresponding functionality. Whether it’s signals like

getVelocity()

or control requests like

m_motor.setControl(m_dutyCycleRequest.withOutput(...));

I have installed the Phoenix 6 vendor library, so I should have visibility of all Phoenix 6 APIs. Still, I can figure out what I need to replace TalonFX with? TalonFX is fundamental. It’s the Falcon motor. If it’s deprecated, it got to be replaced by something. But what is it?

This one? TalonFX (CTRE Phoenix 6 Java 24.0.0-beta-7)

Thanks. I got it. The fact that my import to Phoenix 5 obscure my visibility of Phoenix 6 APIs. Once I deleted Phoenix 5 imports, I can see the new APIs.

My next question is: It used to be that both TalonFX and TalonSRX extend BaseTalon. TalonSRX still extends BaseTalon but TalonFX no longer does that. We have an upper layer that works with all Talon motor controllers and assumes we can work with BaseTalon as a common interface, but this layer no longer works because TalonFX is not a BaseTalon. Any comments on this?

This is intentional. v6 is a complete API and firmware rewrite that adds many new features and fixes common complaints of v5.

v6 has no support for TalonSRX (but you can use v5 just fine with it). Unfortunately, this means your wrapper will be broken.

Note that you can NOT mix and match v5 and v6 APIs for a given device. If a device is on v6 firmware, you MUST use the v6 APIs to interact with it.

1 Like

So, we cannot use new Phoenix 6 features on SRX then? Thanks. I guess time to unwrap this layer.

If our robot uses both Falcons and TalonSRXs, does it mean we have to keep both imports to Phoenix 5 and Phoenix 6 vendor lib? The migration guide said something about if using Phoenix 5, it must have special firmware version. I guess if we use Phoenix 5 only on TalonSRXs, they shouldn’t have Phoenix 6 firmware anyway, correct?

that’s right, you import both v5 and v6, exactly as you describe, so you can use v6 for the falcons and v5 for the talon srx’s.

But isn’t Phoenix 5 going away eventually? If so, how would SRXs work? Unless, Phoenix 5 will stay just for SRXs.

Phoenix 5 will stick around and be maintained for devices that aren’t supported in v6, such as TalonSRX, CANdle, VictorSPX, etc.

Only v6 eligible devices; CANcoder, TalonFX, Pigeon 2.0 are deprecated for removal in 2025.

2 Likes

While porting our code to use Phoenix 6 APIs, I can’t seem to find the equivalent of configFactoryDefaults. How do you get the motor controller to init to a “known state” without going through init’ing every configs?

So, I still have to create default “configs” for every group and do an apply for each group instead of just one single configFactoryDefaults call?

What do you mean by group?

There are many config groups that you need to reset back to default. For example, HardwareLimitSwitchConfigs, MotorOutputConfigs, CurrentLimitsConfigs, … etc. In order to do an equivalent of configFactoryDefaults, I basically have to instantiate every config group and do an “apply” to it. Something like this:

/**
 * This method resets the motor controller configurations to factory default so that everything is at known state.
 */
@Override
public void resetFactoryDefault()
{
    TalonFXConfigurator configurator = motor.getConfigurator();

    talonFxConfigs = new TalonFXConfiguration();
    recordResponseCode("resetTalonFxConfigs", configurator.apply(talonFxConfigs));

    motorOutputConfigs = new MotorOutputConfigs();
    recordResponseCode("resetMotorOutputConfigs", configurator.apply(motorOutputConfigs));

    currentLimitsConfigs = new CurrentLimitsConfigs();
    recordResponseCode("resetCurrentLimitConfigs", configurator.apply(currentLimitsConfigs));

    voltageConfigs = new VoltageConfigs();
    recordResponseCode("resetVoltageConfigs", configurator.apply(voltageConfigs));

    torqueCurrentConfigs = new TorqueCurrentConfigs();
    recordResponseCode("resetTorqueCurrentConfigs", configurator.apply(torqueCurrentConfigs));

    feedbackConfigs = new FeedbackConfigs();
    recordResponseCode("resetFeedbackConfigs", configurator.apply(feedbackConfigs));

    differentialSensorsConfigs = new DifferentialSensorsConfigs();
    recordResponseCode("resetdifferentialSensorsConfigs", configurator.apply(differentialSensorsConfigs));

    differentialConstantsConfigs = new DifferentialConstantsConfigs();
    recordResponseCode("resetdifferentialConstantsConfigs", configurator.apply(differentialConstantsConfigs));

    openLoopRampsConfigs = new OpenLoopRampsConfigs();
    recordResponseCode("resetOpenLoopRampsConfigs", configurator.apply(openLoopRampsConfigs));

    closedLoopRampsConfigs = new ClosedLoopRampsConfigs();
    recordResponseCode("resetClosedLoopRampsConfigs", configurator.apply(closedLoopRampsConfigs));

    hardwareLimitSwitchConfigs = new HardwareLimitSwitchConfigs();
    recordResponseCode("resetHardwareLimitSwitchConfigs", configurator.apply(hardwareLimitSwitchConfigs));
    fwdLimitSwitchInverted = hardwareLimitSwitchConfigs.ForwardLimitType == ForwardLimitTypeValue.NormallyClosed;
    revLimitSwitchInverted = hardwareLimitSwitchConfigs.ReverseLimitType == ReverseLimitTypeValue.NormallyClosed;

    audioConfigs = new AudioConfigs();
    recordResponseCode("resetAudioConfigs", configurator.apply(audioConfigs));

    softwareLimitSwitchConfigs = new SoftwareLimitSwitchConfigs();
    recordResponseCode("resetSoftwareLimitSwitchConfigs", configurator.apply(softwareLimitSwitchConfigs));

    motionMagicConfigs = new MotionMagicConfigs();
    recordResponseCode("resetMotionMagicConfigs", configurator.apply(motionMagicConfigs));

    customParamsConfigs = new CustomParamsConfigs();
    recordResponseCode("resetCustomParamsConfigs", configurator.apply(customParamsConfigs));

    closedLoopGeneralConfigs = new ClosedLoopGeneralConfigs();
    recordResponseCode("resetClosedLoopGeneralConfigs", configurator.apply(closedLoopGeneralConfigs));

    slot0Configs = new Slot0Configs();
    recordResponseCode("resetSlot0Configs", configurator.apply(slot0Configs));

    slot1Configs = new Slot1Configs();
    recordResponseCode("resetSlot1Configs", configurator.apply(slot1Configs));

    slot2Configs = new Slot2Configs();
    recordResponseCode("resetSlot2Configs", configurator.apply(slot2Configs));

    slotConfigs = new SlotConfigs();
    recordResponseCode("resetSlotConfigs", configurator.apply(slotConfigs));
}   //resetFactoryDefault

TalonFXConfiguration contains all other config groups, so passing an empty insurance of this class should be sufficient.

Ah, I missed that. That’s a lot better. So, I can just deal with one big group. Thanks for the pointer.

1 Like

After a couple days of work, I have figured out most of the mappings between Phoenix5 and Phoenix6. I would like somebody to verify if the mappings are correct. Also, there are about 6 APIs that I can’t find the equivalents in Phoenix6. Would somebody comment on them?

configSelectedFeedbackSensor(devType); => Feedback.FeedbackSensorSource = …; getConfigurator().apply(Feedback);
configFactoryDefault(); => getConfiguration().apply(new TalonFXConfiguration());
getBusVoltage(); => getSupplyVoltage().getValueAsDouble();
configSupplyCurrentLimit(…); => CurrentLimits… = …; getConfigurator().apply(CurrentLimits);
configClosedloopRamp(…); => ClosedLoopRamps = …; getConfigurator().apply(ClosedLoopRamps);
configOpenloopRamp(…); => OpenLoopRamps = …; getConfigurator().apply(OpenLoopRams);
setNeutralMode(…); => MotorOutput.NeutralMode = …; getConfigurator().apply(MotorOutput);
configReverseLimitSwitchSource(…); => HardwareLimitSwitch.ReverseLimitType = …; getConfigurator().apply(HardwareLimitSwitch);
configForwardLimitSwitchSource(…); => HardwareLimitSwitch.ForwardLimitType = …; getConfigurator().apply(HardwareLimitSwitch);
configGetParameter(eLimitSwitchNormClosedAndDis); => getConfigurator().refresh(HardwareLimitSwitch);
configReverseLimitSwitchSource(…); => HardwareLimitSwitch.ReverseLimitType = …; getConfigurator().apply(HardwareLimitSwitch);
configForwardLimitSwitchSource(…); => HardwareLimitSwitch.ForwardLimitType = …; getConfigurator().apply(HardwareLimitSwitch);
configReverseSoftLimitThreshold(…); => SoftwareLimitSwitch.ReverseSoftLimit = …; getConfigurator().apply(SoftwareLimitSwitch);
configForwardSoftLimitThreshold(…); => SoftwareLimitSwitch.ForwardSoftLimit = …; getConfigurator().apply(SoftwareLimitSwitch);
setSensorPhase(…); => ???
configGetParameter(eSensorDirection); => ???
setSelectedSensorPosition(…); => getConfigurator().setPosition(…);
setInverted(…); => MotorOutput.Inverted = …; getConfiguration().apply(MotorOutput);
getInverted(…); => getConfigurator().refresh(MotorOutput);
set(ControlMode.PercentOutput, …); => setControl(DutyCycleOut);
getMotorOutputPercent(); => getDutyCycle().getValueAsDouble();
set(ControlMode.Velocity, …); => setControl(VelocityVoltage);
getSelectedSenosrVelocity(); => getVelocity().getValueAsDouble();
configClosedLoopPeakOutput(…); => MotorOutput.PeakForwardDutyCycle = …; MotorOutput.PeakReverseDutyCycle = …; getConfigurator().apply(MotorOutput);
set(ControlMode.Position, …); => setControl(PositionVoltage);
getSelectedSensorPosition(); => getPosition().getValueAsDouble();
set(ControlMode.Current, …); => setControl(TorqueCurrentFOC);
getStatorCurrent(); => getTorqueCurrent().getValueAsDouble();
config_KP(), config_KI(), … => Slotx.kP = …; Slotx.Ki = …; getConfigurator().apply(Slotx);
configGetParameter(eProfileParamsSlot_P) … => getConfigurator().refresh(Slotx);
configAllowableClosedloopError(…); => ???
getClosedLoopError(); => getClosedLoopError().getValueAsDouble(); //??? for the selected PID slot???
configVoltageCompSaturation(…); => ???
isVoltageCompensationEnabled(); => ???
follow(…); => ???