Oct 4, 2012

EasyDriver Part III Sleep and Enable

What is the diference between Enable and Sleep:
  - when you set Enable pin to LOW all the outputs of A397 chip are enabled.
    when set to HIGH all the outputs are disabled.

    Then for normal operation EasyDriver is set by default enabled. Even when stepper is stoped it recieves current and therefore is's position is locked.

    When disabled, the stepper do not recieve current and  therefore it is stopped and it's position is not locked (it can be manually spined).

- to put EasyDirve to Sleep, set  Sleep pin LOW
  for normal operation EasyDriver' Sleep pin is by default set to HIGH.

  When A397 is in Sleep mode, much of the internal circuitry including the outputs, are diabled. iI is used to minimize power consumtion of the chip. It takes about 1 ms to wake-up from Sleep mode .

Finally what is the diference:

  - When in Disabled mode, stepper is sleeping.
  - When in Sleep mode, steppe is sleeping and also A397 chip is sleeping. To Wake-up you have a delay of 1 ms.

Then for a radical power saving put it to Sleep otherwise use Disable.


Sep 30, 2012

My CNC 2.0 Part III

Go to Part I
Go to Part II

Finally the first usable PCB milled with my CNC

I adjusted the table level, now i have an error of 0,2mm. It begins to work fine, but it have to be better.

And now using it (the machine begins to improve itself)

now is the time to structure the wiring

This PCB implements this protoboard (as seen here) and is a shield for Arduino.
 To design the PCB i used DipTrace freeWare.
Here you can find the DIP, PDF, SVG and GCode files i used to mill this PCB.
To create th GCode file, first i print from DipTrace's PCBLayout to a PDF file, then with Adobe Illustrator:
  - i selected all the paths
  - and then Object - Path - Outline Stroke
  - No Fill
  - Stroke - Weight 0.01 mm
  - Stroke - Caps - Projecting
  - Stroke - Corner - Miter Join
  - PathFinder - Unite
Then i take InkSkape's laserengraver addin to create the GCode.
Finally i manually modified the GCode to update it to my standard.
To drill the holes, i exported from DipTrace's PCBLayout to 'Mach 2/3 Drill' from where i get the GCode file that i modified to update it to my standard.


Sep 27, 2012

CNC 2.0 beta 2 with fixed Bugs

 Finally assembled!

by the moment electronics still in protoboard and because that, the cables are hanging.

CNC calibrating the tool length



Now CNC 2.0 beta 2 with fixed Bugs

changes i made in Beta 2:

- some design and software errors are corrected.
- forgotten parts, holes .. are now placed.
- in order to make Z-Axis stronger i changed it. Now Ikea's Kvartal single track rail is used.
- the tool suport now is detachable. So it can be changed easily .
- a new tool lenght calibration is added.

Download 3D Model of beta 2
Download Software Beta 0.1
First test with my CNC
It is drawing the Arduino shield that i designed to hold the stepper drivers and the conections to the limit switches.
To mill the PCB i used Proxxon 28321 milling bits.
But unfortunately the first attempt was not good enough. As you can see in the photo above, the pen version is almost perfect, but the milled version is not so good. Then:
  - The machine works
  - The software begins to work reasonably well with 2D.
  - The machine's precision is good.
  - Although I have improved Z-axis, it is not stroger enough.
  - I have to level the horizontality of the table, because i detected a diference of about 0.5 mm in diferent points of the table. It does'nt seems too much, but if you have to scratch 0.25mm, adding 0.5mm gives a total of 0.75mm to scratch that, given the result, is too much.


Sep 18, 2012

Easy Driver with Arduino Part II (How to adjust the maximum Stepper Current)

Go to Part I
Part II
Go to Part III

   How to adjust the maximum current with Easy Driver.

Easy Driver let's you adjust the maximum current for the motor coils.
But what does this mean:

      More current ==> more torque / more Heat / less Speed  / more motor noise
      Less current  ==> less torque   / less Heat   / more Speed / less noise

Then the best choice is to adjust it to the minimum current given the needed torque.

I did it by trial and error; i expenrienced that when there's not enough torque, some (or all) steps where dropped, then i adjusted the current to the point at witch i never loose an step.

To adjust the current, simply turn the potentiometer (3):
CCW ==> less current
CW   ==> more current
Yes, the SilkScreen is wrong for squarish white box pot (schmalzhaus, says that for some Easy Driver with other pot, the silkscreeen is right) .
To know the actual current for each coil of the steper:
     Take a meter and monitor the voltage between points (1) and (2).
     Take a meter and monitor the resistance between points (4) and (5).
     then aply the following formula:
                 Imax = VREF/8RS                                     (page 5 of Allegro's A3967 Data Sheet)
        Imax is the  max current for each coil (obviously Imax has never to exceed the maximum current  suported by your stepper)
        VREF is the voltage you read in the meter
        RS      is the resistance you read in the meter (in the EasyDriver's schematic sheet Rs is 0.75 Ohm, but in my board i meter this and found that Rs is 1.5 Ohm) 
     For example i read:
          VREF = 1.7V
           RS    = 1.5 Ohm
          Then Imax = 1.7 /(8 * 1.5) = 0.141 A = 141 mA

Jun 15, 2012


Here is my CNC 2.0 beta 1:

Go to Part II / CNC 2.0 beta 2 (with fixed bugs)
Go to Part III


3D Model

You can download 3D files from Here. There are 3 file formats:

.DWFX   i recomend to use 'Autodesk Design Review'.
.DWG     i recomend to use 'Autodesk 123D'.
.STL you can use '123D' or Blender or MeshLab or ...

Maybe you are also interested about free educational version of Autodesk Software specially 'Autodesk Inventor'

I also published the model for Android and iPhone. You can find the app Here and the model for mobile Here.

LaserCutted Parts

I plan to use methacrylate (PMMA) for laser cutted parts. I will use 3 withs 10 mm, 5mm and 2mm.
you can download the 'svg' files and use InkScape to see them.



I explain the 'Beta 1' Electronics for the CNC in this Post of my Blog.


You can also download 'Beta 0.0' Software:

       for Arduino (Write in Processing style) here.

          Simply load it to Arduino IDE and upload to the Arduino.

       and computer side in Processing here.

Actually i'm working with Eclipse IDE.
Then to use the application you have just to:

  1- copy the 'CNC' folder to 'eclipse/workspace' directory
  2- from Eclipse go to 'File-->Import'
        2.1- as import source select 'Existing Projects into Workspace' and press 'Next'
       2.2- click on 'Select root directory' and press 'Browse'
       2.3- Browse to the 'CNC' directory you have just added and press 'OK' and then press 'Finish'

  that's all.

for questions about using Eclipse with Processing go here and here.

Run 'Main.java' as 'Java application' and in the program's screen press on 'folder button' and select one of th GCode files you find there and then press 'Play button'.

to make the GCode files, i actually use 'Inkscape'  with a laser engraver addin see this post for more details.


I desing this CNC to be specially unexpensive:
        The Stepper Motors are NEMA 17 (3 neded). you can find them here or here for about 16 €

        The Stepper driver i used are Easy Driver it cost about 12€ each (3 neded). you can find them here or here.

       The Arduino Board is Arduino Uno. You can get one from here or here. It costs about 22€.

        The rods are taken from 'Ikea Grundtal towel rail' 400 mm long (15 3/4") 2 rods costs about 5 €

        The ball bearing are 608ZZ abec 3 that are used mainly in skating. You can get 8 units for about 5 €

        I used a Rotary Grinder Tool with Flexible Shaft. You can get one from about 40 €.

        The Z rods are precission round brass tubes. I used 2 pcs of  8 x 0.45 x 305 mm (3 pcs costs about 7 €) and 2 pcs of 7 x 0.45 x 305 mm (3 pcs costs also about 7 €).

       The X Y Z treads are M5 (they cost about 3€ 1 m long), but with the same design it is posible to use M8 without modifications. Using M8 increases the speed of the machine by about 30%, and drecreases the machine precission (but it's not really important with M5 for each Step the machine moves 0.004 mm and 0.00625 with M8).

       You have to add the cost of nuts and bolts.  And finally the cost of laser cutted parts. By the moment i've no idea about its cost very expensive (200€), because at this moment the machine is not yet assembled.

Bill of Materials

Feb 22, 2012

Easy Driver With Arduino

Part I              (Maximum Stepper Speed)
Go to Part II   (Adjust max Stepper Current)
Go to Part III (Sleep an Enable)
Click Here to see and download the design of a PCB implementing this circuit.

An important thing to knwo about your stepper, is the maximum speed at witch it can be driven.
To know this, you can follow this LINK;

you need to knwo the specs of your stepper.
For my stepper:

  Voltage:                                  12v
  Inductance:                             46+-20% mH           then i take 50
  Steps per revolution:              Step Angle = 1.8º     360 / 1.8 = 200 Steps/rev
  Current:                                  0.33 A                       i take 135 mA because with easy
                                                                                   driver you can adjust the maximun current
                                                                                   with the potenciometer
                                                                                   (i will explain this in a future post)

then following the calculs from the previous link:

  T = 50 * 0.135 * 2 / 12 = 1.125 ms for a single Step

The default configuration of EasyDriver is eighth stepping then:

  T = 1.125 / 8 = 0.140 ms = 140 us for a single Step

given this we take a prescaler of 128 for the Timer2 (see coments in the code)

  128 / 16000000 = 0.000008 s-1 = 8 us-1         ( the frequency of the processor in the
                                                                              Arduino Uno is 16 MHz)

  Timer2 actulizes its counter every 8 us then, 140 / 8 = 17.5

then we have to program the counter for the Timer2 to 18 ( 18 = ceil(17.5) ), because of that we have a success of Timer2 every 18 * 8us = 144 us

and the speed for our stepper will be: 144 us * 1600 Steps/Revolution = 0.2304 s/Revolution

that is 1 / 0.2304 = 4.34 Revolutions / s , wich is an aproximation to the real speed, because there is an extra delay between steps introduced by the code itself  ( maybe 20 us extra delay ).

To see this working copy the following code to Arduino IDE, set the proper value for  this variables
 and run it.

This program also implements acceleration-desacceleration. You can change the amount of acceleration, changing the value of  'accelDuring' variable ( for example it accelerates during 10 steps the run at constant speed and finaly it desaccelerates during 10 steps ).
If you don't want acceleration set it to 0 ( accepted values are 0 - 255 ).

//Rev/sec = V/(L*2*Imax)/(steps/rev)  (Imax en A, L en mili Herns) p.e. 12/(46*2*0.33)/200
//T = L*Imax*2/V (T miliSegons/step)
  #define DIR_PIN 7
  #define STEP_PIN 6
  #define sbi(sfr,bit)  ( sfr |=   _BV(bit)  )         // a l'antiga manera. cbi() i sbi() son funcions obsoletes
  #define cbi(sfr,bit)  ( sfr &= ~(_BV(bit)) )  
  //  MS1  MS2  Resolution
  //  L    L    00 Full step (2 phase)
  //  H    L    10 Half step
  //  L    H    01 Quarter step
  //  H    H    11 Eighth step
  // per defecte a la easy driver MS1 = MS2 = HIGH
  float microStepping = 8;                             // Valor establert a la easyDriver ( MS1, MS2 )
  long stepsPerRev = 200;                              // característica del motor
  float l = 50;                                        // = 46 +- 20% (el pitjor dels casos es 55.2) característica del motor
  float v = 12;                                        // característica del motor
  float iMax = 0.135;                                  // mesurat amb el tester (cal dividir el resultat per 2 (hi ha 2 bobines))
                                                       // amb la EasyDriver podem controlar iMax abm el potenciòmetre
  float ocr2a;                                         // valor de OCR2A ( que depèn de la velocitat màxima del Stepper )
  int ocr2aIni;                                        // valor inicial de OCR2A donada l'acceleració
  int accelDuring = 10;                                // Accelera i desaccelera durant 10 Steps
  int downCounter = accelDuring;                       // el nombre d'Steps que falten fins acabar la desacceleració
  int upCounter = accelDuring;                         // el nombre d'Steps que falten fins acabar l'acceleració
  int accelDelta;                                      // valor en que varia OCR2A durant l'acceleració 
                                                       // ( p.e. si ha de pasar de 255 a 19 en 10 steps decremeta de 23 en 23 i começa a 249 )
  long stepsLeft = 0;                                  // nombre d'Steps que manque per acabar
  boolean running = false;                             // motor is running?
  void setup() {
    unsigned int usDelay;                              // temps d'espera entre Steps en us
    pinMode(DIR_PIN, OUTPUT);
    pinMode(STEP_PIN, OUTPUT);
    usDelay = l * 2000 * iMax / v / microStepping;     // temps d'espera entre steps en microsegons  ( T= L*Imax*2/V (T miliSegons/step) )
    ocr2a = ceil((float)usDelay / 8.0);                // l'enter mes proper donat l'interval del Timer2 ( 8 us )
    if(accelDuring > 0){
      accelDelta = (255 - int(ocr2a) ) / accelDuring;  // OCR2A pasarà del enter mes proper a 255 fins a ocr2a
                                                       // el valor que hem calculat per la velocitat màxima
        if(ocr2a < 255){                               // la durada de l'acceleració no pot ser tan gran com esperem
          accelDelta =1;
          ocr2aIni = 255;
          accelDuring = 255 - ocr2a;                   // durada màxima de l'acceleració permesa
        }else{                                         // ocr2a = 255, no hi pot haver acceleració
          accelDelta = 0;
          accelDuring = 0;
          ocr2aIni = ocr2a;
      }else                                            // acceleració segons la definició
        ocr2aIni = ocr2a + accelDelta * accelDuring;   // calcula el OCR2A inicial donada l'acceleració
    }else                                              // no hi ha acceleració
      ocr2aIni = ocr2a;
    Serial.print("Inter Step Delay: ");
    Serial.println(" us");
    Serial.print("Max Speed: ");
    Serial.print( 60000000.0 / ((float)stepsPerRev * microStepping * (usDelay)) );
    Serial.println(" RPM");
    Serial.print("Inter Step Delay programat a Timer2: ");
    Serial.println((int( ceil( (float)usDelay / 8.0 ) ))*8);
    Serial.print("Max Speed Real: ");
    Serial.print( 60000000.0 / ((float)stepsPerRev * microStepping * ((int( ceil( (float)usDelay / 8.0 ) ))*8)) );
  long nVoltes = 1;
  long nSteps = nVoltes * stepsPerRev * microStepping;

  void loop(){
      nSteps = -nSteps;
  void driveStepper(long lnSteps){
    int dir = (lnSteps > 0)? HIGH:LOW;
    lnSteps = abs(lnSteps);
    OCR2A = ocr2aIni;                // reinicialitza el contador (permet acceleració)
    upCounter = accelDuring;
    downCounter = accelDuring;
    running = true;
    stepsLeft = lnSteps;
  void setTimer2(int lusDelay) {
    // The ATmega328P has three timers known as Timer 0, Timer 1, and Timer 2
    // Each timer has two output compare registers 
    // Each of the timers has a prescaler that generates the timer clock by dividing
    //         the system clock by a prescale factor such as 1, 8, 64, 256, or 1024
    //         Note that Timer 2 has a different set of prescale values from the other timers
    // The Arduino has a system clock of 16MHz and the timer clock frequency will be
    //         the system clock frequency divided by the prescale factor
    // The timers can also generate interrupts on overflow and/or match against either output compare register
    // TCCRnA and TCCRnB. The Timer/Counter Control Registers hold the main control bits
    //            for the timer. (Note that TCCRnA and TCCRnB do not correspond to the outputs A and B.) 
    // TCCRnA and TCCRnB hold several groups of bits: 
    //     Waveform Generation Mode bits (WGM): these control the overall mode of the timer.
    //         (These bits are split between TCCRnA and TCCRnB.) 
    //     Clock Select bits (CS): these control the clock prescaler 
    //     Compare Match Output A Mode bits (COMnA): these enable/disable/invert output A 
    //     Compare Match Output B Mode bits (COMnB): these enable/disable/invert output B 
    // OCRnA and OCRnB. The Output Compare Registers set the levels at which outputs A and B will be affected
    // TIMSK2 – Timer2 Interrupt Mask Register
    //     OCIE2B: Timer2 Output Compare Match B Interrupt Enable
    //     OCIE2A: Timer2 Output Compare Match A Interrupt Enable
    //     TOIE2:  Timer2 Overflow Interrupt Enable
    // Timer 1 is a 16-bit timer and has additional modes. Timer 2 has different prescaler values
    // The Arduino uses Timer 0 internally for the millis() and delay() functions
    // OC0A pin  6   OC0B pin  5
    // OC1A pin  9   OC1B pin 10
    // OC2A pin 11   OC2B pin  3 
    cli();                           // plana 10. Bit 7 Clear interrupts
    cbi(TCCR2A, COM2A0 );            // plana 158. Table 17-2. Normal port operation, OC0A disconnected. 
    cbi(TCCR2A, COM2A1 );            // 00 deconecta el pin A del timer2
    cbi(TCCR2A, WGM20  );            // TCCR2A Regitre A de control del timer 2
    sbi(TCCR2A, WGM21  );       // plana 160 i 149. Clear Timer on Compare
    cbi(TCCR2B, WGM22  );            // WGM2 = 010 ==> mode of operation Clear Timer on Compare (CTC)
                                     // The counter value TCNT2 increases until TCNT2 == OCR2A, 
                                     // and then counter (TCNT2) is cleared
                                     // repeteix el cilce 0 --> valor ( valor clocks )
    sbi(TCCR2B, CS22   );            // TCCR2B Regitre B de control del timer 2
    cbi(TCCR2B, CS21   );       // Plana 162
    sbi(TCCR2B, CS20   );            // CS2 = 101 prescaler = 128 ==> 128/16.000.000 = 0.000008 s-1 = 8us-1
                                     // màxim temps que es pot contar = 8 * 255 = 2040 us
    sbi(TIMSK2, OCIE2A  );           // Timer2 Output Compare Match A Interrupt Enable. plana 163
    cbi(ASSR, AS2);              // AS2 = 0 clocked from the I/O clock
                                     // plana 164. Asynchronous Status Register
                                     // When AS2 is written to zero, Timer/Counter2 is clocked from the I/O clock, clkI/O.
                                     // When AS2 is written to one, Timer/Counter2 is clocked from a crystal Oscillator
                                     // connected to the Timer Oscillator 1 (TOSC1) pin.    
    OCR2A = lusDelay;                //  si p.e. OCR2A = 21 --> 21*0.000008 = 168us-1  . cridem la funcio un cop cada 168 us. plana 162
    TCNT2 = 0;                       // reset Timer2 counter
    sei();                           // Enable Interrupts
  void stopTimer2() {
    cbi(TIMSK2, OCIE2A  );           // Timer2 Output Compare Match A Interrupt Disable. plana 163
  ISR(TIMER2_COMPA_vect) {           // Timer2 Output Compare Match A Interrupt
                                     // definició dels vectors a Arduino\hardware\tools\avr\avr\include\iom328p.h     
                                     // definitions for ATmega328P
    if(stepsLeft > 0){
      if(stepsLeft == downCounter){  // ha de desaccelerar
        OCR2A += accelDelta;         // incrementa el temps entre Steps en CS22:0 us (el proper Step es produirà 8 us mes tard)
      else if(upCounter >0){         // ha d'accelerar
        OCR2A -= accelDelta;         // decrementa el temps entre Steps en CS22:0 us (el proper Step es produirà 8 us abans)
      digitalWrite(STEP_PIN, HIGH);  // envia el pols a la EasyDriver per avançar 1 Step
      digitalWrite(STEP_PIN, LOW);   // A low-to-high transition on the STEP input sequences the translator 
                                     // and advances the motor one increment.       
                                     // Minimum STEP Pulse Width 1.0 μs (plana 7 de 'A3967.pdf')
                                     // la intruccio NOP triga 1 Clock ( 0,0625 us = 62.5 ns ) per tant
                                     // la instrucció digitalWrite ha de trigar més de 16 Clocks
                                     // mirar el codi a 'wiring_digital.c'
                                     // segons els forums 'digitalWrite()' sembla trigar entre 6 i 9 us
                                     // depenent de si el port es PWM o no
                                     // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230286016
    else                             // para el motor
      running = false;

Feb 6, 2012

Trheading a function with parameters in Processing

In Processing if you want that a function is executed in a diferent thread, you have just to use the following command:

  thread("myFunc");       // this command creates a new thread and executes myFunc in that thread

  void myFunc(){ ..... }

  The restriction is that 'myFunc' must be void, with no parameters and it could not be declared in a subclass in the sketch (it must be a public function in the pApplet class).

With the following code you could thread a public function inside any class, with any number of parameters:

public void thread(final Metode metode, final Object... parametres) {                 // és el mateix que el thread de Processing, però amb paràmetres
  Thread later = new Thread() {  public void run() {  metode.run(parametres);  }  };  // i a més el Mètode pot pertanyer a qualsevol Clase

to use this alternative version of 'thread', you have to do the following:

 Metode resend = new Metode(myObject, "myFunc", byte.class, int.class);
 thread( resend, toSend, mill );
where 'myObject'  is an object of the cass that contains myFunc  (if the function is in in the same class were you declare 'resend' you can use 'this' instead of 'myObject'):
  class myClass{
    public void myFunc(byte toSend, int mill){ ..... }

  myClass myObject = new myClass();

you can find 'Metode' class in this post: Metode Class