BiSS-C encoder support
I’d like to announce more encoder support in moteus, this time for BiSS-C encoders in unidirectional mode. BiSS-C is a protocol often used in higher end industrial encoders that uses a RS-422 wire level signaling scheme. This support works out of the box for moteus-n1 and moteus-x1 which have a RS-422 connector already included. All you need is to have firmware 2026-01-21 or newer installed and to follow the documentation for upgrading.
If you want to see a specific configuration example, or read about how the feature was implemented, read on!
Sample AksIM-2 configuration
To use, first follow the documentation to ensure you have firmware version at least 2026-01-21. You may need to upgrade your moteus_tool before you can flash the newer firmware:
python -m pip install --upgrade moteus
Then configure the necessary pins:
aux1.pins.3.mode 18 # bissc
aux1.pins.4.mode 18 # bissc
aux1.bissc.enabled 1
aux1.rs422 1
With the moteus implementation of BiSS-C, you need to manually specify the number of data bits that the device will report. You can get this from its datasheet or model number. For a 17-bit AksIM-2, you would do:
aux1.bissc.data_bits 17
After that, you Then you can enable this as the primary encoder in motor_position with the following configuration:
motor_position.sources.0.type 9 # bissc
motor_position.sources.0.cpr 131072 # 1 << 17
After which you can calibrate and use the controller as normal.
Implementation
BiSS-C is a protocol that is actually somewhat challenging to implement on general purpose microcontrollers in a completely generic way, as peripherals are rarely capable of doing it out of the box. The closest peripheral in most cases is a SPI controller, with the clock output being the transmit and the CIPO (MISO) pin being the receive. When the current moteus aux2 pinout design was constructed, I knew this, and made a valiant attempt to get both a UART TX pin attached to the RS422 TX pin as well as a SPI clock but was unable to, settling for just the UART TX pin and a timer capable pin. That thus hints at the implementation strategy, which I’ll describe in a bit more detail here.
The premise is to configure the timer pin as a PWM output and have it emit the BiSS-C master signal. This PWM output then triggers a DMA transaction on each rising edge which captures the appropriate byte from the GPIO register that contains the receive pin. Once the requisite number of clocks have been emitted and bytes received, the microcontroller can then extract the necessary bits out of the DMA buffer and parse the BiSS-C response frame.
This means the entire transmission process is handled by hardware, although the decoding is more involved. The decoder starts with an array in memory consisting of bytes, where the received bit is at the same position in every byte. The way this works in principle is that each bit is extracted, the start bit is identified, the data and status bits are extracted, then the CRC is extracted and checked. In practice, this process needs to happen in the primary ISR, so the number of available cycles is very limited. A number of “tricks” are used to decrease the cycle count. For instance, multiplying a 32 bit number by 0x08040201 will move the first bit of every byte into consecutive positions in the highest byte. This drastically reduces the number of instructions needed to extract bits. Similarly, the CTZ builtin intrinsic (count leading zeros), can be used to help efficiently locate the start bit.
Encoder support
It was hard to find external testers for this feature in the mjbots community so the initial validation is less than typical. To date, it has only been experimentally validated on a 17 bit AksIM-2 encoder. The implementation itself should support many encoders that use a 6 bit CRC and a range of data widths.
Feedback
If you have success (or challenges) using this, join the mjbots Discord and report your experience!