Control PID de Barra y Bola con Arduino

18 Agosto, 2015

Es fácil entender el Control PID estudiando un sistema Barra y Bola y utilizando como Controlador un Arduino. El objetivo es situar la bola en el centro de la barra inclinándola de forma conveniente mediante un lazo cerrado de control.

Vídeo Resumen de 5 minutos:

Sistema Barra y Bola

Es un sistema clásico en la Ingeniería de Control.

  • Mediante un Sensor de distancia, medimos la posición de la bola.
  • Con un Controlador, mediante control PID, calculamos el ángulo en el que deberíamos inclinar la barra para colocar y estabilizar la bola en el centro de la barra.
  • Un Actuador modifica la inclinación de la barra.
Sistema Barra y Bola

Sistema Barra y Bola

Sensado de la posición de la Bola

La realizamos mediante el sensor de distancia mediante luz infrarroja y  detector PSD: SHARP GP2Y0A21.

Sensor SHARP

Sensor SHARP

Tiene un rango de medida de 6 a 80 cm. Funciona con 5V y su salida es una tensión relacionada con la distancia medida mediante esta curva característica:

Curva Sensor SHARP

Curva Sensor SHARP

Si la Bola se acerca más de 6cm al sensor, la medida es errónea. Limitamos el movimiento de la bola en esa distancia.

Freno

Freno

Acondicionamiento de la señal del sensor

Para filtrar (paso bajo) la señal del sensor y tener una señal más precisa y repetitiva, conectaremos un condensador electrolítico de 10μF entre la salida del sensor y tierra.

Efecto del condensador de filtrado

Efecto del condensador de filtrado

Como la tensión máxima que vamos a medir es de 3,1V, configuraremos la referencia de tensión del Arduino a 3,3V mediante la instrucción:

analogReference(EXTERNAL);

y conectaremos el pin AREF con la salida de 3,3V del Arduino:

Conexión de la Referencia Analógica a la salida de 3,3V

Conexión de la Referencia Analógica a la salida de 3,3V

De esta forma, los 1024 puntos que nos proporciona el Conversor Analógico Digital de 10 bit del Arduino tendrán un fondo de escala de 3,3V en lugar de los 5V por defecto. Así, incrementamos la resolución de 5mV/ADC a 3mV/ADC.

Calibración del sensor

Para relacionar la tensión proporcionada por el sensor con la distancia en centímetros, desplazaremos la bola por la barra tomando nota de la lectura en ADC. En el Software desarrollado para el Arduino, se incluye un modo de funcionamiento en el que transmite continuamente las lecturas del sensor por el puerto serie:

    if(0){// Para calibrar sensor de Distancia
      Serial.print(dist);
      Serial.print("mm     ADC: ");    
      Serial.println(measure); 
    }

Con 9 puntos a lo largo de la barra es suficiente. Obtenemos la curva de calibración del sensor.

Calibración del Sensor de distancia

Calibración del Sensor de distancia

que en el Software queda definida como:

int dcal [] = { // Calibracion de ADC a Distancia
  -193, -160, -110, -60, 0, 40, 60, 90, 120};
int ADCcal [] = {
  177, 189, 231, 273, 372, 483, 558, 742, 970};

