bclose

Circuito con joystick y servo

Manejando joysticks con Arduino

Objetivos

 

 

    • Presentando un pequeño joystick.
    • Leyendo el joystick.
    • Moviendo el servo mediante el stick.
    • Filtrando las lecturas.

 

Material requerido.

Imagen de Arduino UNO Arduino Uno o similar.

  • Esta sesión acepta cualquier otro modelo de Arduino.

 

Protoboardconexiones Una Protoboard mas  cables.
componenteUn Joystick.
ComponenteUn Servo con sus horns, esas pequeñas piezas de plástico que se ponen en el eje.
tienda online prometec

Que es un joystick

 

Un joystick suele estar formado por dos potenciómetros a 90º que transforman el movimiento en X e Y del mando en una señal eléctrica proporcional a su posición y que además suele incluir un botón.

Así pues, suelen tener 5 pines: X, Y, botón y 6V más GND.

En realidad ya usamos todos estos componentes previamente y la única curiosidad del joystick es que resulta un elemento muy cómodo para posicionar algo, aunque no sea demasiado preciso.

Vamos a montar un circuito con un servo como en la sesión previa y usaremos uno de los ejes del joystick para posicionar un servo, y si pulsamos el botón encendemos un LED. (Ignoraremos el otro eje Y, aunque podríamos usarlo para posicionar un segundo servo).
El pin correspondiente al botón suele venir marcado como SW de Switch.

Aquí tenemos el diagrama eléctrico:

Esquema electricoY para la protoboard:

Protoboard

 

El Programa de control

 

Vamos con el programa (Prog_17_1):

#include <Servo.h>          // Incluir la librería Servo
Servo servo1;               // Crear un objeto tipo Servo llamado servo1
int angulo = 0 ;
int Eje_X = A1 ;
int Eje_Y = A2 ;
int boton = 4  , LED = 12 ;

void setup()
    {
        servo1.attach(6) ;  // Conectar servo1 al pin 6
        pinMode( boton, INPUT_PULLUP) ;
    }

void loop()
    {
        angulo  = map( analogRead(A1), 0, 1024, 0, 180);
        servo1.write(angulo);
        if ( ! digitalRead(boton))
              digitalWrite(LED, HIGH);
        else
              digitalWrite(LED, LOW);
        delay(250) ;
           }
 
  • La parte que corresponde al servo es exactamente lo mismo que en la sesión 16. Por lo demás hemos incluido unas definiciones al principio indicando que hemos conectado el eje X a la entrada analógica A1 y el eje Y a la entrada A2.
  • El pulsador está conectado al pin digital 4 y el LED al 12, de forma que si queremos cambiar de pines, por la razón que sea, bastara con actualizar esta lista al principio del programa.
 

Insistir en que hemos definido la entrada correspondiente al boto del joystick como  INPUT_PULLUP  y no como INPUT, porque de este modo no necesitamos incluir una resistencia, sino que Arduino conecta un pullup internamente

Por eso leeremos LOW al pulsarlo y entre tanto será HIGH, por ese motivo invertimos la condición en el if. Encenderemos el botón solo cuando pulsemos.

El servo sigue la posicion del joystick y cuando soltamos vuelve al centro.

Pero hay algo de epiléptico en el movimiento del servo (y más con uno barato como éste que estoy usando). Recibe muchas interferencias y el movimiento es muy convulso, porque, aún si el servo tuviera una cierta precisión (lo que es una suposición entre optimista y muy optimista) los potenciómetros y los convertidores analógicos a digital siempre tienen un margen de ruido.

Seguro que se nos puede ocurrir una forma de mejorar ese movimiento. Pensadlo, ¿Que podemos hacer para filtrar ese ruido?

No, en serio. Piénsalo primero antes de seguir.

Vale. En el mundo real, las cosas no son nunca blancas o negras, sino más bien en tonos grises (o muy frecuentemente chocolates),  por eso no es buena idea enviar las lecturas directamente al control el servo, o de lo que sea que estamos moviendo.

Hay que filtrar un poco la señal. Sin entrar mucho en este tema (sobre el que hay enciclopedias),vamos a usar una técnica muy básica, pero muy eficaz en muchas ocasiones y que os conviene conocer.

