Go Down

Topic: Mini Mill DRO (Read 6531 times) previous topic - next topic

WMello

Rotary Quad Encoder + Arduino Mini







Video: Video

More pictures: SlideShow

Just a proof of concept

Wagner



Robia42


loudwallpaper69

Nicely done, I can see this having lots of uses. I'm currently building a new drill press table and this would be a nice addition. Can we see your code?

WMello

Code:

Code: [Select]
/******************************************************************/
/*                                                                */
/*                            MillDRO - Z                         */
/*                                                                */
/*                            Apr 4, 2015                         */
/*                                                                */
/******************************************************************/

// Quad Encoder 600 ppr LPA3806
// Red    5 Vcc
// Black  Gnd
// Green  Chanel A Pin 2 (Int 1)
// White  Chanel B Pin 3 (Int 2)

// Display 4 digit SAA1064
// 3/8    None                                            -a-
// 5/8    None                                           f   b
// VCC    5 Vcc                                           -g-
// GND    Gnd                                            e   c
// ADR    Gnd (Read Addr 0x70 / Write Addr 0x71)          -d-   p
// SDA    Pin A4 SDA
// SCL    Pin A5 SCL                                    pgfe dcba

// Zero switch
// COM    Gnd
// NO     Pin 4   

/******************************************************************/

#include "Wire.h"     // Include I2C bus

#define DSP   0x38    // Display Addr (0x70>>1)

#define DSD   100     // Refresh period (100 ms)

