lunes, 10 de julio de 2017

Encoder, Arduino y una pinza robótica. Tutorial de Arduino, control de una pinza robótica por medio de un encoder.

En este tutorial enseñamos a usar el encoder que controlar la apertura y el cierre  de la pinza robótica Andromina V.2.0.. Conectando la pinza robótica directamente a un Arduino UNO podemos controlar en tiempo real la carrera de apertura y cierre de la pinza. La pinza también tiene un interruptor de final de carrera, del cierre de la pinza. En el funcionamiento del encoder hemos analizado su señal y mostramos las interferencias "rebotes" que tiene la señal, pulsos del encoder. La cual puede dar una lectura errónea. En este tutorial se da dos soluciones a este problema. Una solución por "Software" y una por "Hardware".
Garra robótica
Pinza robótica Andromina V.2.0. con 6 dedos y dos grados de libertad.
Al final de este "Post" hay varios programas "sketch" para controlar la pinza con un Arduino UNO.
1-Descripción de la pinza robótica Andromina V.2.0:
Mini interruptor mecánico de final de carrera de la pinza.



Esquema del mini interruptor mecánico de final de carrera.
Vista del servo motor de la pinza.
Vista del interruptor final de carrera de la pinza.
2-Esquema eléctrico básico para el control de la pinza con Arduino UNO: En el siguiente esquema eléctrico  se muestra como se puede conectar la pinza a una placa Arduino UNO. La pinza se puede conectar directamente a Arduino UNO, tal y como se muestra en a continuación. No se necesita pilas, podemos conectar la placa Arduino al ordenado. A un puerto USB que suministre +5 voltios y GND. Se tiene que verificar qué el puerto USB suministra alimentación ya que hay puertos en PC y portátiles que no suministran alimentación +5V. Para que el voltaje en placa se mantenga más estable, se tiene que colocar un condensador electrolítico grande de 6,3 Voltios, entre los pines  +5V y GND. De esta manera al accionar el servomotor, el cual pide un consumo elevado del orden de unos 300 mili Amperios, el voltaje de la placa baja por debajo de los +5 voltios. Lo que puede provocar un bajo voltaje en el chip de Arduino y Arduino no puede funciona a bajo voltaje y deja de funcionar momentáneamente y se reinicia. Provocando un fallo.
Esquema eléctrico básico de conexión de la pinza robótica Andromina V.2.0.
3-El "sketch" más básico de Arduino para el control  de la pinza: Este "sketch" solo controlar la apertura y el cierra de la pinza robótica Andromina V.2.0. Esto se hace con el servomotor de rotación continua SM-S4306R que tiene la pinza. El servo motor tiene un encoder mecánico y la pinza un interruptor final de carrera, pero en este "Sketch" no los usamos. El programa deja la pinza 2 segundos parada, luego va abriendo la pinza durante 2 segundos, luego deja la pinza abierta durante 2 segundos y finalmente la va cerrando durante 2 segundos. Va haciendo este ciclo continuamente.

 *//// Parameters // Variables ////////////////////////////////////////////////////////////////////////////////////////////////
#include <Servo.h>
int pin = 3;              // El servo motor esta conectado en este pin.
Servo servo_pinza; // Declaración del servo motor
////  Configuración del Arduino / Arduino configuration /////////////////////////////////////////////////////////
void setup() {
  Serial.begin(9600);
  servo_pinza.attach(pin);
}
////  Main programe // Programa principal //////////////////////////////////////////////////////////////////////////////
void loop() {
  gripper(90,2000);   // Pinza parada, durante 2 segundos
  gripper(180,2000);  // Abre pinzas, durante 2 segundos
  gripper(90,2000);   // Pinza parada, durante 2 segundos
  gripper(0,2000);    // Cierra pinza, durante 2 segundos
}
//// The end of Main programe / Fin del programa principal////////////////////////////////////////////////////

//// Function // Función que abre y cierra la pinza /////////////////////////////////////////////////////////////////
void gripper(int angle,int servo_time){
  servo_pinza.write(angle);  // Giro 
  Serial.print("Pinza ");
   if (angle == 90 )Serial.println("parada"); 
   if (angle > 90 )Serial.println("abre");
   if (angle < 90 )Serial.println("cierra");
  delay(servo_time);}
//// The end of Function // Fin de la función que abre y cierra la pinza //////////////////////////////////////