Vamos a leer el potenciómetro para decidir si subimos o bajamos el valor del Angulo. No para calcular Angulo directamente.

Como el potenciómetro nos da valores entre 0 y 10000, cuando está centrado o suelto, leerá sobre 500, poco más o menos (aunque bailará). Así que le vamos a dar un margen de tolerancia. Solo aumentaremos el Angulo, un valor dado, si la lectura del potenciómetro sobrepasa el valor de 600 y lo disminuiremos cuando baje de 400.

De este modo pequeñas oscilaciones alrededor del punto medio, no nos afectarán. Es decir las hemos filtrado. Esto reflejado en el programa, podría ser algo así: Prog_17_2

     #include <Servo.h>              // Incluir la librería Servo
     Servo servo1;                   // Crear un objeto tipo Servo llamado servo1
     int angulo = 90 ;               // Empezamos en el centro
     int salto = 3 ;                 // Controla el salto por movimiento
     int Eje_X = A1 ;
     int Eje_Y = A2 ;

     void setup()
        {
           servo1.attach(6) ;  // Conectar servo1 al pin 6
           pinMode( boton, INPUT_PULLUP) ;
         }

     void loop()
        {
            int p = analogRead(A1);
            if ( p < 400 )                    // Si la lectura es menor de 400
                 angulo = angulo - salto ;    // disminuimos el angulo
            else if (p>600)                   // Si mayor de 600
                 angulo = angulo + salto ;    // Aumentamos el angulo
            servo1.write(angulo);             // Y este es el que mueve el servo
            delay (50);                       // Este delay regula la velocidad del movimiento
         }

Creo que comprobareis que el movimiento es más fluido y uniforme, y que prácticamente elimina las convulsiones del servo. Además usamos este método para dejar clavado al servo en la posición que nos interesa (Aunque soltemos el mando), algo que del otro modo sería imposible.

 

Resumen de la sesión

 

 

    • Hemos visto que un joystick son dos potenciómetros a 90º mas un pulsador, ambos normales y corrientes.
    • Aprovechamos el montaje anterior para mover el servo con el joystick y mapear su valor entre 0 y 180º
    • Hemos introducido el concepto de filtrado de señales, que de por si es una rama específica de la electrónica y la computación, y una, que cada día es mas importante en todos los ámbitos de la tecnología.

 

 

 

 

