austin.m.bryan (Customer) asked a question.

Best Method for Reading an Absolute Encoder

Hi everyone,

 

I made a post last week on the Electric Field Device subforum about reading a 2048PPR encoder. I realized it was much too fast for the digital card I'm using (P1-16ND3) so I've exchanged it with a Koyo 360PPR (https://www.automationdirect.com/adc/shopping/catalog/sensors_-z-_encoders/rotary_encoders/medium_duty_absolute_encoders_(gray_code)/trd-na360nwd) encoder to measure an angle of rotation (I probably should have used this one to begin with!).

 

I'm attempting to read the gray code value that it's outputting and am doing so by reading each bit with the P1.readDiscrete function as shown below (full code):

 

This method is giving me a 9 bit gray code value but it is not following in sequence, so it does not start at 0 and work up to 360. I have made sure to include a line trimming 76 excess codes as mentioned in the data sheet of this particular encoder but the output values are still in a random order.

 

I'm wondering: is there a better way to read and decode each gray code pattern? It seems like reading each bit individually is not working but I really don't know an alternative way of approaching this.

 

Thanks in advance,

 

 

 


  • austin.m.bryan (Customer)

    Here is my full code, I forgot to include it in the original post:

     

    1. #include <P1AM.h>
    2.  
    3. bool greyVal[9];
    4. int rawDecVal;
    5. int adjustedDecVal;
    6.  
    7. //==========
    8.  
    9. void setup() {
    10. Serial.begin(115200); //initialize serial communication at 115200 bits per second
    11. while (!P1.init()){
    12. ; //Wait for Modules to Sign on
    13. }
    14. }
    15.  
    16. //==========
    17.  
    18. void loop() {
    19.  
    20. bool binVal[] = {0,0,0,0,0,0,0,0,0}; //must be locally declared to prevent previous binVals from messing up current conversion
    21.  
    22. greyVal[0] = !P1.readDiscrete(1,2);
    23. greyVal[1] = !P1.readDiscrete(1,3);
    24. greyVal[2] = !P1.readDiscrete(1,4);
    25. greyVal[3] = !P1.readDiscrete(1,5);
    26. greyVal[4] = !P1.readDiscrete(1,6);
    27. greyVal[5] = !P1.readDiscrete(1,7);
    28. greyVal[6] = !P1.readDiscrete(1,9);
    29. greyVal[7] = !P1.readDiscrete(1,10);
    30. greyVal[8] = !P1.readDiscrete(1,11);
    31.  
    32. for (int i = 0; i < 9; i++){
    33. Serial.print(greyVal[i]);
    34. }
    35.  
    36. Serial.print(' ');
    37. binVal[0] = greyVal[0]; //MSB of the binary stays the same as the grey value
    38.  
    39. //XOR the values after the MSB
    40. for (int j = 0; j < 9; j++){
    41. if (binVal[j] == greyVal[j+1]){
    42. binVal[j+1] = 0;
    43. }
    44. else{
    45. binVal[j+1] = 1;
    46. }
    47. Serial.print(binVal[j]);
    48.  
    49. }
    50.  
    51. Serial.print(' ');
    52. //Convert binary array to a decimal value
    53. rawDecVal = (binVal[0]*256)+(binVal[1]*128)+(binVal[2]*64)+(binVal[3]*32)+(binVal[4]*16)+(binVal[5]*8)+(binVal[6]*4)+(binVal[7]*2)+(binVal[8]*1);
    54.  
    55. adjustedDecVal = rawDecVal - 76; //trim excess gray codes from encoder. Should start at 76 (0) and end at 435 (360)
    56.  
    57. Serial.print(rawDecVal);
    58. Serial.println();
    59. }

     

    Expand Post
  • PouchesInc (Customer)

    I dont really know C coding so I cant help you much with this, but I was wondering since you said "the numbers are not following in sequence" if you are trying to read it as binary directly, or if you accounted for the different way gray code counts? Gray code doesnt go in the same order as binary counting does. With gray, only a single bit changes each location, so the bit order change is different.

    https://en.wikipedia.org/wiki/Gray_code#Converting_to_and_from_Gray_code

    Expand Post
    • austin.m.bryan (Customer)

      PouchesInc,

       

      Sorry, should have been more specific. I meant that they gray code values it is outputting, once decoded to an integer, do not follow the correct sequence.

       

      Thank you,

      • z28z34man (Customer)

        When reading individual bits one at a time the encoder could very well have moved from the time of the first read to the time of the last read as going through the base controller is not instant. if the encoder moves at all in between reads it will through the value way off. that is why I would suggest reading all the bits at once with a P1.readDiscrete(1) then use a for loop to fill your bit array.

        Expand Post
  • z28z34man (Customer)

    i would read all the inputs at once using the flowing

    allInputChannels = P1.readDiscrete(1)

     

    it will return a HEX value. you then can convert the HEX in to individual bits. this should be much faster than going through the base controller 8 times.

    • austin.m.bryan (Customer)

      sampleSerialOutput

      1. #include <P1AM.h>
      2.  
      3. void setup() {
      4. Serial.begin(115200); //initialize serial communication at 115200 bits per second
      5. while (!P1.init()){
      6. ; //Wait for Modules to Sign on
      7. }
      8. }
      9.  
      10. void loop() {
      11. uint16_t allPoints = P1.readDiscrete(1); // Read state of all channels for slot 1
      12. Serial.println(allPoints,HEX);
      13. }

      Alright, I've got it set up to use P1.readDiscrete(1) now, I've attached a sample of what it's printing to the Serial monitor as an image, as well as my code. Note that the values are changing as I turn the encoder shaft which seems good.

       

      My question now is: how would you convert the value to individual bits to store in the array? Just read the high/low values of each pin and trim where necessary?

       

       

      Expand Post
      • z28z34man (Customer)

        this will convert to a binary array that you can then do with as you need

         

        1. #include <P1AM.h>
        2. int allPoints;
        3. bool binatyallpoints[16];
        4. void setup() {
        5. Serial.begin(115200); //initialize serial communication at 115200 bits per second
        6. while (!P1.init()){
        7. ; //Wait for Modules to Sign on
        8. }
        9. }
        10. void loop() {
        11. allPoints = P1.readDiscrete(1); // Read state of all channels for slot 1
        12. for (int i = 0; i <16; i++){
        13. binatyallpoints[i] = bitRead(allPoints, i);
        14. }
        15. }

         

        Expand Post
  • kewakl (Customer)

    >This method is giving me a 9 bit gray code value but it is not following in sequence,

     

    What sequence do you expect and what sequence do you observe?

    <example image>

     [Edit: the image is from this 'edn' article]

    • austin.m.bryan (Customer)

      kewaki,

       

      The expected gray code sequence should follow the one in the Koyo manual for the 360PPR encoder. The sequence I am getting is completely random:

       

      KoyoGrayCodes

      Expand Post
10 of 19