This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

EQEP position: self-consistent reading rollover flags and encoder counts

Other Parts Discussed in Thread: MOTORWARE

We are using the EQEP module to monitor QEP inputs to track the position of our motor. The code we're using is largely based on the motorware lab 12 a example. We're using quadrature count mode, using the A and B inputs to determine encoder count and direction, and resetting on max position. Frequently we run the encoder through thousands to hundreds of thousands of revolutions in one direction, then turn around and run it a comparable number of total revolutions in the other. We are not using the I input. We see a rare but devastating problem in calculating the total position or total encoder tick count in a particular direction, which is # of times we have rolled over the max position*#ticks in a revolution + # ticks since a rollover.

Our problem is that occasionally, near a rollover, we read the overflow/underflow flags, then read the encoder count, and calculate our total # ticks from those separate reads. The motor is still moving while we are making this calculation. Unfortunately, occasionally the encoder rolls past the rollver point between the time we read the flags and the time we read the encoder count. We then of course get a position that is off by approximately one encoder revolution.

None of this is interrupt driven. We calculate the position as needed by our system. So, some questions for the forum:

1. What is an appropriate way to perform an atomic read of both over/underflow flags and encoder count or otherwise use an appropriate latched position with flags?

2. Can you provide some guidance on the sizing constraints for QPOSCNT? Specifically, one temporary improvement I was hoping to employ for our present problem is simply to make the QPOSMAX very large, so that we actually roll over only very rarely. (Not a solution, obviously, just an improvement.)  With a 32-bit int or uint, there's plenty of room for this. But the sample code from lab 12 and our code uses the Enc_getRawEncoderCount function that casts the QPOSCNT as a 16-bit uint. I see this number is multiplied by several other 32-bit ints and ultimately saved to a 32-bit int. And from experimentation I see that I can't even use the whole range within a 16-bit uint wihtout causing errors that are presumably related to generating overly large numbers by multiplying several 16 or 32 bit numbers together and saving as a 32 bit int. Can you share your thinking about the approach presented in the sample code?

Thanks!

Regards,