byte DspDig[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

/******************************************************************/

#define QFT   0.4     // Encoder Factor (pulse to inch * 1000)

#define QCA   2       // Encoder Chanel A (Pin 2)
#define QCB   3       // Encoder Chanel B (Pin 3)

#define QIA   0       // Encoder Chanel A (Int 1)
#define QIB   1       // Encoder Chanel B (Int 2)

long  QenCnt;         // Counter (inch * 1000) 

/******************************************************************/

#define SWZ   4       // EZero switch (Pin 4)

/******************************************************************/


void setup(void)
{
 Wire.begin();                              // Start up I2C bus
 delay(500);
 QenCnt=0;                                  // Counter init = 0
 IniDsp();
 ClrDsp();
 IniSwz();
 IniQen();
}


void loop(void)
{
 ThrSwz();
 ThrQen();
 delay(DSD);
}


/******************************************************************/


void IniSwz(void)                           // Init switch
{
 pinMode(SWZ,INPUT_PULLUP);
}


void ThrSwz(void)
{
 if(!digitalRead(SWZ))
  QenCnt=0;
}


/******************************************************************/


void IniQen(void)                           // Init encoder
{
 pinMode(QCA,INPUT_PULLUP);
 pinMode(QCB,INPUT_PULLUP);
 attachInterrupt(QIA,QenChAInt,CHANGE);
 attachInterrupt(QIB,QenChBInt,CHANGE);
}


void ThrQen(void)
{
 long v;

 v=(long)((float)QenCnt*QFT);
 VluDsp(v);
}


void QenChAInt(void)                        // Interruption chanel A
{
 if(PIND&4)
  {                 // Chanel A High
   if(PIND&8)
    QenCnt--;       // Chanel B High (decrease)
   else
    QenCnt++;       // Chanel B Low  (increase)
  }
 else
  {                 // Chanel A Low
   if(PIND&8)
    QenCnt++;       // Chanel B High (increase)
   else
    QenCnt--;       // Chanel B Low  (decrease)
  }
}


void QenChBInt(void)                        // Interruption chanel B
{
 if(PIND&8)
  {                 // Chanel B High
   if(PIND&4)
    QenCnt++;       // Chanel A High (increase)
   else
    QenCnt--;       // Chanel A Low  (decrease)
  }
 else
  {                 // Chanel B Low
   if(PIND&4)
    QenCnt--;       // Chanel A High (decrease)
   else
    QenCnt++;       // Chanel A Low  (increase)
  }
}


/******************************************************************/


void IniDsp(void)                           // Init display
{
 Wire.beginTransmission(DSP);
 Wire.write(B00000000);                     // Instruction byte. Zero: the next byte is the control byte
 Wire.write(B00100111);                     // Control byte (dynamic mode, digits 1+3 on, digits 2+4 on, 6 mA current
 Wire.endTransmission();
}


void ClrDsp(void)                           // Clears display
{
 Wire.beginTransmission(DSP);
 Wire.write(B00000001);                     // Instruction byte. One: first digit is 1 (right side)
 Wire.write(B00000000);                     // Digit 1 (Right)
 Wire.write(B00000000);                     // Digit 2
 Wire.write(B00000000);                     // Digit 3
 Wire.write(B00000000);                     // Digit 4 (Left)
 Wire.endTransmission();
}


void VluDsp(long v)                           // Display value
{
 byte i;
 byte d[4];
 
 if(v<0)
  v*=-1;                                         // Negative
 for(i=0;i<4;d[i]=v%10,v/=10,i++);
 Wire.beginTransmission(DSP);
 Wire.write(B00000001);                    // Instruction byte. One: first digit is 1 (right side)
 Wire.write(DspDig[d[3]]|0x80);          // Digit 4 (left) + decimal point
 Wire.write(DspDig[d[2]]);                  // Digit 3
 Wire.write(DspDig[d[1]]);                  // Digit 2
 Wire.write(DspDig[d[0]]);                  // Digit 1 (right)
 Wire.endTransmission();

 


janvier123

what does it do ?
i dont get it :(

WMello

#5
Apr 16, 2015, 02:20 pm Last Edit: Apr 16, 2015, 02:25 pm by WMello
Hi Janvier123

DRO stands for "Digital Read Out".
It is a device used in milling machines for positioning.
It normally shows the position of the milling head in the X, Y and Z axis.
In this project, the Arduino is counting pulses from the encoder and showing the position for the Z axis, in inches.

Wagner


janvier123


CircuitOfHappyness




I am trying to use the exact encoder for measuring the rotational position of my chuck at my lathe but with an arduino leonardo. I have stripped your code of the display parts because I am trying to first do the output to the serial monitor and later to an OLED that I have already working. This is why I introduced the new variable "grad_counter ".

The problem is that the counter is only counting upwards and seem only to work half the 360° turn of the encoders shaft. I somewhat have the feeling, that the PIN address (PIND & 4; PIND  & 8 ) that you are reading directly from are not the same for a mini as for a leonardo. Might this be the problem? Thanks for your help.

Here is 'my' code (I left the parts that I excluded in to make it easier comparable):

Code: [Select]
//******************************************************************/
/*                                                                */
/*                            modified MillDRO - Z                 */
/*                                                                */
/*                            June 2, 2015                         */
/*                                                                */
/******************************************************************/

// Quad Encoder 600 ppr LPA3806
// Red    5 Vcc
// Black  Gnd
// Green  Chanel A Pin 2 (Int 1)
// White  Chanel B Pin 3 (Int 2)

/******************************************************************/

//#include "Wire.h"     // Include I2C bus

//#define DSP   0x38    // Display Addr (0x70>>1)

//#define DSD   100     // Refresh period (100 ms)

//byte DspDig[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

/******************************************************************/

#define QFT   0.6     // Encoder Factor (pulse to angle)

#define QCA   2       // Encoder Chanel A (Pin 2)
#define QCB   3       // Encoder Chanel B (Pin 3)

#define QIA   0       // Encoder Chanel A (Int 1)
#define QIB   1       // Encoder Chanel B (Int 2)

long  QenCnt;         // Counter (angle)
volatile float grad_counter = 0;

/******************************************************************/

//#define SWZ   4       // EZero switch (Pin 4)

/******************************************************************/


void setup(void)
{
 //Wire.begin();                              // Start up I2C bus
 //delay(500);
 QenCnt=0;                                  // Counter init = 0
 //IniDsp();
 //ClrDsp();
 //IniSwz();
 IniQen();
  Serial.begin (115200);
  while(!Serial); // nur bei Leonardo nötig
  Serial.println("Programm start");
}


void loop(void)
{
 //ThrSwz();
 ThrQen();
 delay(100);
}


/******************************************************************/


//void IniSwz(void)                           // Init switch
//{
// pinMode(SWZ,INPUT_PULLUP);
//}


//void ThrSwz(void)
//{
// if(!digitalRead(SWZ))
//  QenCnt=0;
//}


/******************************************************************/


void IniQen(void)                           // Init encoder
{
 pinMode(QCA,INPUT_PULLUP);
 pinMode(QCB,INPUT_PULLUP);
 attachInterrupt(QIA,QenChAInt,CHANGE);
 attachInterrupt(QIB,QenChBInt,CHANGE);
}


void ThrQen(void)
{
 long v;

 v=(long)((float)QenCnt*QFT);
 grad_counter=v;
 Serial.print("Counter value: ");
 Serial.println(grad_counter);
 //VluDsp(v);
}


void QenChAInt(void)                        // Interruption chanel A
{
 if(PIND&4)
  {                 // Chanel A High
   if(PIND&8)
    QenCnt--;       // Chanel B High (decrease)
   else
    QenCnt++;       // Chanel B Low  (increase)
  }
 else
  {                 // Chanel A Low
   if(PIND&8)
    QenCnt++;       // Chanel B High (increase)
   else
    QenCnt--;       // Chanel B Low  (decrease)
  }
}


void QenChBInt(void)                        // Interruption chanel B
{
 if(PIND&8)
  {                 // Chanel B High
   if(PIND&4)
    QenCnt++;       // Chanel A High (increase)
   else
    QenCnt--;       // Chanel A Low  (decrease)
  }
 else
  {                 // Chanel B Low
   if(PIND&4)
    QenCnt--;       // Chanel A High (decrease)
   else
    QenCnt++;       // Chanel A Low  (increase)
  }
}

Leonardo on MacBook Air

WMello

Hi CircuitOfHappyness


I don't know exactly why your setup is not working. Could be a failure on reading the state of the digital pins 2 and 3 (PIND) or that only one of the two interrupt lines are occurring. I think you are right about the problem been on the differences between Arduinos Mini and Leonardo.


PIND&4 and PIND&8 tests the register D for the levels of the third and fourth bits  (right to left). These bits corresponds for the digital pins 2 and 3.

I've used Arduino Mini Pro, processor ATmega168. Leonardo uses ATmega32u4. I don't know if they work the same way.

Apparently the interruptions inputs are also different. See: Arduino Interrupt

Do you have a Mini or Uno to test ?

Wagner

WMello

Hi CircuitOfHappyness

Looking at the datasheets for the Atmega32 (Leonardo). It is really different from the Uno/Mini.

Try using:
PIND&1 instead of PIND&4
PIND&2 instead of PIND&8

Or, use

digitalRead(2) instead of PIND&4
digitalRead(3) instead of PIND&8

The option for digitalRead is much slower; it may not work, depending on the frequency of your pulses.

Wagner

CircuitOfHappyness

Thanks. :smiley-mr-green:

This setup worked:
PIND&1 instead of PIND&4
PIND&2 instead of PIND&8

I tested my code with a mechanical encoder to see if the ports are addressed correctly. So far I am fine.

It seems that the encoder (LPA3806) is not working properly. I checked if the manufacturer has a cable twist, but everything seems al right according to this
Rotary encoder teardown (LPA3806-600BM-G5-24C)

I also tried to connect two LED's to the encoder, turn the shaft slowly and check if they are blinking. They don't! They do even not light up at all. Only if I remove the ground pin the LED's start constantly glowing.

I guess I will contact a friend with a scope to check if the encoder is broken, or are there any other ideas form this community?
Leonardo on MacBook Air

CircuitOfHappyness

O.K. I fiddled around some more.

The green channel is working and triggering the interrupt B. The white one is not responding on interrupt A. If I switch the cable at the arduino than green is triggering interrupt A. White remains dead.



This results in the counter just going +1 and -1 so the output is

0
1
0
1
0

you get the point.

Nevertheless I will go for the scope in the next days.
Leonardo on MacBook Air

CircuitOfHappyness

Tested it with an oscilloscope. White channel is dead.  >:(  Ordered a new one. I hope the next one is O.K.

See how the test went:
https://youtu.be/HuvOfL-acC4

Thanks a lot for the help.
Leonardo on MacBook Air

WMello

Hello,


Please be aware that the outputs of the encoder are of the type "open collector".
They need a resistor pulling then up to the 5 V line.

On my project, the resistors are provided by the microcontroller. See the code: pinMode(QCA,INPUT_PULLUP);

I do believe that your encoder is defective.

Wagner

mulexxl

Hello, you can ask for a diagram and parts list

Go Up