001/* 002 * Copyright (C) Cross The Road Electronics. All rights reserved. 003 * License information can be found in CTRE_LICENSE.txt 004 * For support and suggestions contact support@ctr-electronics.com or file 005 * an issue tracker at https://github.com/CrossTheRoadElec/Phoenix-Releases 006 */ 007package com.ctre.phoenix6.sim; 008 009import static edu.wpi.first.units.Units.*; 010 011import com.ctre.phoenix6.StatusCode; 012import com.ctre.phoenix6.hardware.core.CoreTalonFX; 013import com.ctre.phoenix6.hardware.TalonFX; 014import com.ctre.phoenix6.jni.PlatformJNI; 015 016import edu.wpi.first.units.measure.*; 017 018/** 019 * Class to control the state of a simulated {@link TalonFX}. 020 */ 021public class TalonFXSimState { 022 private static final DeviceType kDevType = DeviceType.P6_TalonFXType; 023 024 private final int _id; 025 026 /** 027 * The orientation of the TalonFX relative to the robot chassis. 028 * <p> 029 * This value should not be changed based on the TalonFX invert. 030 * Rather, this value should be changed when the mechanical linkage 031 * between the TalonFX and the robot changes. 032 */ 033 public ChassisReference Orientation; 034 035 /** 036 * Creates an object to control the state of the given {@link TalonFX}. 037 * <p> 038 * This constructor defaults to a counter-clockwise positive orientation 039 * relative to the robot chassis. 040 * <p> 041 * Note the recommended method of accessing simulation features is to use 042 * {@link TalonFX#getSimState} 043 * 044 * @param device Device to which this simulation state is attached 045 */ 046 public TalonFXSimState(CoreTalonFX device) { 047 this(device, ChassisReference.CounterClockwise_Positive); 048 } 049 /** 050 * Creates an object to control the state of the given {@link TalonFX}. 051 * <p> 052 * Note the recommended method of accessing simulation features is to use 053 * {@link TalonFX#getSimState} 054 * 055 * @param device Device to which this simulation state is attached 056 * @param orientation Orientation of the device relative to the robot chassis 057 */ 058 public TalonFXSimState(CoreTalonFX device, ChassisReference orientation) { 059 _id = device.getDeviceID(); 060 Orientation = orientation; 061 } 062 063 /** 064 * Gets the last status code generated by a simulation function. 065 * <p> 066 * Not all functions return a status code but can potentially report errors. 067 * This function can be used to retrieve those status codes. 068 * 069 * @return Last status code generated by a simulation function 070 */ 071 public StatusCode getLastStatusCode() { 072 return StatusCode.valueOf(PlatformJNI.JNI_SimGetLastError(kDevType.value, _id)); 073 } 074 075 /** 076 * Gets the simulated output voltage of the motor. 077 * 078 * @return Voltage applied to the motor in Volts 079 */ 080 public double getMotorVoltage() { 081 double value = PlatformJNI.JNI_SimGetPhysicsValue(kDevType.value, _id, "MotorVoltage"); 082 if (Orientation == ChassisReference.Clockwise_Positive) { 083 value = -value; 084 } 085 return value; 086 } 087 /** 088 * Gets the simulated output voltage of the motor as a unit type. 089 * 090 * @return Voltage applied to the motor 091 */ 092 public Voltage getMotorVoltageMeasure() { 093 return Volts.of(getMotorVoltage()); 094 } 095 096 /** 097 * Gets the simulated output torque current of the motor. 098 * <p> 099 * Phoenix 6 simulation automatically calculates current. 100 * 101 * @return Torque current applied to the motor in Amperes 102 */ 103 public double getTorqueCurrent() { 104 double value = PlatformJNI.JNI_SimGetPhysicsValue(kDevType.value, _id, "TorqueCurrent"); 105 if (Orientation == ChassisReference.Clockwise_Positive) { 106 value = -value; 107 } 108 return value; 109 } 110 /** 111 * Gets the simulated output torque current of the motor as a unit type. 112 * <p> 113 * Phoenix 6 simulation automatically calculates current. 114 * 115 * @return Torque current applied to the motor 116 */ 117 public Current getTorqueCurrentMeasure() { 118 return Amps.of(getTorqueCurrent()); 119 } 120 121 /** 122 * Gets the simulated supply current of the TalonFX. 123 * <p> 124 * Phoenix 6 simulation automatically calculates current. 125 * 126 * @return Supply current of the TalonFX in Amperes 127 */ 128 public double getSupplyCurrent() { 129 double value = PlatformJNI.JNI_SimGetPhysicsValue(kDevType.value, _id, "SupplyCurrent"); 130 return value; 131 } 132 /** 133 * Gets the simulated supply current of the TalonFX as a unit type. 134 * <p> 135 * Phoenix 6 simulation automatically calculates current. 136 * 137 * @return Supply current of the TalonFX 138 */ 139 public Current getSupplyCurrentMeasure() { 140 return Amps.of(getSupplyCurrent()); 141 } 142 143 /** 144 * Sets the simulated supply voltage of the TalonFX. 145 * <p> 146 * The minimum allowed supply voltage is 4 V - values below this 147 * will be promoted to 4 V. 148 * 149 * @param volts The supply voltage in Volts 150 * @return Status code 151 */ 152 public StatusCode setSupplyVoltage(double volts) { 153 return StatusCode.valueOf(PlatformJNI.JNI_SimSetPhysicsInput(kDevType.value, _id, "SupplyVoltage", volts)); 154 } 155 /** 156 * Sets the simulated supply voltage of the TalonFX. 157 * <p> 158 * The minimum allowed supply voltage is 4 V - values below this 159 * will be promoted to 4 V. 160 * 161 * @param voltage The supply voltage 162 * @return Status code 163 */ 164 public StatusCode setSupplyVoltage(Voltage voltage) { 165 return setSupplyVoltage(voltage.in(Volts)); 166 } 167 168 /** 169 * Sets the simulated forward limit switch of the TalonFX. 170 * 171 * @param closed Whether the limit switch is closed 172 * @return Status code 173 */ 174 public StatusCode setForwardLimit(boolean closed) { 175 return StatusCode.valueOf(PlatformJNI.JNI_SimSetPhysicsInput(kDevType.value, _id, "ForwardLimit", closed ? 1 : 0)); 176 } 177 /** 178 * Sets the simulated reverse limit switch of the TalonFX. 179 * 180 * @param closed Whether the limit switch is closed 181 * @return Status code 182 */ 183 public StatusCode setReverseLimit(boolean closed) { 184 return StatusCode.valueOf(PlatformJNI.JNI_SimSetPhysicsInput(kDevType.value, _id, "ReverseLimit", closed ? 1 : 0)); 185 } 186 187 /** 188 * Sets the simulated raw rotor position of the TalonFX. This is the position 189 * of the rotor (before gear ratio) used for the RotorSensor feedback source. 190 * <p> 191 * Inputs to this function over time should be continuous, as user calls of {@link TalonFX#setPosition} will be accounted for in the callee. 192 * <p> 193 * The TalonFX integrates this to calculate the true reported rotor position. 194 * <p> 195 * When using the WPI Sim GUI, you will notice a readonly {@code position} and settable {@code rawPositionInput}. 196 * The readonly signal is the emulated position which will match self-test in Tuner and the hardware API. 197 * Changes to {@code rawPositionInput} will be integrated into the emulated position. 198 * This way a simulator can modify the position without overriding hardware API calls for home-ing the sensor. 199 * 200 * @param rotations The raw position in rotations 201 * @return Status code 202 */ 203 public StatusCode setRawRotorPosition(double rotations) { 204 if (Orientation == ChassisReference.Clockwise_Positive) { 205 rotations = -rotations; 206 } 207 return StatusCode.valueOf(PlatformJNI.JNI_SimSetPhysicsInput(kDevType.value, _id, "RawRotorPosition", rotations)); 208 } 209 /** 210 * Sets the simulated raw rotor position of the TalonFX. This is the position 211 * of the rotor (before gear ratio) used for the RotorSensor feedback source. 212 * <p> 213 * Inputs to this function over time should be continuous, as user calls of {@link TalonFX#setPosition} will be accounted for in the callee. 214 * <p> 215 * The TalonFX integrates this to calculate the true reported rotor position. 216 * <p> 217 * When using the WPI Sim GUI, you will notice a readonly {@code position} and settable {@code rawPositionInput}. 218 * The readonly signal is the emulated position which will match self-test in Tuner and the hardware API. 219 * Changes to {@code rawPositionInput} will be integrated into the emulated position. 220 * This way a simulator can modify the position without overriding hardware API calls for home-ing the sensor. 221 * 222 * @param position The raw position 223 * @return Status code 224 */ 225 public StatusCode setRawRotorPosition(Angle position) { 226 return setRawRotorPosition(position.in(Rotations)); 227 } 228 229 /** 230 * Adds to the simulated rotor position of the TalonFX. This adds to the position 231 * of the rotor (before gear ratio) used for the RotorSensor feedback source. 232 * 233 * @param dRotations The change in position in rotations 234 * @return Status code 235 */ 236 public StatusCode addRotorPosition(double dRotations) { 237 if (Orientation == ChassisReference.Clockwise_Positive) { 238 dRotations = -dRotations; 239 } 240 return StatusCode.valueOf(PlatformJNI.JNI_SimSetPhysicsInput(kDevType.value, _id, "AddRotorPosition", dRotations)); 241 } 242 /** 243 * Adds to the simulated rotor position of the TalonFX. This adds to the position 244 * of the rotor (before gear ratio) used for the RotorSensor feedback source. 245 * 246 * @param dPosition The change in position 247 * @return Status code 248 */ 249 public StatusCode addRotorPosition(Angle dPosition) { 250 return addRotorPosition(dPosition.in(Rotations)); 251 } 252 253 /** 254 * Sets the simulated rotor velocity of the TalonFX. This is the velocity 255 * of the rotor (before gear ratio) used for the RotorSensor feedback source. 256 * 257 * @param rps The new velocity in rotations per second 258 * @return Status code 259 */ 260 public StatusCode setRotorVelocity(double rps) { 261 if (Orientation == ChassisReference.Clockwise_Positive) { 262 rps = -rps; 263 } 264 return StatusCode.valueOf(PlatformJNI.JNI_SimSetPhysicsInput(kDevType.value, _id, "RotorVelocity", rps)); 265 } 266 /** 267 * Sets the simulated rotor velocity of the TalonFX. This is the velocity 268 * of the rotor (before gear ratio) used for the RotorSensor feedback source. 269 * 270 * @param velocity The new velocity 271 * @return Status code 272 */ 273 public StatusCode setRotorVelocity(AngularVelocity velocity) { 274 return setRotorVelocity(velocity.in(RotationsPerSecond)); 275 } 276 277 /** 278 * Sets the simulated rotor acceleration of the TalonFX. This is the acceleration 279 * of the rotor (before gear ratio) used for the RotorSensor feedback source. 280 * 281 * @param rpss The new acceleration in rotations per second² 282 * @return Status code 283 */ 284 public StatusCode setRotorAcceleration(double rpss) { 285 if (Orientation == ChassisReference.Clockwise_Positive) { 286 rpss = -rpss; 287 } 288 return StatusCode.valueOf(PlatformJNI.JNI_SimSetPhysicsInput(kDevType.value, _id, "RotorAcceleration", rpss)); 289 } 290 /** 291 * Sets the simulated rotor acceleration of the TalonFX. This is the acceleration 292 * of the rotor (before gear ratio) used for the RotorSensor feedback source. 293 * 294 * @param acceleration The new acceleration 295 * @return Status code 296 */ 297 public StatusCode setRotorAcceleration(AngularAcceleration acceleration) { 298 return setRotorAcceleration(acceleration.in(RotationsPerSecondPerSecond)); 299 } 300}