Skip to content

Encoders and Rotor Position

dev_joint_controller supports 2 encoder channels with the following parameters:

Encoder / Estimator sampling frequency 8kHz
Available channels 0, 1
op_state warning bit Bit 4 - Encoder warning flag

Encoder and Position Signal Path

JCS positional information is typically derived via acquiring a position from some position source, then passing this through an estimator to derive velocity and an estimated position. The position and velocity are then output as JCS signals, or depending on the application, used internally by the device system.

Encoder signal path

Encoder Common Configuration

The following parameters are common to all encoder types:

Command Type Required Description
encoder_X_type enum Required Selects the active encoder.
encoder_X_position_zero command Optional Records the current encoder position as the zero offset.
encoder_X_position_offset float32 Optional Sets or returns the rotor position offset.
encoder_X_direction boolean Required Sets the encoder direction.
encoder_X_theta_bypass boolean Optional Bypasses the encoder such that JCS input signal th_m is presented to the estimator.
encoder_X_theta_bypass_direction boolean Optional Sets the direction of the bypassed input signal.
encoder_X_linearisation_coeffs float32 array Optional An array of 64 coefficients for encoder linearisation. If any elements are non-zero, encoder linearisation is activated.

Encoder selection

Select the active encoder by writing an enum to encoder_X_type. See device specific "Supported Encoders" for available options.

Encoder position zeroing and offset

An encoder may be zeroed by either writing a zero offset or commanding the system to sample the current encoder position as the zero offset.

To store the encoder current position as the zero offset, issue JCS command encoder_X_position_zero. The encoder position will be sampled and stored in encoder_X_position_offset. The sampled zero position may be read as a float32 from encoder_X_position_offset.

To write an encoder offset, write a float32 to encoder_X_position_offset. Any existing entry will be overwritten.


Devices (such as motor controllers) may have specific encoder zeroing requirements.

Encoder commissioning

Incremental encoders always start with their position reset to zero.

When commissioning an absolute encoder, it is useful to first zero the encoder at some mechanical position that defines the start of the travel. This position may be stored in the device configuration file as a zero offset, so that the zero position can be recovered at each startup. A typical process might be:

  • Move the joint to the required mechanical zero position.
  • Issue JCS command encoder_X_position_zero.
  • Retrieve the zero position with a float32 read to encoder_X_position_offset.
  • Store this zero position offset in the device YAML config, eg:
    encoder_0_position_offset: 0.7565

Encoder direction

Set the encoder direction with a boolean write to encoder_X_direction.

Encoder theta bypass

Encoder theta bypass allow the system to take a positional input from JCS signal th_m_X rather than from an encoder. An example use of this feature is driving a motor in open loop mode while recording e.g. th_m_encoder_X for the encoder linearisation process.

Enable theta bypass with a boolean write to encoder_X_theta_bypass. The incoming direction of th_m_X may be changed with a boolean write to encoder_X_theta_bypass_direction.

Encoder theta bypass is not available on all devices.

Encoder linearisation

The encoder system supports linearisation of the encoder position by means of a lookup table for correction. The linearisation process takes the scaled encoder value and adds a small corrective bias term that is derived from the linear interpolation of the correction table.

Encoder linearisation

Encoders may be linearised by writing an array of 64 linearisation coefficients to encoder_X_linearisation_coeffs.

Encoder error handling

The encoder system is monitored for errors and registers errors as they occur. If an encoder error occurs, the previous timestep encoder value is used and the encoder manager will attempt to continue.

If a flood of errors occur such that the error rate goes above the limit set in encoder_X_error_rate_limit, then an E-stop will be generated and the system will attempt to shut down.

To tune the encoder error rate monitor, write a float32 to encoder_X_error_rate_limit:

Command Type Required Description
encoder_X_error_rate_limit float32 Optional Configures the encoder error rate limit.
Valid values between [0.0f, 1.0f]
Default: 0.05f
Set to 1.0f to disable.


  • Disabling the error rate monitor is recommended for encoder testing only.
  • If the error rate monitor is disabled encoders will still attempt to return a valid position, regardless if the data is erroneous. This may be useful for debugging
  • The encoder error rate is available as JCS signal encoder_X_error_rate even if the error rate monitor is disabled.

Supported Encoders

dev_joint_controller supports the following encoders:

Encoder type Description
jcs_as5047p JCS differential absolute encoder
spi Differential or single ended generic absolute or incremental encoder

Generic SPI Encoder Interface

JCS supports a generic SPI interface for communicating with encoders. The electrical interface supports either differential or single ended connections. See the device specific hardware documentation for connectors and pinouts.

Select the generic SPI encoder by writing enum value spi to encoder_X_type.

SPI configuration

The SPI peripheral must be configured for the appropriate encoder. Configure the device SPI peripheral with the following parameters:

Command Type Required Description
encoder_X_spi_frequency enum Required Sets the SPI peripheral frequency divisor.
encoder_X_spi_phase enum Required Sets the SPI peripheral sampling phase.
encoder_X_spi_polarity enum Required Sets the SPI peripheral sampling polarity.
encoder_X_spi_transfer_size enum Optional Defines the number of bits per transfer.
Default: 8 bits.
encoder_X_spi_using_chip_select bool Required Sets the SPI peripheral to use the chip select line.
Only effective if hardware supports it.
SPI frequency

Select the SPI frequency by dividing down fpclk and writing the value as an enum to encoder_X_spi_frequency. See device Hardware Specifications for fpclk value.

encoder_X_spi_frequency value Description
frequency_fpclk_on_2 SPI frequency is fpclk / 2
frequency_fpclk_on_4 SPI frequency is fpclk / 4
frequency_fpclk_on_8 SPI frequency is fpclk / 8
frequency_fpclk_on_16 SPI frequency is fpclk / 16
frequency_fpclk_on_32 SPI frequency is fpclk / 32
frequency_fpclk_on_64 SPI frequency is fpclk / 64
frequency_fpclk_on_128 SPI frequency is fpclk / 128
frequency_fpclk_on_256 SPI frequency is fpclk / 256
SPI phase and polarity

Configure the SPI peripheral phase by writing an enum to encoder_X_spi_phase:

encoder_X_spi_phase value Description
first_edge SPI data sampled on the first clock edge.
second_edge SPI data sampled on the second clock edge.

Configure the SPI peripheral polarity by writing an enum to encoder_X_spi_polarity:

encoder_X_spi_polarity value Description
idle_low SPI SCLK is idle low.
idle_high SPI SCLK is idle high.
SPI transfer size

Configure the SPI peripheral sample size in bits by writing an enum to encoder_X_spi_transfer_size.

encoder_X_spi_transfer_size value Description
num_bits_8 8 bits per SPI transfer.
num_bits_7 7 bits per SPI transfer.
num_bits_6 6 bits per SPI transfer.
num_bits_5 5 bits per SPI transfer.
num_bits_4 4 bits per SPI transfer.


Regardless of the number of bits sent, one byte per transfer must be allocated in the spi command and masks in the sections below.

SPI pin support

The SPI interface supports chip select, SCK and MISO.

MOSI is not supported electrically on all devices, however the software interface remains the same.

On devices where the MOSI pin is not supported, the encoder selected must support returning data with with either the encoder's MOSI pin held in a known state, or MOSI not required. Examples are:

  • AKSiM-2 which will return valid position data if it's MOSI pin is held low, equivalent to SPI command 0x00.
  • AS5047p which will return valid position data if it's MOSI pin is held high, equivalent to SPI command 0xff.

Position recovery

Position recovery is performed by masking and shifting the position bits out of a received byte array. Operation is based on SPI transfers of 4 - 8 bits per transfer using efficient DMA.

The transfers are represented by an array of bytes defined by the user in encoder_X_spi_command, with each byte containing one transfer (of 4 - 8 bits). The number of bytes defined in the array defines the number of transfers the will occur per transaction.

For example, a encoder_X_spi_transfer_size of 6 with two bytes defined in encoder_X_spi_command will result in a total of 12 bits being exchanged.

Once the data is exchanged, any positional and status information needs to be extracted and manipulated for use. The encoder system requires that the returning position information be right aligned and a maximum of 32 bits wide.

The returned combined position and status information is masked via the byte array encoder_X_spi_position_mask to separate out the position. The resulting masked position is then shifted with encoder_X_spi_position_mask (if required) to ensure it is right aligned.

Finally, the configured number of position bits encoder_X_spi_position_bits is used to scale the resulting position to the range \([0, 2\pi]\).

The following parameters are used for position recovery:

Command Type Required Description
encoder_X_spi_command uint8 array Required Defines an array of transfers to complete the SPI data exchange.
For devices that support MOSI, the command to send is defined in this array.
encoder_X_spi_position_mask uint8 array Required An array of values to mask the position bits out of the returned data.
encoder_X_spi_masked_position_shift uint8 Optional The number of bits to shift the masked position data by. The final position must be a right aligned 32 bit unsigned int.
encoder_X_spi_position_bits uint8 Required The number bits that make up the position.

Fault handling

An SPI encoder may return status information within the returned data. For example, AS5047p returns error status in bit 14.

The JCS generic SPI interface can mask out these bits of interest and generate an error if the assertion criteria is met.

The error flags are configured similarly to extracting the position information. A mask encoder_X_spi_flag_mask first masks out the bits representing errors, then a shift encoder_X_spi_flag_bits_shift can be applied to move the resultant error flags into a 32 bits wide right aligned integer.

An error condition will be raised to the encoder error monitor if any bits are set within the resulting 32 bits wide integer.


  • Defining encoder_spi_flag_mask enables error checking. If it is not defined no error checking of the encoder will occur.
  • If encoder_spi_flag_mask is not defined then encoder_spi_flag_bits_shift has no effect.

The following parameters are used for fault handling:

Command Type Required Description
encoder_X_spi_flag_mask uint8 array Optional An array of values to mask the fault bits out of the returned data.
encoder_X_masked_flag_shift uint8 Optional The number of bits to shift the masked fault bits by. The flags must fit into a 32 bit unsigned int.


AS5047p encoder has 14 bits of position and 2 status bits for a total of 16 bits. We will configure the SPI encoder for two 8 bit transfers. Our device does not support MOSI (the encoder has MOSI pin pulled high).

  # SPI encoder
  encoder_0_type: spi

  # AS5047p: 14 bits of position, 2x status bits, Total of 16 bits = 2x bytes.
  # Command frame:
  # 15:   Parity = 1
  # 14:   Read = 1
  # 13:0: Address = 0x3fff - Measured angle with dynamic angle compensation
  encoder_0_spi_position_bits:      14
  encoder_0_spi_command:            [0xff, 0xff]

  # Read data frame:
  # 15:   Parity bit
  # 14:   Frame error bit - 1 = error occurred
  # 13:0: Data - Measured angle with dynamic angle compensation
  encoder_0_spi_position_mask: [0x3f, 0xff]
  # We don't need to shift - our position is already right aligned
  encoder_0_spi_position_bits_shift: 0

  # Bit 14 of the returned data represents an error. We will watch this bit
  # and flag an error if it is set
  encoder_0_spi_flag_mask: [0x40, 0x00]
  # The resulting flag will be within a uint32, so no need to shift right

  # SPI config
  # Capture on second clock transition, falling edge
  encoder_0_spi_phase:     second_edge
  encoder_0_spi_polarity:  idle_low
  # about 3mhz
  encoder_0_spi_frequency: frequency_fpclk_on_16

Note in this example:

  • Since we are not using MOSI, the values contained in the encoder_0_spi_command have no effect. However, the spi command byte array must still be defined as this determines the number of SPI transfers that occur.
  • The values in encoder_0_spi_position_mask mask out the lower 14 bits of position information.
  • We do not need to shift the masked position - it is already right aligned.
  • We do not need to shift the masked flags - they already fall within a uint32.


JCS Generic SPI encoder interface does not currently support computing parity bits or CRC for error checking.

JCS AS5047p Encoder

Select the JCS AS5047p based encoder by writing enum value jcs_as5047p to encoder_X_type.

JCS AS5047p encoder has no specific configuration requirements.

The following debug parameters are available:

Command Type Required Description
encoder_X_as5047p_last_rx uint16 Optional Raw SPI frame returned by the AS5047p encoder. (Read only)