(82) Comments

  • Hola. Tendrás algun tutorial para mover 2 motores paso a paso con un joystick como el de este ejemplo. Apenas inicio con arduino y se lo básico.

    • Hola Gustavo, no tenemos ninguno. Pero échale un ojo a esta sesión http://www.prometec.net/motor-28byj-48/

      Se trataría de adaptar el programa a los paso a paso (que entenderás como funcionan en esa sesión), y usar un eje del joystick para cada motor. Un saludo.

  • Buenas una pregunta se puede hacer lo mismo con unos motores para controlar un carro de control remoto pero via bluetooth

  • pregunta!!! Si se usa los dos ejes del joystick para un solo servo, posicionandolo segun la orientacion del joystic. cómo seria? gracias

    • Hola Nicolás, no estoy seguro de entenderte. Si vas a controlar un único servo no veo por qué utilizar los dos ejes del joystick. Un saludo.

  • Hola.
    Vi la sesion de las funciones, y tuve una duda:
    Hay funciones predefinidas (que ya vienen), como map(), que se pueden usar como valores (aunque yo le de unos valores para “operar”, al fin y al cabo lo usa como un valor: puede sumarlo, restarlo, etc.).
    Puedo hacer una funcion, por ejemplo “Redondea()” que la pueda usar igual?

    void Redondea(float valor) //Si por ejemplo valor=152,536
    {
    int valor1 = valor; //cuando se pasa de float a int tunea obviando los decimales. valor uno sería 152 y valor 152,536
    if ( (valor – valor1) >= 0.5 ) //Aquí se si la parte decimal es mayor o igual a 0,5
    {
    BuenValor = (valor1 + 1); //Entonces se aproxima subiendo en 1 la parte entera (153) y pbviando los decimales.
    }
    else
    {
    BuenValor = valor1; //sino, se deja la parte entera original y se obvian los decimales (no es el caso)
    }
    }
    Aquí tuve que inventarme tres variables: valor(float), valor1(int) y BuenValor(int). Pero eso consume espacio, así que me interesaria saber si hay maneras de usar esa funcion (modificando el programa, obvio) como un valor.
    Recordar que eso es un “ejemplo”
    Espero que se me entienda y gracias por anticipado por la respuesta.

  • volvi a pegar el mismo codigo con fallo XD

    #include
    Servo servo1;
    Servo servo2;
    int boton = 4 ;
    int angulo1 = 90 ;
    int salto1 = 3 ;

    int angulo2 = 90 ;
    int salto2 = 3 ;

    int Eje_X1 = A1 ;
    int Eje_Y1 = A2 ;

    void setup()
    {
    servo1.attach(5) ;
    servo2.attach(6) ;
    pinMode(boton,INPUT_PULLUP) ;
    }
    void loop()
    {
    int p1 = analogRead(A1);
    if ( p1 600);
    angulo1 = angulo1 + salto1;
    servo1.write(angulo1);
    delay (50);

    int p2 = analogRead(A2);
    if ( p2 600);
    angulo2 = angulo2 + salto2;
    servo2.write(angulo2);
    delay (50);
    }

    • Hola Kevin, tengo preparado subir en cuanto pueda un tutorial para controlar un brazo robot compuesto de 2 servos con un joystick. No me sale correctamente tu programa, pero en principio te faltan los else después de los if para controlar el movimiento del joystick hacia los dos lados.

      De todas formas ya te digo que subiremos el tutorial lo antes posible que seguro te ayudará a solucionar tu problema. Un saludote!

  • hola muchas gracias por la informacion, soy un estudiante de ingenieria electronica y para un proyecto quisiera controlar dos servos, uno que rote con el “eje x” y otro con el “eje y” del joystick. avance hasta aqui en el programa, pero solo mueve un servo en un sentido, si alguien podria apuntar mi error por favor y ayudarme a corregirlo estaria agradecido.

    #include
    Servo servo1;
    Servo servo2;

    int angulo1 = 90 ;
    int salto1 = 10 ;

    int angulo2 = 90 ;
    int salto2 = 10 ;

    int Eje_X1 = A1 ;
    int Eje_Y1 = A2 ;

    void setup()
    {
    servo1.attach(5) ;
    servo2.attach(6) ;
    }
    void loop()
    {
    int p1 = analogRead(A0);
    if ( p1 600);
    angulo1 = angulo1 + salto1;
    servo1.write(angulo1);
    delay (20);

    int p2 = analogRead(A1);
    if ( p2 600);
    angulo2 = angulo2 + salto2;
    servo2.write(angulo2);
    delay (20);
    }

    • Hola Kevin, no sé si es un fallo al pegar tu código, o es que no has puesto los else después del if para que se mueva también en el otro sentido. Un saludo.

    • Hola Kevin, En unos días Ivan va a publicar un tuto sobre este mismo tema que creo que te gustará

      • muchas gracias, por que revisando el foro me di cuenta que fernando tenia el mismo problema pero con 6 servos. me estoy rompiendo la cabeza intentando saber la falla en el codigo de porq no me responden al movimiento del joystick

    • Antonino

    Hola, se podrían controlar un par de motores PAP con un joystick, de modo que giren más rapidamente cuanto más alejado del centro esté el mando y más lentamente cuando esté más próximo el mando al punto central??

    • Hola Antonino, sí se podría hacer. Por ejemplo relacionando el tiempo que dura el delay del final del programa con la posición del joystick, con una relación inversa. Cuanto mayor sea el desplazamiento del joystick respecto al centro, menos tiempo debería durar el delay. Un saludo.

    • Juan morales

    gracias por tus tutoriales….recién comienzo a descubrir arduino y me ayudas mucho…gracias

  • Buen día,

    el código me funciona muy bien con dos servos sin embargo quiero saber si tengo una cáara de unos 1.5Kg qué dimensiones deberían tener el servo, aproximadamente. Por otro lado si tengo un servo cuyo torque es insuficiente, si agrego un sistema de engranes mejorará el torque pero disminuirá proporcionalmente la velocidad de seguimiento. Mi pregunta es: en este caso debo realizar un control realimentado para hacer una respuesta más rápida? Si es así, debo diseñar una etapa de potencia para mover la carga? Tengo un servo de 13Kg-cm pero al parecer este torque es insuficiente.

    Saludos,

    JOse

    • Hola Jose,
      El asunto es sencillo. Con un servo de 13 kg por cm, puedes levantar 13 kg con uneje de 1cm, 0 de 26 kg con un eje de 0,5

      Si esto no es suficiente, puedes cambiar el motor para usar uno de mas par o bien usar un engranaje que multiplique su fuerza a costa de disminuir la velocidad

  • Hola queria saber en el ultimo ejercisio como puedo hacer para sumar mas servos ?… eh intentado y no eh podido gracias

    • Hloa Lue, ¿Cual es exactamente tu pregunta?

  • Hola de nuevo. El código no se ha copiado bien… lo que quería indicar es que en el if, al calcular el angulo, si se incluye la función angulo=min(180, angulo+salto) se impide que angulo tome valores superiores a 180. Y lo mismo en el límite inferior con angulo=max(0, angulo-salto). Simplemente es una pequeña precaución para evitar comportamientos extraños. Un saludo!

  • Hola, una pequeña aportación a esta magnífica sesión. En el último código el valor de la variable angulo pude tomar valores negativos o superiores a 180. En el vídeo se ve como una vez el servo está en un extremo tarda un poco en volver a moverse. Si se muestra la variable por el puerto serie se ve más claro. Propongo una pequeña modificación para mejorar este punto.

    Estoy siguiendo el tutorial y disfrutando de él. Gracias!

    void loop()
    {
    int p = analogRead(pin_joystick_x);
    if (p 600) angle = min(180, angle + salt);

    servo1.write(angle);
    Serial.print(“L’angle es: ” + String(angle));

    if (digitalRead(pin_joystick_boto) == 0)
    {
    digitalWrite(pin_led, HIGH);
    Serial.println(” i el led esta ON”);
    }
    else
    {
    digitalWrite(pin_led, LOW);
    Serial.println(” i el led esta OFF”);
    }

    delay(25);
    }

    • NekoZama

    Hola, y gracias por el programa, funciona perfectamente y es muy sencillo, sólo quería saber, cómo puedo hacer para que en el segundo ejemplo, cuando suelte el joystick, el servo regrese a su posición inicial?

    • Hola! Muy sencillo, simplemente crea una condición y que si el valor del joystick es el que mide cuando está en reposo (con un poco de margen), el servo se posicione el el ángulo inicial que tu elijas. Si por ejemplo en reposo mide 512 sería algo así:
      if (p< =525 && p>=500)servo1.write(90);
      Un saludote.

    • Carlos

    Hola Ivan, lo que pasa es que ya lo intentamos como el codigo del segundo ejemplo, pero sigue sin funcionar. Que ajustes podriamos usar? Saludos y espero tu pronta respuesta.

    • Hola Carlos! Viendo el trocito de código que pones lo que tienes que cambiar es en vez de int angulo3 = map (joy_y, -512, 512, 0, 180); darle un valor inicial, por ejemplo int angulo3 = 90. Después comprobarías igual que en el ejemplo (pero con tu variable joy_y) si lo estás inclinando para un lado u otro y le sumarías o restarías un número de grados, por ejemplo, angulo3 = angulo3 + salto. Y entonces ya sí fijas la posición del servo con miServo3.write (angulo3).

      A ver si te sirve de ayuda!

    • Carlos

    Hola, buena tarde, una duda, estamos usando Arduino Esplora, y su respectivo joystick con los ejes X y Y. Pero queremos que el servo se quede clavado en la posicion que nosotros queramos, y no que se centre al soltar el joystick. Como podriamos hacerlo? Aqui le dejo el codigo

    int joy_y = Esplora.readJoystickY(); //Control del angulo Y
    int angulo3 = map (joy_y, -512, 512, 0, 180);
    miServo3.write (angulo3);
    delay (20);

    • Hola Carlos! Lo que tendrías que hacer es crear una variable “angulo” con la cual das la posición al servo. A esta variable le sumas o le restar el valor que quieras en cada ciclo en función de si el joystick está inclinado para uno u otro lado, y si está en el centro que no haga nada, poniéndole un delay para regular la velocidad de movimiento. El código lo tienes en la segunda parte de esta misma sesión.

      Un saludote.

  • Supongo que ya alguien lo habrá dicho, pero por si no es así lo digo yo:
    En el setup falta definir el modo de trabajo del LED, es decir falta pinMode(LED, OUTPUT);

  • Hola cesar,

    He bloquedado tu post en los comentarios por su extension y porque las respuestas serian a su vez excesivamente extensas,
    No obstante te a nimo a que lo publiques en el foro y alli es mas facil que entre unos yotros revise os tu problema. Vale?

    Un saludo

  • Hola recien estoy empezando con arduino y me ah interesado el proyecto pero quisiera saber hace lo mismo pero solo con 2 servos y un jostyck xy se agradeceria mucho su orientacion

    • Hola Luis, Puedes usar este codigo de muestra para mover un servo mediante el eje x y el otro mediante el eje y. Prueba a escribir tu codigo y si tienes problemas dinos que te ayudaremos con gusto

      • disculpe mi ignorancia recien estoy aprendiendo si quiero omitir el led no lo cuento? con todo y lo que conciernte sus cables y resistencia y omitir estos parametros ” pinMode( boton, INPUT_PULLUP) ;”?

        • Hola Luis. Con permiso de Admin. Puedes ,simplemente, no conectarlo, y dejar las instrucciones correspondientes al botón y al LED como están. Lo que ocurrirá cuando pulses el botón, es que Arduino pondra a 5V el pin 12, pero como no hay nada conectado, no pasará nada.

          Saludos.

          • Imagen de perfil de Luis Nano

            Entonces no importa si borro o no conecto no hay problema y aparte de eso mi idea original era tener 8 servos y 4 jostyck pero veo como dicen el comentario es mucho, se podria de alguna manera tener 6 servos de 3 grupos y q cada grupo sea manejado por un solo jostyck, el jostyck maneja al grupo A y luego con algun mecanismo pasar al grupo B y luego al grupo C o escoger que grupo quiero mover… agradeceria si alguien me pudiera dar ideas

          • Imagen de perfil de Jesús Sánchez

            Puedes conectar todos los servos que quieras. Piensa en un Robot araña la cantidad de servos que tiene. Lo único que hace falta es una o unas Motor shields especiales para eso.
            Lo de un joystick para varios servo, claro que se puede. Podría implementar un pulsador y unos LEDs, uno por cada servo a controlar. Cada vez que acciones el pulsador, se va encendiendo el LED correspondiente a un servo, indicando que es ese el que controlas con el joystick. Podrías empezar con dos servos y ver como te sale el sketch. Ya luego pensamos en la shield que necesitarias para 8 servos. Cuando tengas lo primero controlado, vas pasando a otro nivel.

          • Imagen de perfil de admin

            Prueba para el shield con el servo shiedl que tienes en la tienda. Puedes manejar hasta 16 servos con un unico shield y ademas puees conectarle alimentacion externa, que vas a necesitar para 6 servos

          • Imagen de perfil de Luis Nano

            mi problema cuando pongo los codigo es que me sale error en esta parte pinMode( boton, INPUT_PULLUP) ; y aparte q no eh conectado el led osea omiti el cable negro la resistencia el led y el cable verde y cuando elimine el codigo el servo se movio un poco lentamente y se qdo estancado y no hizo nada =s

          • Imagen de perfil de Jesús Sánchez

            Pásanos el sketch, pero no por aquí, sino en el foro, pues aquí no se ve correctamente, y lo miramos.

          • Imagen de perfil de Luis Nano

            lo acabo de postear gracias

  • Ahora si ,gracias Jesus por despejar las dudas,me interesa el tema por que quiero controlar con dos servos lo ejes x,y para colocar una cam y poder direccionarla .asi q a seguir estudiando del tema .ya que el joystick mio seria de una app por bluetooth (todo esto encima de un robot que ya esta pronto jej,por ahora anda solo y esquiva obstaculos ,le falta el control a distancia).
    Gracias !!! muy bueno todo lo que se aprende aqui

  • Hola Jesús.acabo de abrir un hilo en el foro de proyectos .a ver como lo sacamos adelante

Give a Reply

WordPress Anti-Spam by WP-SpamShield