Janet

  • Janet,

    I think there are a couple different ways you can address issue number 1.

    1. Implement logic after they call ENC_getRawEncoderCounts to detect that an extra rollover has happened.  This would look something like this pseudocode:
    if(rollover_counter == rollover_counter_OLD)
    {
      if(<clockwise>)
      {
        if(encoder_pos_old > encoder_pos)
        {
          rollover++;
        }
      }
      else
      {
        if(encoder_pos_old < encoder_pos)
        {
          rollover--;
        }    
      }
    }
    2. Calculate the actual motor position based on the outputs from SpinTAC Position Convert used in lab 12a.  This module outputs the current mechanical position of the system along with rollovers and is not susceptible to the issue they are seeing.  I've attached a document that explains how SpinTAC handles the position signal along with rollovers.
     
    As far as issue number 2, the example code is designed to take in a uint16 variable with the encoder counts and convert that into an IQ24 variable for motor electrical position that varies between 0 and 1.  In order to do that efficiently, there were some things in the math that were assumed when the value for mech_angle_gain is calculated.  This value does that conversion but it is not scaled to accept a value larger than the maximum position count of the encoder.  So if you were to put in larger values it would work for a while, but it would not handle larger values very well.
  • Adam,

    Thank you.

    Did you by any chance attach a different document than you meant to? Or if that was what you meant, is there some text or code to go with it?

    For issue #2: I didn't quite follow what you meant. What I was hoping to do was make QPOSMAX a very large number, something nearer 0x7fffffff than 0x0000ffff, so that rollovers would occur only at position 0 -- or even also offset the starting point to halfway between 0 and the QPOSMAX, so that practically we never need to roll over.  The QPOSCNT would never be larger than QPOSMAX. What sorts of effects on the code in enc.c and the spintac code would I have if I were to do this, so that most or all of the time the TI-generated code in those source files saw a value of QPOSCNT that was much larger than would fit into a 16 bit uint?

    Regards,

    Janet

  • Janet,

    That was the document I meant to attach.  I should have provided some additional context to go along with it.  Lab 12a uses SpinTAC Position Convert in order to convert the electrical angle from the encoder into a velocity signal used by SpinTAC  Velocity Identify.  In addition to outputting a velocity signal, SpinTAC Position Convert will also output a mechanical position to be used in position control systems.  This could be used in your application as a way of tracking the position of the motor without having to write your own encoder rollover and summing detection.

    The document I attached is an example of how mechanical position signals are handled in the SpinTAC software suite.  While the document is specifically addressing the profile generator it is also applicable to SpinTAC Position Convert.  For example, if the motor were to move 130 revolutions, the mechanical position output of SpinTAC Position Convert would look like the position signal in the plot and the rollover output of SpinTAC Position Convert would look like the position rollover count in the plot.

    The way that the encoder code is setup in the example project, QPOSCNT is only ever reset back to 0 when the value in QPOSCNT matches the value in QPOSMAX.  So if you set QPOSMAX to a very large value, than the position counter would have values larger than the maximum position count from the encoder during a single revolution.  In order to do what you suggested, you would need to modify the way in which the encoder module converts QPOSCNT into electrical angle.  The FOC and SpinTAC expect that the electrical angle from an encoder will vary between 0 and 1 in an IQ24 variable.  As long as you can get that output setup, the rest of the code will run fine.  So, the key changes will be in determining a new value for mech_angle_gain that can handle the conversion for you.

  • Thank you for the answer. More followup questions below.

     

    Can you clarify how the SpinTac Positiion Convert code avoids the problem we were asking about of inconsistent flags and counter reading due to lack of an atomic read of the flags and counter? Also, we need a total position—that is, the calculation of rollover_counts*number_of_counts_per_encoder_revolution + current_encoder_position. Can the position convert code provide that for us?

     

     

    Second,  some questions and comments on the sample code you provided. This appears to me on first reading to reduce the frequency of the position calculation errors but not to eliminate them. The second flags check handles specifically the one type of error where a single rollover occurs after the first flag read and before the second flag read.  But it doesnt handle multiple rollovers, either before or after the second flag check.

     

    For example:

     

    Let’s say our motor is in a mostly stopped state, wiggling just a tiny bit while  trying to approximately hold a position. And let’s say that position just happens to be right about the position where the encoder ticks over from MAX to 0. Let’s say further that we start the  position calculation with the encoder in the position QPOSMAX-1. We read the flags and see no over or under flow. At the same time, the encoder moves CW just a little, and the flags are now set to Overflow and the counter to 2. We read the counter and store the 2. Now we read the flags again. But again, the motor has wiggled CCW a little and we are now in position QPOSMAX-2 with flag Underflow set. So we record Underflow and Overflow as the flags.  We increase rollover_count by 1 to be consistent with Overflow and decrease it by 1 to be consistent with Underflow. (The sample code didn’t have the If Underflow statement, but since we are using these two flags rather than index event and dir to be consistent with our particular hardware setup, I’m assuming a slightly-modified set of checks here).

     

    To handle up to 2 (but not 3) rollovers occurring at any position after an initial flag read, here is some other pseudo code.

     

    <read and store flags in flags_before>

    <read and store position count>

    <read and store flags in flags_after>

    while <flags_before != flags_after>

                {

                flags_before=flags_after;

                <read and store position count>

                <read and store flags in flags_after>

    }

    clear flags that are set

    if (<overflow flag set in flags_after>

                rollover_count++;

    if <underflow flag set in flags_after>

                rollover_count--;

    position=rollover_count*ticks_per_encoder_revolution+stored_position_count

     

     

    But again, this doesn’t handle 3 rollovers that could occur within the period of execution of this code snippet.

     

    Comments? Suggestions?

    Regards,

    Janet

               

  • Janet,

    Janet Stillman said:
    Can you clarify how the SpinTac Positiion Convert code avoids the problem we were asking about of inconsistent flags and counter reading due to lack of an atomic read of the flags and counter?

    SpinTAC Position Convert code avoid this problem because it's only input is the motor electrical angle which is derived from just the position count.  Since it only needs to read the position count, this is atomic.  But it does require at least three samples per electrical angle of the motor, so there is an upper limit to the motor speed.

    Janet Stillman said:
    Also, we need a total position—that is, the calculation of rollover_counts*number_of_counts_per_encoder_revolution + current_encoder_position. Can the position convert code provide that for us?

    SpinTAC Position Convert does provide this.  This piece of software is designed to convert motor electrical angle into a mechanical position signal used for position control.  It will output the position within a bounded window in order to preserve accuracy.  It also provides a count of the number of rollovers from one bounded window to another for this exact purpose

    Your sample code looks reasonable, I would expect it to work ok.

    The easiest way to address these issues is to avoid tying yourself to the encoder rollover point for position tracking.  For example SpinTAC Position Convert does a similar approach but it does it every 20 mechanical revolutions, and it is tied against electrical angle rollovers, which is not necessarily the same as the encoder rollover point.  Because of this approach the motor could dither about the encoder rollover point forever and it wouldn't cause any kind of position issues.

  • Adam,

    So let's see if I understood what you meant about the SpinTAC code : by sampling the position count often enough that it can track when a rollover occurs without reference to flags, likely missing any temporary rollovers that would mess up the multiple-flag-checking arrangement of my code, the position convert would give me a current encoder count plus a current rollover count which I could read without risk of inconsistencies (assuming threads are appropriately controlled.) Is that right?

    Regards,

    Janet

  • Janet,

    Your understanding is correct.  The only thing I want to correct is the units.  SpinTAC Position Convert outputs in the units of mechanical revolution that varies between -10 and 10, and a count of the rollovers of from 10 to -10 (counted as positive rollovers) or from -10 to 10 (counted as negative rollovers).  From these values you can convert back into encoder counts.

  • Dear Adam,

    I'm having the question like Janet. In my project, I want to get a positive counts when motor rotate in forward direction (+) and get a negative counts when the motor reserves its direction (-). But as your explaination about SpinTAC Position Convert, if I use the STPOSCONV_getPosition_mrev() function, when the motor run in forward direction I can't get a positive encoder count?

    What should I do to resolve this problem?

    Many thanks!

  • If you are looking to use the mechanical position scheme employed by SpinTAC you would need to use the rollover counters in order to generate the units and values you expect.  The rollover counter will provide an indication of the absolute position of the axis and if a rollover occurs in the negative direction the value will be negative.

    SpinTAC's position system uses relative positioning, and the rollover counter is what allows you to convert into absolute.

  • Dear Adam,

    Thank you for your feedback in this topic as well as other topics to reply my questions related to get the absolute position from Qep Encoder based SpinTAC-CONV.

    As your explanation, SpinTAC's position system uses relative positioning, so in order to get the absolute position I will use the rollover counter to convert from the relative position to the absolute position. But how must I use to do this? What is the equation to use for this conversion? 

    In orther words, 1 rollover count = ??? Qep counts?

    Thank you for your support.