If you've looked at our robot, you might have noticed the yellow and green wires going around, connecting the motors and sensors. These are CAN bus wires, which is the de facto communication protocol/system in FRC.
The Electrical Side
The CAN bus, like other wired communication types, is a protocol meant to communicate bits between nodes. This is done by having a differential voltage on the two wires. In an idle, or "recessive" state (corresponds to the bit 1), the two wires are at 2.5V. In a "dominant" state, the CAN high is 3.5V and the CAN low is 1.5V (corresponds to the bit 0). This seemingly confusing scheme is important for two main reasons: by having two wires, EMI is mostly eliminated as the interference will be applied to both wires, which results in the differential voltage being the same. This is also the reason that the CAN wires are twisted most of the time. In a robot with a lot of electronics, EMI can be a big issue. Additionally, one of the main problems with this decentralized "highway" is that the nodes cannot send information at the same time. By having a "recessive" and a "dominant" state, a node applying the "dominant" state will override another node applying the "recessive" state. When nodes are sending data, they check that the state they set was actually applied, and if two nodes are sending data at the exact same time, the node that overrides the other node's "recessive" state essentially "wins" the arbitration and gets to send the rest of their message. The CAN bus protocol starts off with transmitting the ID, so lower IDs get a higher priority as their bits have more "dominant" states.
CAN Bus Utilization
As you can think of the CAN bus as a highway of information, you can divide a period of time (called a timeslice) into the time that information was being transmitted and the time that the highway was empty. When the highway is empty most of the time, nodes that want to send information can do so without any problems, but if the highway is full all the time, nodes will not be able to send data when they want to and may result in stale data or frames not being transmitted at all. In practice, a CAN bus utilization above 80% (80% percent of a given time period is filled with information being sent between nodes) should raise some warnings flags and solutions to fix it can be found below.
The Software Side
In practice, we should never be interacting directly with the CAN bus data, but it helps to understand what is happening under the hood. CAN frames can be split up into two types: control and status frames. Control frames are sent from the RoboRIO to devices, and usually includes data about configuration, actions, or other commands that "control" the device. Status frames are sent from devices to the RoboRIO and usually include data about the state of the motor, or the "status".
CTRE Phoenix 6
Configuration
When we initialize motors and sensors, we use a bulk configuration object (ctre::phoenix6::configs::TalonFXConfiguration
) and pass the whole thing to the device at once.
Status Frame Frequencies
The devices send status frames to the RoboRIO asynchronously - that is, on an interval. This is measured in Hertz (100Hz means the device is transmitting a certain metric 100 times a second). This frequency is a trade off between accuracy and CAN bus utilization. For example, we might want the drive motors to send their velocity and position statuses at 250Hz instead of the default frequency of 100Hz. This would result in a higher accuracy because the (math alert!) maximum latency when getting the last value on the RIO is much less than when at 100Hz (4 ms maximum latency as opposed to 10 ms).
Removing Unused Signals
By default, Phoenix 6 publishes a lot of signals with the default frequency of 100Hz. This includes important ones, such as position, velocity, and acceleration, but also relatively useless ones such as IsProLicensed, VersionBugFix, or VersionBuild. If the CAN bus utilization is under control, then great! No need to do anything. However, if you are noticing that the CAN bus utilization is high, one easy way to fix it is to use CTRE's OptimizeBusUtilizationForAll
. This will stop any signals that did not have a signal frequency manually assigned to them, but you have to be careful to set the status frequency of the signals that you do need to receive.