Showing posts with label arduino. Show all posts
Showing posts with label arduino. Show all posts

Saturday, 16 March 2019

Arduino based quadrature decoder experiments


While looking for a very efficient method to decode quadrature signals directly on the Arduino Nano, I came up with this solution for 2 encoders. While not suitable for high resolution encoders, it is at least fast enough for 400 CPR running at 3000 rpm. Interesting finding was the lookup table method found else where on the internet, is about twice as slow. The  subroutine is called from a timer interrupt routine.





// GPL, Hannes de Waal 2019 
// Measured 97 KHz, 5.8us duration with lookup table 
// 128.9 kHz with 3.36us using 2 case statements, instead of lookup

void read_encoder() {

 
  static uint8_t enc1_ab = 0;
  static uint8_t enc1_idx = 0;
  static uint8_t enc2_ab = 0;
  static uint8_t enc3_ab = 0;
  
  /**/
  unsigned char port = PINC;
  enc1_ab <<= 2;               //remember previous state
  enc1_ab |=  ( port & 0x03 );  //add current state
  enc1_idx <<= 1;
  enc1_idx |= ( port & 0b00000100 );
  
  enc2_ab <<= 2; 
  enc2_ab |= ( port>>2 & 0x03 );
 // Pos1 +=  enc_states[( enc2_ab & 0x0f )];
 
/* state transitions
  10 -> 11 +
  11 -> 01 +
  01 -> 00 +
  00 -> 10 +
  10 -> 00 -
  00 -> 01 -
  01 -> 11 -
  11 -> 10 -
  10 -> 01 e
  01 -> 10 e
  00 -> 11 e
  11 -> 00 e
  */
  switch( ( enc1_ab & 0x0f ) ) {
    
    case 0b00001011 : Pos += 1; break;
    case 0b00001101 : Pos += 1; break;
    case 0b00000100 : Pos += 1; break;
    case 0b00000010 : Pos += 1; break;
    
    case 0b00001000 : Pos -= 1; break;
    case 0b00000001 : Pos -= 1; break;
    case 0b00000111 : Pos -= 1; break;
    case 0b00001110 : Pos -= 1; break;
    
    case 0b00001001 : Err ++; break;
    case 0b00000110 : Err ++; break;
    case 0b00000011 : Err ++; break;
    case 0b00001100 : Err ++; break;
   // 0000 hold
   // 0101 hold
   // 1010 hold
   // 1111 hold
        
  }
  

 switch( ( enc2_ab & 0x0f ) ) {
    
    case 0b00001011 : Pos1 += 1; break;
    case 0b00001101 : Pos1 += 1; break;
    case 0b00000100 : Pos1 += 1; break;
    case 0b00000010 : Pos1 += 1; break;
    
    case 0b00001000 : Pos1 -= 1; break;
    case 0b00000001 : Pos1 -= 1; break;
    case 0b00000111 : Pos1 -= 1; break;
    case 0b00001110 : Pos1 -= 1; break;
    
    case 0b00001001 : Err1 ++; break;
    case 0b00000110 : Err1 ++; break;
    case 0b00000011 : Err1 ++; break;
    case 0b00001100 : Err1 ++; break;
        
  }
 
}

Thursday, 3 January 2019

Writing Software for CNC Applications

Need to synchronise the spindle to the C axis? Or implement an electronic gearbox reduction for a lathe? Stepper on a rotary table? Or just plot a circle on XY planes? all of these implementations have a few common problems to solve, one of which is to coordinate the movement of two or more axis. Since each axis might have different resolution and or require fractional advance of that resolution to accomplish the desired motion. Most open and closed source implementations seem to make use of some sort of  Bresenham's line algorithm here, to deal with the resulting error.

void main () {
   double y0 = 0.00;
   double dy = 0.0125; // 5mm / 100x4
   double dx = 23; // gear ratio
   double k = (double)dy / (double)dx;

    double y = (double)y0;
    double yi = 0.0000;

    for (int x=0; x<23; x++)
    {
        y += k;

        if ((y+0.0005) > yi) // error larger than 0.0005? increment yi
        //if ((int)(y+0.5) > yi)
        {
            yi=yi+0.0005;
        }
      printf("%02d %02f %02f\n", x, y, yi );
    }

}

Let us look at Gear ratios, the concept of accurate synchronized electronic reduction gears for the lathe made me think. Why not use closed loop phased locked control?

1) decode position pulses to direction and 4x steps,
2) Multiply step pules by M an then divide by N. 
3) feed the resulting pules directly to a stepper which can act as the divider

To implement this one would require a PLL for multiplication. Using this method should make it possible to implement any gear ratio without error.  I have implemented this on Arduino making use of the internal clocks and one external PLL 4046. The lock and capture range now determine the spindle speeds. The solution runs entirely on hardware no software is required once the counters have been set. It is abit more complex than this, since direction needs to be accounted for. But here is the gist of it. I then found commercial industrial solution doing exactly this at http://www.motrona.net/encoder_divider.html




Sunday, 20 May 2018

Quadrature decoder ideas for glass scales and rotary encoders on Arduino and AVR

Ever wonder how the Heidenhain glass scales, can measure at increments of 0,5 µm? if the graduation on the scale is only 20um? If you come from the digital world, there are four transitions so the minimum should be 4um.
This mystery made me read up on the Heidenhain signals 1VPP or 11 µAPP ( 1VSS, 11 µASS ) These are analog signals, if you read the older literature it becomes clear that photo sensitive devices are used to generate the current, the 1Vpp signals are probably pre-loaded with a 90ohm resistor. 
Vernier scales are similar, so are modulation techniques like QAM, QPSK. With glass scales there is no amplitude or phase modulation on top of the carrier, only two orthogonal signals, the rotational relationship between the two base-band signals (I/Q) translates to position, speed and velocity. 
So what advantages do analog signals have over digital? The states are infinite, limited only by noise. But how to extract infinite states from two orthogonal signals? Run them through an AD converter and calculate the angle., this will work but the system response is limited by conversion rate and calculation performance.

Investigating further I stumbled on CORDIC https://en.wikipedia.org/wiki/CORDIC

With a search for CORDIC Quardrature decoder, I found various other methods of Sine/Cosine to Digital Conversion
http://www.ichaus.de/upload/pdf/WP7en_High-Precision_Interpolation_140124.pdf

  Flash Conversion

 Vector -Tracking Conversion

 SAR Conversion with Sample-and- Hold Stage

 Continuous -Sampling A/D Conversion
Out of pure curiosity, I will implement the continuous sampling conversion with CORDIS lookup on the Arduino, and perhaps try the vector tracking conversion on the Attiny2313
Should this work, I will try to convert my Sino Digital scales to analog and see what accuracy I can achieve. Perhaps even build a Heidenhain scale interface for the Touch DRO Project.

Resources 

CORDIC


https://eprints.soton.ac.uk/267873/1/tcas1_cordic_review.pdf

https://www.mikrocontroller.net/articles/AVR-CORDIC

Linear interpolation

https://www.mikrocontroller.net/articles/AVR_Arithmetik/Sinus_und_Cosinus_(Lineare_Interpolation) 

Fast Sampling on AVR
http://yaab-arduino.blogspot.com/2015/02/fast-sampling-from-analog-input.html


http://wiki.linuxcnc.org/cgi-bin/wiki.pl?ResolverToQuadratureConverter


Chipmaster Gear Cutting

  Calculate all the possible gear combinations for the gear selector to cut a 15TPI thread: Imperial TPI C 5 24 20 Imperial TPI ...