Supported Devices

Currently, the following devices are supported in simulation:

  • Talon SRX

  • Talon FX

  • Victor SPX

  • CANCoder

  • Pigeon IMU

  • Pigeon 2.0


Multiple CAN buses using the CANivore API is not supported at this time. All CAN devices will appear on the same CAN bus. If you wish to run your robot code in simulation, ensure devices have unique IDs across CAN buses.

Simulation API

Each supported device has a SimCollection object to manage I/O with the simulation model. The object can be retrieved by calling getSimCollection() on an instance of a device.

TalonFX fx = new TalonFX(0);
TalonFXSimCollection fx_sim = fx.getSimCollection();


For example usage of the SimCollection API, check out our examples that support simulation, such as our differential drive simulation example.


Simulating non-FRC applications (not using WPI_* classes) will require calling Unmanaged.feedEnable(100); to enable simulated actuators.


To view simulated devices in the WPILib simulation GUI, use the WPI_* class extensions.

Simulating Sensors

CTRE device simulation reflects what the physical device would see in normal hardware operation. This does not always reflect the behavior of our regular device APIs.

As an example, when setInverted(true) is called on a motor controller, the following values are all inverted in the regular device API:

  • input to set()

  • output of getMotorOutputPercent()

  • output of getMotorOutputVoltage()

  • input to setSelectedSensorPosition()

  • output of getSelectedSensor*()

However, the SimCollection I/O represents what the physical motor controller sees. For example, getMotorOutputLeadVoltage() returns the voltage you would read across the motor output leads with a voltmeter. If the motor is inverted, the voltage measured will be inverted from what is seen in the regular device API.

Therefore, in the SimCollection API, none of the following values will be inverted:

  • output of SimCollection.getMotorOutputLeadVoltage()

  • input to SimCollection.set*Position()

  • input to SimCollection.add(Quadrature/IntegratedSensor)Position()

  • input to SimCollection.set*Velocity()

It is important to take this into account to avoid unexpected behavior. For example, using the output of getMotorOutputVoltage() to determine the input of SimCollection.set*Velocity() will result in the sensor values being inverted in the API. However, using the output of SimCollection.getMotorOutputLeadVoltage() will result in the expected behavior.

“Raw” Quadrature/Integrated Sensor Position

The quadrature sensor on the Talon SRX and the integrated sensor on the Talon FX have a unique problem. Users can set the position of the sensor through the regular device API using setSelectedSensorPosition() and SensorCollection.set(Quadrature/IntegratedSensor)Position(). However, the user simulation model does not know about these calls. Our solution is to separate the encoder values seen in the regular device API from the simulated encoder values. We call this separate simulated encoder position the “raw” position.

When the raw position of the quadrature or integrated sensor is set in the SimCollection API, the simulated device takes the difference between the new raw position and the previous raw position. It then adds that difference to the actual sensor position reported to the user. As a result, the user simulation model does not have to worry about user calls to setSelectedSensorPosition().