Con este programa podremos comprobar y calibrar si el encoder de la pinza funciona correctamente. Podremos poner un multímetro digital en los pines del encoder, con la función para medir continuidad con un pitio. El pitido tiene que ser intermitente al ir abriendo y cerrando la pinza. si variamos los dos valores 0º y 180º por unos más próximos a 90º la velocidad de cierre y apertura será más lenta y podremos contar los pitidos. Por ejemplo podemos colocar estos dos valores;
gripper(110,3000);  // Abre pinzas
gripper(70,3000);    // Cierra pinza

4-Rebotes: Al querer controlar esta pinza con una placa Arduino nos dimos cuenta de que tanto el encoder mecánico como el micro interruptor producen rebotes eléctricos  "interferencia" en los pulsos que nos envían. Esto provoca que las dos señales recibidas sean erróneas y que la placa lea más pulsos de los que realmente tiene que enviar el encoder. Para solucionar este problema hay dos soluciones. Eliminar los rebotes por software o por hardware.
En las dos fotografías siguientes se muestra  un pulso de la señal que recibimos del encoder mecánico o del interruptor de la pinza robótica. En la pantalla del osciloscopio se aprecia la rampa de subida de la señal y vemos que hay varios rebotes en esta señal.
Vista de los rebotes que hay en la rampa de subida de la señal del encoder.
En la foto siguiente se aprecia los rebotes de la rampa de bajada de la señal del encoder.
Vista de los rebotes que hay en la rampa de bajada de la señal del encoder

5-Una solución de los rebotes por "Software": Este "sketch"  de Arduino UNO de la pinza robótica con un interruptor y un encoder, no tiene en cuenta los rebotes "interferencias" que aparecen en el encoder y en en el interruptor de final de carrera. El "sketch" indica si el interruptor final de carrera esta pulsado o no. La pinza cierra y cuando el interruptor final de carrera es accionado la pinza se vuelve a abrir. Luego se para y vuelve a cerra. Va haciendo este ciclo continuamente. Por el puerto serie del Arduino va apareciendo los pulsos del encoder.
Link sobre sopresión de rebotes "debounce" con Arduino.

*//// Libraries // Librerias //////////////////////////////////////////////////////////////////////////////////////////////////
#include <Servo.h>
//// Parameters // Declaración de las variables ////////////////////////////////////////////////////////////////////////
//// Variables de la pinza robótica servo de abrir y cerrar la pinza /////////////////////////////////////////////
int pin = 5;                // El servo motor de abrir y cerrar la pinza esta conectado en el pin 5.
Servo servo_pinza;   // Declaración del servo motor
long time_Open = 0;// Variable de tiempo que almacena la ultima vez que se le ordeno abrir a la pinza
boolean Open = false;   // Variable que indica si la pinza se esta abriendo.
//// Variables de eliminación de los rebotes en el interruptor y en el encoder mecánico /////////////////////
const int timeThreshold = 100;   // Variable de tiemplo máximo que duran los rebotes.
volatile int ISRCounter_1 = 0;   //
int counter_1 = 0;     // Variable que cuenta las veces que el intrruptor es pulsado y dejado de pulsar
long timeCounter_1 = 0; // Variable que almacena el tiempo en que se leyó el último pulsado correctamente
volatile int ISRCounter_2 = 0;   //
int counter_2 = 0;       // Variable que cuenta las veces que el encoder es pulsado y dejado de pulsar
long timeCounter_2 = 0;// Variable que almacena el tiempo en que se leyo el último pulso del encoder correctamente
boolean Led = true;              // Variable que enciende el LED 13 o lo apaga.
boolean Interruptor_pulsado = false; // Variable que nos indica si el interruptor esta pulsado o no.
boolean Encoder_pulsado = false;    // Variable que nos indica si el encoder esta pulsado o no.
//////// Arduino configuration // Configuración del Arduino //////////////////////////////////////////////////////////
void setup(){
 servo_pinza.attach(pin);
 Serial.begin(9600);
 pinMode(LED_BUILTIN, OUTPUT); // configura el pin 13 donde hay el led conectado
 pinMode(2, INPUT);     // Configura el pin 2 donde hay la interrupción y el interruptor final de carrera conectado.
 attachInterrupt(digitalPinToInterrupt(2), debounceCount_1, CHANGE); // Configura la interrupción 0
 pinMode(3, INPUT);     // Configura el pin 3 donde hay la interrupción y el encoder conectado.
 attachInterrupt(digitalPinToInterrupt(3), debounceCount_2, CHANGE); // Configura la interrupción 1
 gripper(0);} // Cierra pinza
