This is the quick and dirty guide on how to write IOTalon files which are files that will communicate directly with your motor and relay the things the motor tells you to your IO file for logging and later use in your logic files.
So the first thing you'll need to do is create the object that will go in this file note that this is an object and not a class. You'll write something to this effect
object SubsystemIOTalon: SubsystemIO {}
Now within this the first thing you'll need to do is create a code representation of your motors and sensors. This guide will only cover doing a motor but you can be on the look out for an extension on how to implement sensors later on. Please ensure that you have one motor object for each motor on your subsystem. Follow the API below to help you construct and use your motor object.
https://api.ctr-electronics.com/phoenix6/release/java/com/ctre/phoenix6/hardware/TalonFX.html
This other API will tell you how to implement other devices like CANRanges etc.
com.ctre.phoenix6.hardware (CTRE Phoenix 6 Java 25.4.0)
So following that you'll need to write something like this to implement your motor
private val subsystemTalon: TalonFX = TalonFX(Constants.Subsystem.MOTOR_ID) //Create Motor
private val motionMagicControl: MotionMagicVoltage = MotionMagicVoltage(-1337.degrees.inDegrees)
private val configs: TalonFXConfiguration = TalonFXConfiguration()
private val subsystemSensor = ctreAngularMechanismSensor(
subsystemTalon, SubsystemConstants.GEAR_RATIO, SubsystemConstants.VOLTAGE_COMPENSATION
)
The first line is constructing the motor object to represent the motor object in code. The next line creates a Motion Magic voltage control request that tells the motor to move to –1337 degrees this is just a temporary request value and will be replaced the second the logic kicks in. The final line creates an empty TalonFX configuration object that you will fill with motor settings before applying them to the motor. The final line is creating a sensor, this helps your code track the actual position of the subsystem by taking into account the gear ratios. You'll need to reference this sensor for position and velocity later. Choose carefully between ctreLinearMechanismSensor and ctreAngularMechanismSensor depending on your use case.
Next you'll need to declare a bunch of status signals these are the raw signals outputted by your motor to declare its current position voltages etc. Below is an example of declaring status signals using the WPILib generic typings. If you'd like to know more about generics in Kotlin refer to this video. I highly recommend you watch this if you haven't seen generics before
https://www.youtube.com/watch?v=tddbTT_v1BE
var statorCurrentSignal: StatusSignal<WPICurrent>
var supplyCurrentSignal: StatusSignal<WPICurrent
var tempSignal: StatusSignal<WPITemp>
var dutyCycleSignal: StatusSignal<Double>
var motorTorqueSignal: StatusSignal<WPICurrent>
var motorVoltageSignal: StatusSignal<Voltage>
var motorAccelSignal: StatusSignal<AngularAcceleration>
var rotorPositionSignal: StatusSignal<WPIAngle>
var rotorVelocitySignal: StatusSignal<AngularVelocity>
//Dont worry if your IDE screams at you about not initializing variables we will do this later
The init function is a function that runs immediately after constructing an object in Kotlin for more info on that refer to these docs init block in Kotlin. In your init you'll need to initialize all of your status signals and set your configs. Below is an example of doing this
init {
subsystemTalon.clearStickyFaults()
//setup these constants for every subsystem (see below for more info)
configs.CurrentLimits.SupplyCurrentLimit = 40.0
configs.CurrentLimits.StatorCurrentLimit = 40.0
configs.CurrentLimits.SupplyCurrentLimitEnable = true
configs.CurrentLimits.StatorCurrentLimitEnable = true
configs.MotorOutput.NeutralMode = NeutralModeValue.Brake //What your motor will do when
//nothing is requested of it coast will do nothing, brake will apply resistive force
configs.MotionMagic.MotionMagicCruiseVelocity = subsystemConstants.MAX_VELOCITY
configs.MotionMagic.MotionMagicAcceleration = subsystemConstants.MAX_ACCELERATION
subsystemTalon.configurator.apply(configs) //very important dont forget to apply your configs
//initalize status signals by getting inputs directly from the talon
rotorPositionSignal = subsystemTalon.position
rotorVelocitySignal = subsystemTalon.velocity
statorCurrentSignal = subsystemTalon.statorCurrent
supplyCurrentSignal = subsystemTalon.supplyCurrent
tempSignal = subsystemTalon.deviceTemp
dutyCycleSignal = subsystemTalon.dutyCycle
motorTorqueSignal = subsystemTalon.torqueCurrent
motorVoltageSignal = subsystemTalon.motorVoltage
motorAccelSignal = subsystemTalon.acceleration
zeroEncoder() // Dont worry if you haven't written this yet but still include it here
}