jueves, 20 de febrero de 2014

Pruebas con motores paso a paso (III)

Cuando adquirimos un motor del tipo paso a paso tiene una serie de características :





* Voltaje de alimentación de las bobinas.En mi experiencia , a veces me he vuelto loco si viene expresado en voltaje de la bobina . Hay que tener encuenta que el driver muchas veces lo que nos hace es dividir esta tensión y aplica +V/2 a una salida de bobina , mientras que en la otra aplica -V/2. Total, que la tension entre los dos bornes del bobinado es V, entonces cuando compro el motor , la característica que me dice el datasheet es tensión por fase , como yo utilizo fuentes de alimentación de unos 5v , elijo motores que tengan una tensión por fase cercana a 2.5v o algo superior.


* Intensidad maxima de las bobinas. Es otro factor a tener en cuenta, ya que el driver tiene que estar preparado para aguantar esta intensidad. 


* Pasos del motor (por ejemplo 200). Este número representa el número de impulsos que hay que inyectarle para que de una vuelta entera. Con esto tenemos una resolución de 360º/200 impulsos que es lo mismo que 1.8 º/impulso.

Hoy voy a comentar el tema micropasos que es una manera de ganar resolución de giro del motor pero en su contra perdemos fuerza en el mismo, como siempre, hay que buscar el equilibrio y las necesidades.

Un motor paso a paso estandard se descompone en 4 movimientos tal y como vimos en los anteriores posts.

1010        HIGH   LOW    HIGH   LOW
0110        LOW    HIGH   HIGH   LOW
0101        LOW    HIGH   LOW    HIGH
1001        HIGH   LOW    LOW    HIGH

Esta rutina se repite hasta 50 veces en un motor de 200 pasos hasta completar toda la vuelta.


Como que se trata de salidas digitales que gestionamos por defecto en nuestro Arduino a través de la libreria Stepper, si modificamos esta podremos cambiar el comportamiento de nuestro motor.




Por ejemplo podemos crear los medios pasos siguiendo la siguiente lógica:




Si utilizamos salidas digitales podremos obtener el siguiente trazo (tendremos unos cambios de torque muy bestias (+41%) cuando utilizemos las dos bobinas a la vez :



Mientras que si nos tiramos por las salidas analógicas podemos obtener una esfera en su posicionamiento obteniendo un torque más regular:




Cambiando la libreria lograriamos convertir nuestro motor en 400 pasos y una resolución de 0.9º. Para ello tendremos que editar el archivo Stepper.cpp en la linea dónde dice

stepMotor(this->step_number % 4);  hay que sustituirlo por  stepMotor(this->step_number % 8); dónde este 8 significa el numero de "movimientos" posibles. Finalmente también hay que modificar la parte final de la libreria, en este caso debería cambiar en el caso de utilizar salidas digitales :

      
      case 0:    // 1000
      digitalWrite(motor_pin_1, HIGH);  
      digitalWrite(motor_pin_2, LOW);
      digitalWrite(motor_pin_3, LOW);
      digitalWrite(motor_pin_4, LOW);
      break;
      case 1:    // 1010
      digitalWrite(motor_pin_1, HIGH);  
      digitalWrite(motor_pin_2, LOW);
      digitalWrite(motor_pin_3, HIGH);
      digitalWrite(motor_pin_4, LOW);
      break;
      case 2:    // 0010
      digitalWrite(motor_pin_1, LOW);  
      digitalWrite(motor_pin_2, LOW);
      digitalWrite(motor_pin_3, HIGH);
      digitalWrite(motor_pin_4, LOW);     
      break;
      case 3:    // 0110
      digitalWrite(motor_pin_1, LOW);  
      digitalWrite(motor_pin_2, HIGH);
      digitalWrite(motor_pin_3, HIGH);
      digitalWrite(motor_pin_4, LOW);
      break;
      case 4:    //0100
      digitalWrite(motor_pin_1, LOW);  
      digitalWrite(motor_pin_2, HIGH);
      digitalWrite(motor_pin_3, LOW);
      digitalWrite(motor_pin_4, LOW);
      break;
      case 5:    //0101
      digitalWrite(motor_pin_1, LOW);  
      digitalWrite(motor_pin_2, HIGH);
      digitalWrite(motor_pin_3, LOW);
      digitalWrite(motor_pin_4, HIGH);
      break;
      case 6:    //0001
      digitalWrite(motor_pin_1, LOW);  
      digitalWrite(motor_pin_2, LOW);
      digitalWrite(motor_pin_3, LOW);
      digitalWrite(motor_pin_4, HIGH);
      break;
      case 7:    //1001
      digitalWrite(motor_pin_1, HIGH);  
      digitalWrite(motor_pin_2, LOW);
      digitalWrite(motor_pin_3, LOW);
      digitalWrite(motor_pin_4, HIGH);
      break;


En caso de querlo hacer con salidas analogicas , se deberia usar siguiendo instrucciones del siguiente tipo:



case 0:    // 
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 255);
      analogWrite(motor_pin_4, 0);
      break;
      case 1:    //    
      analogWrite(motor_pin_1, 180);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 180);
      analogWrite(motor_pin_4, 0);     
      break;    

Y en nuestro programa de Arduino también deberemos modificar la linea dónde le definimos el número de pasos de nuestro motor (por ejemplo#define motorSteps 800 )



Y a partir de aqui tenemos otra opción que es generar los micropasos, es decir 1/4 , 1/8, 1/16 , 1/32 de paso, para ello hay que modificar la libreria también. Llegados a este punto de resolución deberemos usar salidas analogicas en vez de digitales, para ello lo haremos con las marcadas como PWM (en realidad no dan una salida constante pero si una tensión media). Recomendable una lectura sobre como funcionan las señales PWM

De momento tendremos de sustituir las expresiones digitalWrite por analogWrite y en vez de dar un valor alto o bajo (HIGH o LOW) pasará a ser un valor entre 0 y 254 que es el rango en que trabaja nuestro pequeño arduino.

Para ello podriamos utilizar las siguientes tablas:

Estas tablas basicamente resultan de dividir en fracciones la columna grados por 4 veces la inversa  del numero de micropasos (en este caso 4 x inversa de 1/4 = 16 movimientos electricos). Entonces dividimos los 360º de una vuelta en 16 y nos da la columna GRADOS. A continuación aplicamos el Sinus y el Cosinus (columnas SIN y COS), este par de valores oscilan entre -1 y 1 y como que nosotros trabajamos con salidas analógicas que van de 0 a 255 lo único que hacemos es multiplicar el valor por 255. Finalmente nos vamos a las 4 columnas de sálidas PWM. En las dos primeras va el valor del sinus. Si es un valor positivo va a la primera columna, mientras que si es negativo lo pondremos en la segunda columna pero siempre en valor absoluto (sígno siempre positivo , nunca negativo - Como el Van Gal!-). Las columnas tercera y cuarta es lo mismo pero con los valores de Cosinus.

He aquí las tablas para 1/4 de paso (800 impulsos/vuelta y resolución de 0.45º).





1/8 de paso (1600 impulsos/vuelta y resolución de 0.225º). Esta por ejemplo la tengo yo modificada para trabajar con drivers de 4 entradas. Si alguién la quiere que contacte conmigo.




Os dejo el código enterito de la libreria (no os rayeis! hay que acabarlo de pulir , y también renombrar el archivo .h )

/*
  Based on Stepper.cpp - - Stepper library for Wiring/Arduino - Version 0.4
  
  Original library     (0.1) by Tom Igoe.
  Two-wire modifications   (0.2) by Sebastian Gassner
  Combination version   (0.3) by Tom Igoe and David Mellis
  Bug fix for four-wire   (0.4) by Tom Igoe, bug fix from Noah Shibley  

  Drives a unipolar or bipolar stepper motor using 4 wires

  When wiring multiple stepper motors to a microcontroller,
  you quickly run out of output pins, with each motor requiring 4 connections. 

  A slightly modified circuit around a Darlington transistor array or an L293 H-bridge
  connects to only 2 microcontroler pins, inverts the signals received,
  and delivers the 4 (2 plus 2 inverted ones) output signals required
  for driving a stepper motor.


 */


#include "Arduino.h"
#include "Stepper3.h"

/*
 *   constructor for four-pin version
 *   Sets which wires should control the motor.
 */

Stepper3::Stepper3(int number_of_steps, int motor_pin_1, int motor_pin_2, int motor_pin_3, int motor_pin_4)
{
  this->step_number = 0;      // which step the motor is on
  this->speed = 0;        // the motor speed, in revolutions per minute
  this->direction = 0;      // motor direction
  this->last_step_time = 0;    // time stamp in ms of the last step taken
  this->number_of_steps = number_of_steps;    // total number of steps for this motor
  this->valorPWM = valorPWM;  // NEW ********
  

  // Arduino pins for the motor control connection:
  this->motor_pin_1 = motor_pin_1;
  this->motor_pin_2 = motor_pin_2;
  this->motor_pin_3 = motor_pin_3;
  this->motor_pin_4 = motor_pin_4;

  // setup the pins on the microcontroller:
  pinMode(this->motor_pin_1, OUTPUT);
  pinMode(this->motor_pin_2, OUTPUT);
  pinMode(this->motor_pin_3, OUTPUT);
  pinMode(this->motor_pin_4, OUTPUT);

  // pin_count is used by the stepMotor() method:  
  this->pin_count = 4;  


}

/*
  Sets the speed in revs per minute

*/
void Stepper3::setSpeed(long whatSpeed)
{
  this->step_delay = 60L * 1000L / this->number_of_steps / whatSpeed;
}

/*
  Moves the motor steps_to_move steps.  If the number is negative, 
   the motor moves in the reverse direction.
 */
void Stepper3::step(int steps_to_move)
{  
  int steps_left = abs(steps_to_move);  // how many steps to take
  
  // determine direction based on whether steps_to_mode is + or -:
  if (steps_to_move > 0) {this->direction = 1;}
  if (steps_to_move < 0) {this->direction = 0;}
    
    
  // decrement the number of steps, moving one step each time:
  while(steps_left > 0) {
  // move only if the appropriate delay has passed:
  if (millis() - this->last_step_time >= this->step_delay) {
      // get the timeStamp of when you stepped:
      this->last_step_time = millis();
      // increment or decrement the step number,
      // depending on direction:
      if (this->direction == 1) {
        this->step_number++;
        if (this->step_number == this->number_of_steps) {
          this->step_number = 0;
        }
      } 
      else { 
        if (this->step_number == 0) {
          this->step_number = this->number_of_steps;
        }
        this->step_number--;
      }
      // decrement the steps left:
      steps_left--;
      // step the motor to step number 0, 1, 2, or 3:
      stepMotor(this->step_number % 32);
    }
  }
}

/*
 * Moves the motor forward or backwards.
 */
void Stepper3::stepMotor(int thisStep)
{

  if (this->pin_count == 4) {
    switch (thisStep) {
case 0:    // 
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 255);
      analogWrite(motor_pin_4, 0);
      break;
      case 1:    //        
      analogWrite(motor_pin_1, 50);
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 250);
      analogWrite(motor_pin_4, 0);
      break;
      case 2:    // 
      analogWrite(motor_pin_1, 98);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 236);
      analogWrite(motor_pin_4, 0);
      break;
      case 3:    // 
      analogWrite(motor_pin_1, 142);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 212);
      analogWrite(motor_pin_4, 0);
      break;
      case 4:    // 
      analogWrite(motor_pin_1, 180);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 180);
      analogWrite(motor_pin_4, 0);     
      break;
      case 5:    //
      analogWrite(motor_pin_1, 212);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 142);
      analogWrite(motor_pin_4, 0);
      break;
      case 6:    // 
      analogWrite(motor_pin_1, 236);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 98);
      analogWrite(motor_pin_4, 0);
      break;
      case 7:    //
      analogWrite(motor_pin_1, 250);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 50);
      analogWrite(motor_pin_4, 0);   
      break;
      case 8:    //
      analogWrite(motor_pin_1, 255);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 0);
      break;
      case 9:    //
      analogWrite(motor_pin_1, 250);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 50);
      break;
      case 10:    //
      analogWrite(motor_pin_1, 236);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 98);
      break;
      case 11:    //
      analogWrite(motor_pin_1, 212);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 142);    
      break;
      case 12:    //
      analogWrite(motor_pin_1, 180);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 180);
      break;
      case 13:    //
      analogWrite(motor_pin_1, 142);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 212);
      break;
      case 14:    //
      analogWrite(motor_pin_1, 98);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 236);
      break;
      case 15:    //
      analogWrite(motor_pin_1, 50);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 250);
      break;
      case 16:    // 
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 0);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 255);
      break;
      case 17:    //        
      analogWrite(motor_pin_1, 0);
      analogWrite(motor_pin_2, 50);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 250);
      break;
      case 18:    // 
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 98);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 236);
      break;
      case 19:    // 
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 142);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 212);
      break;
      case 20:    // 
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 180);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 180);     
      break;
      case 21:    //
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 212);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 142);
      break;
      case 22:    // 
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 236);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 98);
      break;
      case 23:    //
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 250);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 50);   
      break;
      case 24:    //
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 255);
      analogWrite(motor_pin_3, 0);
      analogWrite(motor_pin_4, 0);
      break;
      case 25:    //
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 250);
      analogWrite(motor_pin_3, 50);
      analogWrite(motor_pin_4, 0);
      break;
      case 26:    //
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 236);
      analogWrite(motor_pin_3, 98);
      analogWrite(motor_pin_4, 0);
      break;
      case 27:    //
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 212);
      analogWrite(motor_pin_3, 142);
      analogWrite(motor_pin_4, 0);    
      break;
      case 28:    //
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 180);
      analogWrite(motor_pin_3, 180);
      analogWrite(motor_pin_4, 0);
      break;
      case 29:    //
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 142);
      analogWrite(motor_pin_3, 212);
      analogWrite(motor_pin_4, 0);
      break;
      case 30:    //
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 98);
      analogWrite(motor_pin_3, 236);
      analogWrite(motor_pin_4, 0);
      break;
      case 31:    //
      analogWrite(motor_pin_1, 0);  
      analogWrite(motor_pin_2, 50);
      analogWrite(motor_pin_3, 250);
      analogWrite(motor_pin_4, 0);
      break;
    } 
  }
}

/*
  version() returns the version of the library:
*/
int Stepper3::version(void)
{
  return 4;
}




1/16 de paso (3200 impulso/vuelta y resolución de 0.1125º)






Y finalmente 1/32 pasos:


Mi experiencia con motores tipo NEMA-17 es que pierden mucha fuerza (ya de por si son pequeñitos) cuando trabajamos con micropasos, pero puede ser una buena solución en algunos casos.

Para vuestra curiosidad os informo que hay unos drivers "Big Easy Driver" de SparkFun que haciendo unos simples puentes ya podemos seleccionar si queremos trabajar con micropasos y os evitais la currada de modificar la libreria... Eso si, estos drivers no funcionan con las mismas ordenes utilizadas hasta ahora tipo MyStepper Stepper (200); es otro cantar, pero si buscais informacion en san Google la encontrareis.



Con estos tres posts espero que entendais como funciona un motor paso a paso para que lo podais implementar en vuestros inventos fotográficos.



No hay comentarios:

Publicar un comentario