////  Main programe // Programa principal //////////////////////////////////////////////////////////////////////////
void loop(){
 if (counter_1 != ISRCounter_1){
    counter_1 = ISRCounter_1;
    digitalWrite(LED_BUILTIN,Led);   // turn the LED on (HIGH is the voltage level)
    Serial.print(counter_1);
    if(Interruptor_pulsado){
      Serial.print(" Interruptor pulsado -> ");
      gripper(180);      // Abre la pinza
      time_Open = millis();
      Open=true; 
     }     
    if(!Interruptor_pulsado)Serial.println(" Interruptor no pulsado");
    }
 if (counter_2 != ISRCounter_2){
    counter_2 = ISRCounter_2;
    Serial.print(counter_2); 
    if(Encoder_pulsado) Serial.println(" encoder pulsado");
    if(!Encoder_pulsado) Serial.println(" encoder no pulsado");
    }
 if(millis() > time_Open + 6000 && Open){
    Serial.print("Tiempo "); Serial.print(millis()/1000); Serial.print(" segundos -> ");
    gripper(0); // Cierra pinza
    Open=false;
    }
 }
//// The end of Main programe // Fin del programa principal ///////////////////////////////////////////////////////
/////////////////////////// Function_1 // Función 1 que indica si el interruptor esta pulsado o no /////////////
 void debounceCount_1(){
  if(  digitalRead (2) && (millis() > timeCounter_1 + timeThreshold) && digitalRead (2) ) { // Comprueba que el interruptor esta pulsado. Vuelve a comprobar que el interruptor envia una señal buena y luego comprueba que el tiempo es superior a 150 microsegundos y vuelve a comprobar que la señal es correcta.
        ISRCounter_1++;
        Led = !Led;
        Interruptor_pulsado = true;
        timeCounter_1 = millis();}// Almacena el tiempo para comprobar que no contamos el rebote que hay en la señal.
   if(  !digitalRead (2) && (millis() > timeCounter_1 + timeThreshold) && !digitalRead (2) ) { //  Comprueba que el interruptor esta no pulsado. Vuelve a comprobar que el encoder envia una señal buena y luego comprueba que el tiempo es superior a 150 microsegundos y vuelve a comprobar que la señal es correcta.
        ISRCounter_1++;
        Led = !Led;
        Interruptor_pulsado = false;
        timeCounter_1 = millis();} // Almacena el tiempo para comprobar que no contamos el rebote que hay en la señal.
}
/////////////////////////// Function_2 // Función 2 que cuenta el encoder /////////////////////////////////////////
void debounceCount_2(){
   if(  digitalRead (3) && (millis() > timeCounter_2 + timeThreshold) && digitalRead (3) ) { // Comprueba que el interruptor esta pulsado. Vuelve a comprobar que el interruptor envia una señal buena y luego comprueba que el tiempo es superior a 150 microsegundos y vuelve a comprobar que la señal es correcta.
        ISRCounter_2++;
        Encoder_pulsado = true;
        timeCounter_2 = millis();}// Almacena el tiempo para comprobar que no contamos el rebote que hay en la señal.
   if(  !digitalRead (3) && (millis() > timeCounter_2 + timeThreshold) && !digitalRead (3) ) { //  Comprueba que el interruptor esta no pulsado. Vuelve a comprobar que el encoder envia una señal buena y luego comprueba que el tiempo es superior a 150 microsegundos y vuelve a comprobar que la señal es correcta.
        ISRCounter_2++;
        Encoder_pulsado = false;
        timeCounter_2 = millis();} // Almacena el tiempo para comprobar que no contamos el rebote que hay en la señal.
 }
/////////////////////////// Function 3 // Función 3 que abre y cierra la pinza /////////////////////////////////////////////
void gripper(int angle){
  servo_pinza.write(angle);  // Giro 
  Serial.print(" Pinza ");
  if (angle == 90 )Serial.println("parada"); 
  if (angle > 90 )Serial.println("abre");
  if (angle < 90 )Serial.println("cierra");
  }
6-Solución de los rebotes por "Hardware": Esta solución consiste en colocar un condensador cerámico en cada interruptor. Estos condensadores eliminan totalmente los rebotes y las interferencias que se originan en el pulso del encoder mecánico.
Continuará.....

7-Esquema eléctrico con condensadores para el control de la pinza con Arduino UNO: En el esquema eléctrico siguiente se muestra como se puede conectar la pinza a una placa Arduino UNO. 
Esquema eléctrico de la pinza robótica Andromina V.2.0. con dos condensadores.
8-Calibración de la posición del encoder: Continuará.....

1 comentario :

  1. Indistintamente del sector, esta claro que el uso de tecnologías como la impresión 3D esta significando un paso agigantado en España en vías del futuro. He leído sobre la Lion 2 en http://www.leon-3d.es y tiene mucho que ofrecer a distintas áreas profesionales.

    ResponderEliminar

Google analytics