y para transformar las lecturas ADC del sensor, almacenadas en la variable measure, en la posición en mm de la variable dist, aplicamos el siguiente algoritmo:

   for(int i =0; i<8; i++){ // Aplicamos curva de Calibracion de ADC a mm 
      if (measure >= ADCcal[i] && measure< ADCcal[i+1]){
        dist = map(measure,ADCcal[i],ADCcal[i+1],dcal[i],dcal[i+1]);
      }

La variable dist tiene valores negativos y positivos: -193mm en el extremo izquierdo de la barra, 120mm en el derecho y 0 en el centro. Como nuestro objetivo es dejar la bola en el punto central, esta variable dist equivale al error utilizado en la bibliografía de sistemas de control PID.

Actuador

Inclinaremos la barra con un Servo HEXTRONIK HX5010 de 6,9 kg.cm de par motor y una biela de fibra de vidrio anclada a un extremo de la barra.

Actuador Servo

Actuador Servo

Como dice la Wikipedia, controlamos el giro del servo con pulsos de duración variable:

Control de la posición del servo mediante pulsos

Control de la posición del servo mediante pulsos

En este servo en concreto la posición 0º se obtiene con pulsos de 0,5ms y el giro de 180º con 2,3ms.

La biblioteca estándar (incluida en el IDE de Arduino) servo, incluye la instrucción write(angle), siendo angle un integer entre 0 y 180, que nos permite ajustar la posición del servo. Ésta es la instrucción que se usa habitualmente, pero como nosotros queremos la máxima precisión en el giro del servo, utilizaremos writeMicroseconds en su lugar. Su sintaxis es: servo.writeMicroseconds(μS), siendo μS los microsegundos de duración del pulso. Dispondremos de valores entre 500 (posición arriba) y 2300 (posición abajo), teniendo 1800 puntos distintos en lugar de sólo 180 usando la instrucción más básica: write(angle).

Durante la puesta en marcha y ajuste, calcularemos la posición de reposo (barra horizontal) con la ayuda de un nivel de burbuja.

Nivel de burbuja

Nivel de burbuja

Controlador

Utilizaremos un clon de Arduino con microcontrolador ATMEL ATMEGA328-PU equiparable al Arduino UNO o al antiguo Duemilanove original.

  • Recibe la medida de la posición de la bola en su entrada analógica A0.
  • Emite pulsos para controlar el servo en su salida digital 12.
  • A través de su conexión USB envía distintos juegos de datos para debug o tramas de la forma:
173,173,-5,-5$ //dist,dist,vel,vel$

que son recibidas por un PC ejecutando una aplicación desarrollada en Processing y que nos permitirá disfrutar de gráficas de la posición y la velocidad de la bola en función del tiempo como ésta:

Gráfica de Processing

Gráfica de Processing

  • Como bonus, enciende un led conectado a la salida 13 cuando la bola está situada a menos de 8mm del centro.

Alimentación de 5V

El Arduino recibe los 5V necesarios para su funcionamiento a través de su conexión USB. La potencia de su pin de 5V es insufiente para alimentar el servo, por lo que lo alimentaremos con una fuente de alimentación auxiliar. ¡No olvides conectar la tierra de la fuente de alimentación auxiliar con la tierra GND del Arduino! De lo contrario, las señales de control del servo no tendrán un referencia común y no funcionará.

Esquema del sistema completo

Esquema Control PID de Barra y Bola con Arduino

Esquema Control PID de Barra y Bola con Arduino

Conexiones

Conexiones

Conexiones Arduino - Breadboard

Conexiones Arduino – Breadboard

 

Control PID

Una vez que tenemos implementado el sistema físico, llega el momento de dar al controlador la inteligencia necesaria para mover la barra de forma tal que consigamos nuestro objetivo: Dejar la bola quieta en el centro de la barra.

Software para Arduino: _70_Barra_y_Bola_v5_MicroSegundos

Período de medida y reacción

Las secuencias de medida y reacción (los ciclos de programa) no se harán tan rápido como pueda el microcontrolador, sino cada 50ms (valor almacenado en la variable period). Lo hacemos así porque los sistemas de control PID funcionan mejor si los ciclos de medida y reacción siempre tienen la misma duración.

El microcontrolador, con reloj de 16MHz, tiene velocidad suficiente para hacer el ciclo de programa en menos de 10ms. Pero con ciclos tan rápidos, la medida de la velocidad de la bola pierde precisión porque las diferencias en la posición de la bola entre ciclos son ínfimas y nosotros calculamos la velocidad de la bola como la diferencia en su posición en 2 ciclos consecutivos de programa.

Periodo Muestro 50Periodo Muestro 10

Si alargamos el periodo a 100ms, la medida de la velocidad es más precisa, pero el servo funciona de una forma perceptiblemente intermitente.

Tras las pruebas realizadas, un período de 50ms aporta mediciones aceptables de la velocidad de la bola y un funcionamiento del servo fluido.

Cálculo de la velocidad de la bola

En el Software que implementa el control PID en el Arduino calculamos la velocidad como la diferencia entre la posición actual de la bola (variable dist) y la que tenía en el ciclo anterior (variable lastDist). Vamos a mejorar la precisión de está medida mediante un filtro digital de paso bajo (Promediador) que consiste en obtener la media de la últimas 5 velocidades medidas. Las almacenamos en la matriz v[], y las tratamos con el siguiente algoritmo en cada ciclo de programa:

  for (int i=0; i<nvel-1; i++){ // Movemos todas hacia la izq 
      v[i] =v[i+1];
    }
    v[nvel-1]= (dist - lastDist); // Ponemos un dato nuevo
    vel=0;
    for (int i=0; i<nvel; i++){ // Calculamos la media
      vel = vel+ v[i];
    }
    vel = vel/nvel;

El valor de la velocidad lo utilizaremos para calcular la componente Derivativa del control PID. Además lo enviamos a través del puerto serie / cable USB para que lo reciba el software Processing y nos lo represente gráficamente.

Primera aproximación: El término Proporcional

Si de lo que se trata es de llevar la bola al centro de la barra, parece lógico que debemos inclinar la barra más, cuanto más alejada esté la bola del centro. El giro del servo, que determina la inclinación de la barra, lo determinamos con el valor de la variable pos que adopta valores negativos (hacia arriba):

Servo Arriba

pos < 0 : Servo Arriba

y positivos (hacia abajo) a partir del valor 0 que deja la barra en horizontal:

Servo Abajo

pos > 0 : Servo Abajo

Como tenemos la posición de la bola en la variable dist, “Inclinar más la barra cuanto más lejos esté la bola del centro” se escribe en el software como:

pos=Kp*dist

siendo Kp una constante.

Así ya tenemos implementado el Término Proporcional del control PID.

– ¡No me digas que no es sencillo!

– Sí, claro… y que valor asignamos a Kp.

Para asignar un valor a Kp (como para los posteriores Kdiferencial y Kintegral) comenzaremos por asignarle un valor cualquiera: 1, 100, 235, 0.01 o el que te apetezca y observaremos el comportamiento del sistema.

Estamos buscando el valor más pequeño que sea suficiente para inclinar la barra cuando la bola está cerca del objetivo pero todavía no ha llegado. Valores grandes hacen que la bola alcance demasiada velocidad y ¡luego hay que detenerla en el centro!

Para el sistema construido, un valor adecuado es 2. Sólo con el término proporcional, la bola nunca se estabiliza.

En el siguiente vídeo se muestran los efectos de:

– Kp =1. Demasiado bajo. Con poco efecto en las proximidades del punto 0.
– Kp =100. Demasiado alto. Acelera demasiado la bola.
– Kp =2. Es adecuado para nuestro sistema.

Deteniendo la bola: El término Diferencial

El término Diferencial opera sobre la diferencia de posiciones entre el ciclo actual y el anterior. Es decir, sobre la velocidad de la bola, ya que el tiempo transcurrido entre una medida y la siguiente es siempre el mismo. Ese tiempo es el periodo de medida y reacción y en nuestro sistema son 50ms.

El término diferencial se escribe en el software como:

pos=Kd*vel

En las 3 primeras líneas de programa definimos los valores de las 3 constantes del control PID:

float Kp =0; 
float Kd = 100;
float Ki =0;

Lo que estamos haciendo es inclinar la barra oponiéndonos a la velocidad de la bola. Comenzamos dando un valor cualquiera a Kd.

– ¿puedo darle el valor 10, que es mi número favorito?

– Sí, claro. Adelante.

Hemos puesto Kp=0 para que el término proporcional no participe y Kd=10 como punto de partida. Se observa que es un valor insuficiente porque no reacciona suficiente como para detener la bola.

Subimos a Kd=100: Sobre-reacciona y el sistema es inestable.

El valor correcto está entre 10 y 100. Probamos con 50, 25… observando el comportamiento del sistema bajo control Derivativo. Un valor aceptable es Kd=35.

¡Conseguimos detener la bola con bastante eficacia!

Nuestro objetivo es detener la bola en el punto medio. El control proporcional acerca la bola al centro inclinando la barra más cuanto más lejos esté. El control derivativo inclina la barra más cuanto más rápido se mueva la bola y consigue detenerla. Observemos ahora la acción conjunta de los 2 términos, definiendo la posición del servo como:

    pos=Kp*dist+Kd*vel;

¡Esto ya funciona!

La acción combinada de los término Proporcional y Derivativo es un control PD, suficiente para muchas aplicaciones. Una de sus debilidades es que cuando la bola se ha detenido cerca del punto central ya no reacciona. Como la velocidad es 0, el término diferencial no actúa. Como está cerca del punto central, la inclinación de la barra por el término proporcional es pequeño y puede no ser suficiente como para que la bola se mueva. Es lo que ocurre en esta ocasión:

Esto nunca ocurrirá en posiciones alejadas del centro porque el término proporcional ya tendría suficiente entidad como para que su inclinación haga que la bola se mueva.

– ¿Incrementamos el término Proporcional?

Valores altos de Kp conllevan inestabilidad en el sistema como vimos en el vídeo anterior con Kp=100.

La solución es la letra que nos falta para tener un auténtico control PID: la I de Integral.

Incrementando la precisión: El término Integral

El término Integral considera la posición de la bola (como el término Proporcional) y cuánto tiempo lleva allí. Dicho de una forma más rigurosa: De la misma manera que el término Derivativo actúa sobre la velocidad, que es la derivada de la posición de la bola a lo largo del tiempo, el término Integral actúa sobre el área que queda bajo la curva de la posición a lo largo del tiempo.

Base de los términos

Base de los términos

Ese área depende del intervalo de integración. Si integramos ininterrumpidamente el área bajo la curva, el término integral sólo aporta inestabilidad en el sistema. Sólo vamos a integrar la posición de la bola cuando ésta se encuentre a menos de 4 cm del centro de la barra. Cuando esté a menos de 8 mm del centro, damos por cumplido el objetivo y dejamos de integrar. Si se sale de un intervalo reiniciamos I (I=0). Lo escribimos en el software como:

int Rint = 8;
int Rext = 40;

    if(abs(dist)>Rint && abs(dist)<Rext){
      I=I+dist*Ki;
    } 
    else {
      I=0;
    }
 pos=Kp*dist+Kd*vel+I;

Es decir, que mientras la bola esté a menos de 4 cm y más de 8mm del centro, vamos a coger su distancia al centro, la vamos a multiplicar por Ki y el resultado lo vamos a ir acumulando en I. Cuanto más tiempo pase ahí, más grande se va a hacer I.

Como conclusión, el término integral aporta más precisión pero hay que acotar convenientemente su acción porque de lo contrario conlleva demasiada inestabilidad.

115 thoughts on “Control PID de Barra y Bola con Arduino

  1. obijuan

    Muchísimas gracias por el post y los vídeos!!! Es un trabajo fantástico! Muchas gracias! 🙂

    Responder
  2. Luis

    Me ha encantado el artículo y el proyecto.
    Justo ahora acabo de empezar a estudiar en la universidad Ingenieria de Control y después de ver esto estoy deseando llegar a los PID’s.
    ¡Gracias!

    Responder
  3. Toni Vera

    ¡¡ IMPRESIONANTE !! Me ha encantado tú video, después de muchos años me he vuelto a lanzar a estudiar Ingeniería Electrónica y Automática, y este tipo de cosas me ayudan a saber porque me reenganche a este mundo tan apasionante.

    Te seguiré en tus futuros trabajos.

    Responder
  4. Josemanu

    Enhorabuena por el tutorial, es fantástico.

    Yo se muy bien lo que es escribir tutoriales (por eso los mios son mas cortos) así que aprecio de veras el esfuerzo que has hecho con este, está muy bien documentado.

    Voy a poner un enlace desde mi web a la tuya.

    Animo y sigue adelante escribiendo más tutoriales.

    Un saludo.

    Responder
  5. Martin Arias

    La verdad que buen proyecto y muy interesante la verdad. Sigue así, te ganaste un fan. Saludos!!!

    Responder
  6. Antonio

    Me gusto mucho la explicacion de casa una de las combinaciones de los controladores P,I y D, gracias por el video.

    Tengo una duda, si utilizara un sensor ultrasonico HC-SR04 en vez del sensor optico, afectaria la velocidad del sensado de la distancia, para el control PID?

    Gracias por todo

    Responder
  7. juan pablo morales

    Hola angel! como estas? estoy interesado en realizar el sistema bola-viga que tu realizaste.Te quería preguntar si lo que usaste como bola es una pelota de pig-pong?tiene el suficiente peso como para hacer pivotar la barra? y te quería preguntar si me podes pasar la información de otro sensor de posición infrarrojo alternativo al que tu usaste ya que en mi país (Argentina) no lo consigo.Muchas gracias!!

    Responder
    1. Angel Espeso Autor de la Entrada

      Hola Juan Pablo,
      Sí, utilicé una pelota de ping-pong ordinaria.
      Puedes utilizar cualquier sistema de sensado de posición. El infrarrojo del post lo tienes disponible en:
      http://es.farnell.com/sharp/gp2y0a21yk0f/sensor-distancia-anal-gico/dp/1243869
      Pero puedes utilizar cualquier otro, el de ultrasonidos: HC-SR04 o incluso puedes utilizar 2 hilos resistivos a lo largo de una viga de material aislante y una bola metálica que pise ambos y forme un potenciómetro con resistencia dependiente de la posición de la bola.
      ¡Adelante!

      Responder
  8. juan pablo morales

    hola Angel como estas?soy nuevamente juan pablo morales!ya consegui en sensor sharp!! te queria preguntar de que material es la viga?gracias!

    Responder
      1. Juan Pablo Morales

        Gracias Ángel!!! Ya estoy en proceso haciendo la maqueta!! Cuando la tenga terminada te mandaré un vídeo para que la veas! Un abrazo!

        Responder
  9. michael

    Me parece un proyecto excelente pero la verdad me he confundido un poco en el orden que debe llevar el código del arduino , te agradecería si me lo pudieras mandar a mi correo para verificar si lo he hecho bien . un abrazo y muchas gracias por compartir tus conocimientos

    Responder
      1. Alexis

        Hola angel no me podras mandar ami tambien la programacion por que me confundi

        Responder
  10. Lis

    Buen dia, excelente video y expliciación, pero tengo una duda, en que parte del código dice la distancia que quiere llegar la pelota? por ejemplo, si deseo dejar la pelota en -10?

    Responder
    1. Angel Espeso Autor de la Entrada

      ¡ Buen día !
      Si quieres dejar la pelota en -10, inserta la línea:
      dist = dist + 10;
      como línea número 50 en el código. Las líneas 49-51 quedarían:
      }
      dist = dist + 10;
      // Calculo de la media de la VELOCIDAD

      Saludos afectuosos.

      Responder
  11. Jonatan Murcia

    Muy genial, muy bien explicado, quería hacerte una pregunta, yo quiero hacer algo muy parecido pero que la bola pueda moverse en ambos ejes, XY, seria en una tabla y con dos servos, mi pregunta es que sensor puedo usar? había pensado poner una cámara encima y usar visión artificial y ese seria mi sensor, pero quería saber si se puede de otro modo, que sensor puedo usar? gracias.

    Responder
  12. kevin SR

    Un proyecto excelente lo entendi muy bien lo felicito eres increible es mejor que encontrado pero queria pedirte una ayuda con la programacion del arduino porque estoy un poco confundido en como funciona cada parte de la programacion del arduino no se si me lo podrias enviar al correo y te lo agradesco mucho angel.
    muchas gracias bendiciones y abrazos.

    Responder
  13. Bryan André

    Hola Angel! te felcitio mucho por este tutorial me ha encantado… Quería preguntarte si eso que va conectado al sensor es un capacitor? y si es, de que valor seria? Y tambien si me podria pasar tu codigo que me gustaria basarme en el para mi proyecto de sensores… Te agradesco muchisimo, me gustan mucho tus tutoriales. Saludos!

    Responder
  14. t4h4wk

    Felicidades por el proyecto, me ha encantado. Igual me animo a replicarlo pero haciendo el control desde un PLC. Tengo una duda, las partes que se ven en azul estan hechas con impresora 3D?

    Responder
  15. Rafael

    Hola Angel, excelente proyecto y muy bien explicado, por favor me puedes pasar el diseño de las partes en fibra de vidrio.

    Responder
  16. Armando

    Hola Angel excelente proyecto! Uno de los mejores que he visto por la red! Me gustaría que me pasaras el diseño de las partes 🙂 de ante mano gracias y sigue así!

    Responder
  17. Nathan Cross

    You rock man! Thanks for the script, is very useful for us (currently working in ball and plate with resistive screen). God bless you!

    Responder
      1. Nathan Cross

        gracias! de hecho estoy en este preciso momento con Mauricio Salomón, el muchacho que le hizo unas consultas hace un rato.

        Responder
  18. Mauricio Salomón

    Hola Angel, excelente proyecto te felicito, estoy tratando de implementar el sistema ball and plate, he visto tu código y tengo una duda, creas esta variable int sensorPin=0; //Pin Analogico donde esta conectada la señal del Sensor de distancia la cual es la que da un valor de voltaje analógico dependiendo de la posición de la bola, mi duda es que en donde asignas ese pin como una entrada en tu código? Es que no lo veo asignado en ningún lado solo en una parte que dice measure = analogRead(sensorPin);, supongo que ahí está midiendo el valor de sensorPin pero en donde le asignas sensorPin como entrada? Gracias

    Responder
    1. Angel Espeso Autor de la Entrada

      Hola Mauricio,
      Celebro que te guste el post. Gracias.
      Los pines analógicos son sólo de entrada, por eso no se definen como los digitales. Sólo es eso.
      Saludos afectuosos.

      Responder
      1. Mauricio Salomón

        Entiendo, entonces el cable de mi sensor lo conecto al pin A0(Analog In) del Arduino Uno y listo?

        Responder
          1. Mauricio

            muchas gracias, espero probarlo mañana.

          2. Mauricio

            otra duda jeje, que significan las constantes Rint y Rext y porqué tienen esos valores?

  19. Daniel Osorio

    Buen dia angel!
    tu post a generado revuelo, me fascina que aun hay personas dispuestas a compartir su conocimiento y Me parece un proyecto excelente, la verdad me e confundido con la sintaxis del código en el arduino, si me lo pudieras enviar a mi correo quedaría encantado ya que quizá omití alguna linea, un abrazo enorme y espero sigas realizando proyectos como este.

    Responder
      1. Daniel Osorio

        ¡Recibido, gracias Angel!
        de casualidad las dimensiones de las bielas las tienes, disculpa la molestia y gracias de nuevo. 😀

        Responder
  20. wilfer nieto

    buen dia te felicito excente trabajo, mu gustaria saber donde ingreso el setpoint para posicionar la bola a una distancia deseada.
    Gracias

    Responder
    1. Angel Espeso Autor de la Entrada

      ¡Buen Día Wilfer!
      Si quieres dejar la pelota en el setpoint: 10mm, inserta la línea:
      dist = dist – 10;
      como línea número 50 en el código. Las líneas 49-51 quedarían:
      }
      dist = dist – 10;
      // Calculo de la media de la VELOCIDAD

      Saludos afectuosos.

      Responder
  21. Pingback: PID en Step7: Ejemplo de control de temperatura

  22. Raul M.

    Hola,

    Gran post y excelente trabajo !!!
    Me gustaría saber dónde has comprado el servo HEXTRONIK HX5010 y si cualquier otro de más o menos esas características cuadraría con la pieza de soporte.

    Gracias,
    Raul

    Responder
  23. Miguel Lara

    Hola que tal, de verdad es muy bueno el articulo, tu proyecto en concreto. Estoy haciendo algo parecido y queria o quiero comparar el codigo que tienes con el mio, serias tan amable de mandarmelo a mi correo si eres tan amable? Estoy impresionado de verdad por este proyecto. Espero tu respuesta, gracias.

    Responder
      1. Raul

        hola excelente trabajo, estoy realizando algo similar me gustaría saber si me puedes compartir tu código

        Responder
  24. Joaquin

    Hola, he pasado por tu canal y me ha fascinado la colaboración que has dado, quiero felicitarte por tener el tiempo de hacer estos trabajos y me gustaría que me proporcionaras el código para compararlo con el que he echo ya que he usado un sensor ultrasonico y quiera comparar por que no me ha salido. De antemano muchas gracias y nuevamente Felicidades Angel

    Responder
  25. Armando ibarra

    Oye disculpa que tendria que modifcar si agrego como sensor HC-SR04, soy novato, el sensor tiene 4 pines

    Responder
  26. JESUS RDZ

    hola felicidades por su proyecto esta muy bien explicado pero soy un novato en arduino me podria decir como quedaria su codigo si en lugar de usar el sensor infrarojo uso un sensor ultrasonico SH-SR04 GRASIAS Y MUY BUEN PROYECTO!!

    Responder
    1. Angel Espeso Autor de la Entrada

      Hola Jesús,
      Celebro que te haya gustado el Post.
      La lectura de la distancia con el sensor SH-SR04 la puedes hacer con el código de arduino:
      long distancia;
      long tiempo;
      void setup(){
      Serial.begin(9600);
      pinMode(9, OUTPUT); /*activación del pin 9 como salida: para el pulso ultrasónico*/
      pinMode(8, INPUT); /*activación del pin 8 como entrada: tiempo del rebote del ultrasonido*/
      }
      void loop(){
      digitalWrite(9,LOW); /* Por cuestión de estabilización del sensor*/
      delayMicroseconds(5);
      digitalWrite(9, HIGH); /* envío del pulso ultrasónico*/
      delayMicroseconds(10);
      tiempo=pulseIn(8, HIGH); /* Función para medir la longitud del pulso entrante. Mide el tiempo que transcurrido entre el envío
      del pulso ultrasónico y cuando el sensor recibe el rebote, es decir: desde que el pin 12 empieza a recibir el rebote, HIGH, hasta que
      deja de hacerlo, LOW, la longitud del pulso entrante*/
      distancia= int(0.017*tiempo); /*fórmula para calcular la distancia obteniendo un valor entero*/
      /*Monitorización en centímetros por el monitor serial*/
      Serial.println(“Distancia “);
      Serial.println(distancia);
      Serial.println(” cm”);
      }
      cableándolo según:
      http://elcajondeardu.blogspot.com.es/2014/03/tutorial-sensor-ultrasonidos-hc-sr04.html
      La declaración de variables y el setup… a su sitio en el programa de Barra y Bola.
      La parte del loop tienes que ponerla en lugar de esto que pertenece al mío:
      // Medimos DISTANCIA
      measure = analogRead(sensorPin);
      measure = constrain(measure, ADCcal[0], ADCcal[8]);
      lastDist = dist; // Guardamos el valor anterior de dist para calcular la velocidad
      for(int i =0; i<8; i++){ // Aplicamos curva de Calibracion de ADC a mm
      if (measure >= ADCcal[i] && measure< ADCcal[i+1]){ dist = map(measure,ADCcal[i],ADCcal[i+1],dcal[i],dcal[i+1]); } } Ten en cuenta que, a diferencia de en mi código tu dist = 0 sería pegado al sensor. En mi código, gracias a la calibración, dist = 0 está en el centro de la barra. Puedes añadir: dist = dist - 15; siendo 15 cm la distancia desde el sensor al centro de la barra y ya lo tendrías. Al final siempre funciona, sólo hay que seguir hasta que funcione 😉

      Responder
      1. Lucas

        Anjo, yo no podría hacer este cambio para incluir el SH – SR04 …
        En mi caso , creo que la distacia inicial (limitación del sensor) sería de 40 mm , 290 mm en el centro y 540 mm en el extremo.
        Yo quería saber dónde incluir y qué hay que cambiar .

        Responder
  27. Alexis

    Excelente trabajo angel, me gusto mucho tu trabajo.. gracias por compartirnos tus conocimientos. Yo soy nuevo en la programacion y estoy realizando este mismo trabajo, pero estoy utilizando el sensor ultrasonico sh-sr04 y no me funciono muy bien nose si me equivoque o me falta algo nose sime podrias auxiliar enviandome el codigo, para ver en lo que me equivoque y asi poder ir mejorando. Te lo agradeseria mucho.

    Responder
  28. Lucas Ramos

    ¡Hola, Angel! En primer lugar quiero darle las gracias por el tutorial , que fue hecho de manera muy explicativa .
    Estoy haciendo una ” barra y bola ” proyecto y también a utilizar un SH – RS04 , he visto algunas críticas .
    ¿Cómo voy a hacer para aumentar un potenciómetro lineal a cualquier posición que lo puse , el sistema para la posición de la bola . Como el vídeo a continuación:

    Responder
    1. Angel Espeso Autor de la Entrada

      ¡Hola Lucas!
      Para variar el SetPoint, que seleccionas con el potenciómetro, tienes que insertar como línea 50 en el programa:
      dist = dist – SetPoint;
      Las líneas 49-51 quedarían:
      }
      dist = dist – SetPoint;
      // Calculo de la media de la VELOCIDAD

      Saludos.

      Responder
      1. Lucas

        ¡Gracias por la respuesta! Otra pregunta sería: Si yo quiero poner un servo con un mayor par motor que influyen en algo?
        Si pongo el servomotor en el centro de la barra tendría un problema, cambiar alguna configuración ? ( Algo así como este proyecto a continuación https://www.youtube.com/watch?v=VGTy1MdWkhk )

        Responder
        1. Angel Espeso Autor de la Entrada

          Puedes poner un servo de más par sin ningún problema.
          Poniendo el servo en el centro de la barra, al llevarlo a sus 0º o 180º tendrías la barra en vertical y la bola se saldría del carril. Poniéndolo en un extremo tienes una mayor resolución porque los 0 – 180º del servo son -10 a +10º de la barra, que son suficientes para mover la bola.
          Espero ser de ayuda.
          ¡Saludos Lucas!

          Responder
  29. Lucas Ramos

    Estimado Ángel , he intentado todo aquí en mi horario con el sensor HC – SR04 , pero no funciona .
    Mi barra tiene 540 mm , 40 están limitados por el sensor y el otro de 500 mm se distribuyen . Por lo que el centro es de 290 mm .
    Si no es mucho pedir , que podría hacer que el código para mí ? Como ya he dicho he intentado todo y no fuinciona

    Responder
  30. gerardo

    exelente proyecto, me encantaría hacer este proyecto pero no pude cargar el código al arduino nano, y me preguntaba también si es posible gratificar los datos en matlab

    Responder
    1. Angel Espeso Autor de la Entrada

      Celebro que te guste Gerardo.
      Los datos se envían por el puerto USB. Seguro que MatLab puede leerlos.
      Saludos.

      Responder
      1. Daniel

        Hola he implementado el circuito y todo el montaje, pero no me funciona. el servo hace un ruído extraño y pareciera que está como forzado… el balanceo de la bola lo hace muy brusco y n logro que la bola quede en el centro, puedes ayudarme?

        Responder
        1. Angel Espeso Autor de la Entrada

          Hola Daniel,
          Yo intentaría mover el Servo con el ejemplo Sweep que tienes en el IDE de Arduino (Archivo/Ejemplos/Servo/Sweep). Si no funciona con ese ejemplo sustituiría el Servo.

          Responder
  31. Uriel MG

    Hola me a gustado mucho su proyecto quisiera que me apoyara diciéndome la lista de los componentes que utilizo, y si me puede facilitar el circuito eléctrico que utilizo, de antemano muchas gracias y felicidades por tan buen tutorial me a sido de gran ayuda.

    Saludos y bendiciones

    Responder
    1. Uriel MG

      Disculpa que capacitores ocupaste para el circuito, podrias mostrarme como es el circuito o conexiones que realisaste.

      Responder
  32. Felipe Ortiz

    Hola muy buenas tardes tengo una duda, funciona con cualquier servo ? o cual es la especificacion o por que usar el HEXTRONIK HX5010 y otra pequeña duda es lo mismo usar el sensor SHARP GP2Y0A21YK ?? Espero su respuesta muchas gracias !!! Muy buen Proyecto!

    Responder
      1. Felipe Ortiz

        Una duda más si mi sensor es de 10-80 cm , ¿que es lo que variará en la programación crees que me puedas ayudar ?

        Responder
      2. samanta

        estoy interesada en el proyecto, vi los comentarios debido a que en mi pais no puedo conseguir en servo hextronik hx5010 6.9kg cm entonces vi que puso un link donde se podia conseguir pero el link se dirige a un servo sg5010 R/C es lo mismo? misma conexion y misma programacion???

        Responder
      3. samanta

        SI CAMBIA ALGO DEL SERVO NECESITO SABERLO, PARA QUE NO TENGA PROBLEMAS CON LA PROGRAMACION, LE AGRADECERIA ME INFORMARA, SI PUSO LA LIGA DE ESE SERVO ES PORQUE ES IGUAL NO ES ASI? Y NO DEBERIA CAMBIAR NADA, SI NO QUE SERVO ES EL MAS CERCANO AL HXT5010

        Responder
  33. ANDERSON

    Hola Angel.
    Que buen trabajo Quería preguntar que código en arduiono utilizaste para realizar el proyecto con un HC SRO4, pues estoy trabajando el mismo proyecto que realizaste pero con un ultrasonido el problema es que el sistema se torna muy inestable y el pin pon comienza a balancearse mucho y no encuentra el equilibrio y este es el codigo que tengo hasta el momento.

    #include
    #include

    const int servoPin = 9; //Servo Pin

    float Kp = 2.5; //Initial Proportional Gain 2.5
    float Ki = 0; //Initial Integral Gain
    float Kd = 0.9; //Intitial Derivative Gain
    double Setpoint, Input, Output, ServoOutput;

    PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); //Initialize PID object, which is in the class PID.

    const int pingPin = 7; //Trig Pin Arduino 7
    const int pingPin2 = 6; //Echo Pin Arduino 6

    Servo myServo; //Initialize Servo.

    void setup()
    {
    pinMode(pingPin, OUTPUT);
    pinMode(pingPin2, INPUT);
    Serial.begin(9600); //Begin Serial
    myServo.attach(servoPin); //Attach Servo
    Input = readPosition(); //Calls function readPosition() and sets the balls
    // position as the input to the PID algorithm
    myPID.SetMode(AUTOMATIC); //Set PID object myPID to AUTOMATIC
    myPID.SetOutputLimits(-10, 90); //Set Output limits to -80 and 80 degrees.
    }

    void loop()
    {
    Setpoint = 15; //15
    Input = readPosition();
    myPID.Compute(); //computes Output in range of -80 to 80 degrees
    ServoOutput = 120 + Output; // 102 degrees is my horizontal
    myServo.write(ServoOutput); //Writes value of Output to servo
    }

    float readPosition() {
    long duration, cm;
    unsigned long now = millis();
    digitalWrite(pingPin, LOW);
    delayMicroseconds(5);
    digitalWrite(pingPin, HIGH);
    delayMicroseconds(10);
    duration = pulseIn(pingPin2, HIGH);
    cm = 0.017 * duration;
    if (cm > 30) // 30 cm is the maximum position for the ball // make 35
    {
    cm = 30; // make 30
    }
    Serial.println(cm);
    return cm; //Returns distance value.
    }

    Responder
  34. samanta

    estoy interesada en el proyecto, vi los comentarios debido a que en mi pais no puedo conseguir en servo hextronik hx5010 6.9kg cm entonces vi que puso un link donde se podia conseguir pero el link se dirige a un servo sg5010 R/C es lo mismo? misma conexion y misma programacion???

    Responder
  35. Samanta

    El sensor sharp tal cual lo describen no hay, el que encontré es de 10-80 cm. Que cambia del programa

    Responder
  36. Jose Reyes Gomez

    Hola Ángel.

    felicidades muy buen trabajo;
    Requiero de tu ayuda trabajo con un sensor sharp de 10cm-80cm y una barra de 50cm, servomotor modelo MG995
    y no logro ponerlo en el centro no se en que falle, si me puedes ayudar con el programa gracias, Saludos desde mexico.

    Responder
  37. Enrique

    Hola ángel muchas felicidades por el proyecto , solo una pregunta, como conecto Processing con Arduino para tener las gráficas ?? me dice que hay un error: please fix the size () Line to continue

    Responder
    1. Angel Espeso Autor de la Entrada

      ¡Gracias Enrique!
      En la línea 33 cambia:
      size(xpant, ypant);
      por:
      size(1000, 500);
      En las últimas versiones, Processing no soporta variables en el comando size.
      Saludos

      Responder
  38. Alvaro Rodriguez

    Buenas Angel, gran trabajo.
    Yo estoy haciendo algo parecido pero con un HC-SR04. El caso es que este sensor me da medidas erróneas a partir de unos 15-20cm usando una pelota de pinpon. En cambio, si lo que uso es algo plano que mire directamente al sensor, la medida es correcta. Lo he probado con otro HC-SR04 y ocurre lo mismo. ¿Habría alguna solución para que el sensor me detectara la pelota? Gracias y un saludo.
    PD: Si a alguien le ha ocurrido algo parecido agradecería su ayuda.

    Responder
  39. Alejandro

    Hola se que el post ya tiene algo de tiempo aqui pero si es posible , me gustaria me respondiera como hace corresponder la distancia leida por el sensor para asi utilizar la salida del control PID , en la instruccion de salida para el servo, por que no alcanzo a comprender esa parte , lo digo por las lineas
    pos=Kp*dist+Kd*vel+I;
    myservo.writeMicroseconds(reposo+pos);
    Pero en que parte de la programacion se asegura que la variable pos, corresponda o este dentro del rango de valores que admite la salida al servo? En este caso los microsegundos del pulso que hacen mover al servo. Gracias

    Responder
    1. Angel Espeso Autor de la Entrada

      Hola Alejandro,
      Si reposo+pos se sale de los límites aceptados por el servo, éste se queda en sus posiciones extremas. Saludos.

      Responder
  40. angel

    en que se baso para saber que servomotor es el adecuado y referente al sensor SHARP solo encontre de
    10 a 80 cm esto perjudicaria en la medida de la barra ya que usted maneja una regla de 40cm

    Responder

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *