A local team is using SPARK MAX/NEO with SRX MAG Encoder (aka CTRE Magnetic Encoder). This is with SDS MK3 Swerve Modules. Initially, the encoder was hooked up to the roboRIO as an incremental encoder, using two PWM-style cables to bring “A” and “B” out from the encoder and also to connect +5V and GND between the encoder and the roboRIO. This works, but does not provide an absolute position, which is useful in this context.
A better option is to use the PWM output, connecting this to a digital input on the roboRIO (and also connecting +5V and GND). This can be done with a single PWM cable, and a careful splice onto the end of the 10-conductor ribbon cable (the end with no connector on it, opposite the 10-pin connector plugged into the encoder). It is possible to do this and also connect the A/B inputs to the roboRIO, but there’s not much point in having A/B connected in this scenario. The DutyCycleEncoder class provides the means of reading the PWM absolute position when this is wired into the roboRIO in this way.
However, this means the feedback into the motor controller is a bit sub-optimal – this is probably fine; I suspect quite a few teams run this way. The feedback for the motor controller in this scenario is going through the roboRIO, and/or is using the commutation (A/B/C) encoder built-into the NEO. The built-in encoder is separated from the wheel rotation by gearing and a belt, and has fewer counts per rotation. Going through the roboRIO introduces (a little) extra delay.
So, are there any other options here? I looked, and it isn’t clear to me that the SPARK MAX can decode the PWM absolute position coming from the encoder (it looks like at least not yet, based on the state of the REV tracking bug that has been mentioned in other threads). So, what exactly is available from this encoder?
First, the encoder needs +5V (pin 2) and GND (pin 10); this power would be supplied by either the roborRIO or the SPARK MAX. The +3.3V pin (pin 1) is not used (no connect). Pins 3 and 6 are also no connect. Pins 4 and 8 are not used either, they are simply brought out via solder pads on the encoder board. This just leaves pins 5 (B), 7 (A) , and 9 (PWM OUT). So, there are three digital outputs available with this encoder. These could be used with digital inputs on the roboRIO, as discussed previously.
What about the SPARK MAX?
We have +5V (pin 2), GND (pin 10), and +3.3V (pin 1). We also have analog input (pin 3). There is no use for either +3.3V or analog input with the encoder being used here. Further, pins 5, 7, and 9 are not available. This is because they are internally connected to the A/B/C commutation encoder inputs coming from the NEO (through the encoder port located near the three motor driver wires). This only leaves pins 4, 6, and 8, all digital inputs. It is the role of these inputs that changes in “alternate encoder mode”.
So, three digital outputs from the encoder, and three digital inputs to the SPARK MAX. Two of these (“A” and “B”) directly correspond. The third is PWM absolute position from the encoder and “I” into the SPARK MAX. However, looking at the REV alternate encoder adapter, it is clear that the PWM input is planned for pin 4 (the “I” pin mentioned above). Note that there it is not possible to use a limit switch in alternate encoder mode, as these three pins are normally used for the two limit switch inputs and a “multi-function” input. There is no need for limit switches with this swerve module, so that’s fine.
In view of all of this, it would be nice to have “A”, “B”, and “PWM” connected between the encoder and the SPARK MAX, as well as +5V and GND. At the same time, it would be very good to also have “PWM” available at the roborRIO. This requires isolation, most likely an optoisolator. It’s also important to look at the ratings and specifications for things like current, voltage, and timing, in order to ensure everything is compatible. To make a slightly long story a bit shorter, here’s a schematic that provides this connectivity:
Here’s a small PCB for this circuit:
And, here’s a 3D CAD view of a populated board: