Encoder with Multiple Index Pulses

I’m working on modifying the ODrive firmware to work with a custom optical encoder I have. The disk has 16 index pulses with a unique number of counts between them. This makes it work like pseudo-absolute encoder where the exact position can be determined by rotating past 2 index channels and comparing the counts between against a lookup table. There are 5056 CPR on the disk and it is being read by an AEDR-8500.

My plan is to integrate this into the ODrive AXIS_STATE_ENCODER_INDEX_SEARCH process. It would also work with AXIS_STATE_ENCODER_OFFSET_CALIBRATION

This way on startup it can accomplish offset alignment with only a slight rotation of the motor. The motor is attached to a gearbox and is generally under load when starting up. I initially tried using the encoder without the index but found encoder offset calibration doesn’t like running under load.

I’ve been working to modify the enc_index_cb function to store the position of a first and second index pulse so I can take the difference and know abs pos/offset later.

The problem I’ve been having is that it seems to detect an index pulse initially (likely where it left off) but I don’t see it on my attached oscilloscope (set to trigger on the index line).

The ODrive often misses multiple of the next pulses (but I can see them on the scope). I can’t get 2 consecutive index pulses to trigger (roughly 400 counts between them).

In my limited knowledge I think it has something to do with the disabling of the interrupt after the trigger. They are not being re-enabled in run_lockin_spin()

I’ve spent a few hours in VSCode and the debugger trying various combinations of the code below but just keep going in circles.

Any help you can provide in how to accomplish the overall project (including a better approach) are greatly appreciated!

Thanks in advance,

Here is the modified code:

void Encoder::enc_index_cb() {
    if (config_.use_index) {
          set_circular_count(0, false);
        if (config_.zero_count_on_find_idx)
            set_linear_count(0); // Avoid position control transient after search
        if (config_.pre_calibrated) {
            is_ready_ = true;
        } else {
            // We can't use the update_offset facility in set_circular_count because
            // we also set the linear count before there is a chance to update. Therefore:
            // Invalidate offset calibration that may have happened before idx search
            is_ready_ = false;
        if(abs(abs(shadow_count_) - abs(config_.lastInterrupt)) > 40){
            config_.lastInterrupt = shadow_count_;
            config_.countIndex1_ = shadow_count_;
            config_.firstIndex_ = false;
            index_found_ = true;
        else if(config_.firstIndex_ == false && (abs(abs(config_.countIndex1_) - abs(shadow_count_)) > 20)){
            config_.countIndex2_ = shadow_count_;
        config_.firstIndex_ = true;
         index_found_ = true;
         //GPIO_unsubscribe(hw_config_.index_port, hw_config_.index_pin);
        //index_found_ = true; //try 1 location
    // Disable interrupt
    GPIO_unsubscribe(hw_config_.index_port, hw_config_.index_pin); //original location

  //  set_idx_subscribe(!index_found_);


As a sanity check, it might be worth commenting out everything and have your callback toggle a GPIO to see if it’s your code that’s taking too long to execute or whether there’s something wrong with the callback dispatcher. That way you can also check the latency of the encoder pulse to the execution of your callback.

I can’t remember where the interrupt flag is cleared but it almost sounds like the flag isn’t being cleared before the next pulse is detected.


Thanks, Simon!

I am working with my STM programmer to try and implement this test but he’s not an ODrive expert.

I’d be willing to pay you or someone else to help develop this (we can share the code still online).

Please let me know if this is something you (or anyone else) is interested in.


Add a 22nF cap to the index line, this is a known issue. Also, I’m not sure if that callback is even attached if use_index is false? So make sure that’s set to true. And indeed you don’t want to unsubscribe from the index callback function if you’re actually using it :slight_smile:

Thanks! I believe I may have cracked the coding problem. Working on testing it now and then will report back soon…