martes, 14 de septiembre de 2021

Midiendo distancias con un sensor HC-SR04

 Un complemento imprescindible para muchos de robots o vehículos controlados a distancia es un sensor que nos permita saber la distancia libre de obstáculos para movernos. Si las distancias van a ser pequeñas podemos emplear sensores de infrarrojos, pero si queremos movernos en áreas grandes y poder medir distancias en un rango de varios metros el complemento perfecto es un sensor de ultrasonidos. ¿Y porque hacer una entrada sobre un sensor sobre el que se han escrito miles de entradas? Pues por que la inmensa mayoría de entradas y revisiones sobre este sensor no se complican la vida y recurren a una librería para sacar el dato de la distancia. A ver, el uso de librerías está bien, es casi obligatorio para todo hardware minimamente complejo, pero este no es el caso ¿para que utilizar una librería cuando tan sólo hace falte un poco de ingenio y una sencilla operación matemática? Además repasaremos un concepto muy simple de física aplicada que no nos vendrá mal como argumento de que estudiar sirve para muchas cosas (además de no ser un ignorante).

Funciona exactamente igual que un radar, de hecho es un pequeño radar. Emite un pulso de sonido a una frecuencia tan alta que es imperceptible para el oído humano y cronometra el tiempo que el sonido tarda en llegar a un obstáculo, rebotar y volver al sensor. Así que tenemos 2 datos: la velocidad del sonido (343.2 m/s) y el tiempo, atención que ahora viene lo chulo, tal como aprendimos en el instituto en el nivel más básico de Física, que es la cinemática (ahora veréis como si que sirve de algo el haber estudiado) echamos mano de una conocidísima formula (e = v * t) y calculamos la distancia recorrida por el sonido. Parece fácil ¿verdad?... por que lo es y no hace falta recurrir a una librería para hacer una simple multiplicación.

Utilizaremos un sensor de ultrasonidos HC-SR04, conocidísimo, cuyo rango de medida va desde los 3cm a los 3m, suficiente para cualquier proyecto de robótica y que sólo necesita de 2 pines para  hacerlo funcionar:

El sensor de ultrasonidos sólo tiene 4 pines, uno de alimentación, uno de masa, uno de disparo (Triger) y, el último, el pin Echo por el cual nos dará la lectura del tiempo.  

A través del pin Triger enviaremos una señal de activación al sensor y para ello lo activaremos durante 10 microsegundos, es decir, le enviaremos un pulso muy corto, no necesita más. Luego transladaremos nuestra atención en el pin Echo, por este pin el sensor nos dará el tiempo que el sonido a tardado en ir, rebotar  y volver al sensor. Esto lo haremos cada vez que necesitemos tomar una media, que en el código de ejemplo será cada segundo.

La señal de salida del sensor será un pulso de la misma duración que el tiempo cronometrado, es decir, si el sonido tardó 10 microsegundos en ir del sensor al objeto y volver al sensor nos devolverá un pulso de una duración de 10 microsegundos. Así que será fácilmente medible mediante la función pulseIn(). También hay que tener en cuenta que ese tiempo es de ida y vuelta, por lo que tenemos que dividirlo por la mitad a la hora de hacer el cálculo.

Así que sin más preámbulos vamos a programar:

long tiempo;

int disparador = 7;   // triger

int entrada = 8;      // echo

float distancia;


void setup(){

  pinMode(disparador, OUTPUT);

  pinMode(entrada, INPUT);

  Serial.begin(9600);

}

            

void loop(){

  // lanzamos un pequeño pulso para activar el sensor

  digitalWrite(disparador, HIGH);

  delayMicroseconds(10);

  digitalWrite(disparador, LOW);

  

  // medimos el pulso de respuesta

  tiempo = (pulseIn(entrada, HIGH)/2); // dividido por 2 por que es el 

                                       // tiempo que el sonido tarda

                                       // en ir y en volver

  // ahora calcularemos la distancia en cm

  // sabiendo que el espacio es igual a la velocidad por el tiempo

  // y que la velocidad del sonido es de 343m/s y que el tiempo lo 

  // tenemos en millonesimas de segundo

  distancia = float(tiempo * 0.0343);

  // y lo mostramos por el puerto serie una vez por segundo

  Serial.println(distancia);

  delay(1000);

}

Así de fácil es este ejemplo. Dentro de un proyecto sería aun mas sencillo pues no necesitaríamos sacar los datos por el puerto serie (al menos no los dos) y podríamos meter todo el procedimiento dentro de una función de modo que con tan solo llamarla nos diera la distancia. De hecho yo he modificado el código para mostrar el dato de distancia en el Micro-micro y me ha quedado tal que así:


Dentro del código hay que prestar atención a los distintos tipos de datos ya que trabajamos con un unsigned long y con un float y además tenemos que hacer operaciones entre ellos, lo cual puede ser delicado.

Terminaré comentando que haciendo las pruebas con el sensor y el código del ejemplo me sorprendió lo precisas que resultan las mediciones siempre que la superficie y el sensor estuviesen bien perpendiculares, si no el rebote del sonido o los ecos parásitos podían generar medidas erróneas.

Y nada más que añadir….. bueno si, quiero hacer hincapié en que las librerías están bien para muchos casos pero en otros como este es mejor, en mi opinión, utilizar los conocimientos que hemos adquirido en otras disciplinas, como física.





sábado, 4 de septiembre de 2021

Pantalla LCD grafica de 84x48 pixeles.

 Hemos vuelto!!! Despues de años sin publicar nada retomo este blog donde ire compartiendo cosas chulas sobre arduino, processing, raspberry pi, etc.


Uno de los LCDs gráficos más populares por sus prestaciones y bajo precio, tiene una resolución de 84x48 píxeles que dan para representar gráficos y hasta 5 filas de caracteres alfanuméricos, tiene iluminación por leds y comunicación por SPI. Es la misma pantalla que montaban modelos de Nokia como el 5110 y el 3310.




Cuando pensamos en una pantalla LCD para nuestro proyecto siempre nos fijamos primero en las pantallas LCD a color y con bastante resolución, pero estas requerir un montón de pines para su control. Otra opción son las pantallas LCD controladas por serie o I2C (me viene a la cabeza las pantallas Nextion con conexión Serial), pero en estas el precio aumenta sensiblemente. La opción mas barata y más sencilla de utilizar es esta pantalla gráfica LCD que se controla con 4 pines.

Esta mini-board incluye un controlador PCD8544 que es el que se encarga de toda la gestión de los 84x48 píxeles de la pantalla. La comunicación con el controlador se hace por SPI, así que los más valientes pueden buscar el datasheet del PCD8544 y comunicarse con el directamente, el resto de seres humanos recurriremos a las librerías que en su día desarrollaron en Adafruit para controlar esta pantalla.

Lo primero que hay que tener en cuenta para conectar la pantalla a nuestro Arduino es que esta pantalla trabaja 3.3v aunque es tolerante a 5v que es nuestro voltaje de trabajo con la mayoría de placas.

Conexiones del LCD

Vamos con las conexiones:

El pin VCC es el de alimentación, lo conectaremos al pin de 3.3v de Arduino.

GND de la pantalla al GND de Arduino.

SCE ó CS (Chip Select), también conocido como SS (Slave Select) en comunicación SPI, debe activarse para indicarle al dispositivo que se le van a enviar datos.

RST (reset), no es necesario, podemos conectarlo al pin de reset de nuestro Arduino y nos ahorramos un pin.

D/C (Data / Command select).

DN (MOSI) o DIN es la entrada de datos de la pantalla (MOSI = Master Out Slave IN).

SCLK, pin por el que Arduino manda la señal de reloj que rige la comunicación.

LED, el pin de Backlight, lo que viene a ser la iluminación de la pantalla, a la que no le podemos meter 5v para no dañar los ledes, pero vamos a ser muy pillos y este pin lo vamos a conectar a un pin con salida analógica de nuestro arduino y le mandaremos un voltaje analógico de entre 0 y 168 (3,3v), yo lo suelo dejar a 120, así se ve bien.

Para este ejemplo estoy utilizando mi montaje Micro-micro, como se puede ver en las fotos. Ya podemos pasar al IDE de Arduino, primero nos bajamos la librería PCD8544  y la  Librería GFX, ambas de Adafruit (lo podemos hacer desde el gestor de librerias). Abrimos el Arduino IDE y en Ejemplos  ya nos aparece PCD8544LCD y dentro el sketch pcdtest.

En la línea 27 del Sketch aparecen las asignaciones de pines de Arduino a la comunicación SPI con la pantalla, tal cual están no funcionará por que yo he utilizado un orden diferente. Entonces en la línea que aparece:


Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);


La he cambiado para que quede así (comentario / chuleta incluida):
// Adafruit_PCD8544(SCLK, DIN, D/C, CS, RST);
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);

Y ya podemos subir el código de ejemplo y ver como en nuestra pantalla se despliega toda una demostración de sus capacidades gráficas y alfanuméricas.

Estudiando el código de ejemplo a fondo encontramos todos los métodos a emplear con la pantalla, que son:

begin() inicializa la pantalla.

setContrast(int contraste) establece el contraste, en el ejemplo está a 50.

display() si el buffer de memoria está vacío el logo de Adafruit, una vez empecemos a trabajar con ella y mandar contenido que se almacena en la memoria cuando llamemos a esta función hará que se muestre en pantalla lo que hayamos programado.

clearDisplay() borra la pantalla.

setPixel(int x,int y, color) dibuja un único pixel. El parámetro color nos lo encontraremos en más funciones y es muy simple, si ponemos un 1 se mostrará el texto o figura con pixeles negros sobre fondo transparente, en cambio si lo ponemos a 0 nuestro texto o dibujo aparecerá en pixeles blancos sobre fondo negro.

drawline(int x0, int y0, int x1, int y1, color) dibuja una línea de las coordenadas (x1, y1) a las coordenadas (x2, y2).

drawrect(int x, int y, int ancho, int alto, color) dibuja un rectángulo partiendo desde el punto (x, y) con el ancho y alto que le especifiquemos.

fillrect(int x, int y, int ancho, int alto, int color) dibuja un rectángulo sólido partiendo desde el punto (x, y) con el ancho y alto que le especifiquemos.

drawcircle(int x, int y, int radio, color) dibuja una circunferencia con el centro en (x, y) y del radio especificado.

fillcircle(int x, int y, int radio, color) dibuja una circunferencia solida con el centro en (x, y) y del radio especificado.

Los 6 métodos anteriores admiten el parámetro color, el cual puede ser 0 y 1, como he explicado antes pero también admite WHITE o BLACK, que quizá os sea más intuitivo.

setCursor(int x, int y) posiciona el cursor en la coordenada (x, y) para escribir texto a continuación, pero ATENCIÓN, las coordenadas corresponden a la esquina superior izquierda del cuadro de texto o gráfico, no os preocupéis, es fácil acostumbrarse.

print("Ardumania ") escribe el texto entre las comillas. El método print() admite los mismos parámetros de entrada que estamos acostumbrados a utilizar con el método print() de la clase Serial

println("mola") igual que el print() pero añadiendo un retorno de carro al final... vaya, igual que el println() que conocemos de la clase Serial.

drawbitmap(int x, int y, bitmap, int ancho, int alto, color) a partir de la coordenada (x, y) dibuja un mapa de bits guardado en formato binario en el array bitmap del ancho y alto especificados. En el código de ejemplo, tras los defines hay podéis ver como son los arrays binarios que he utilizado para los símbolos del estado de la batería.

El código de ejemplo está en GitHub, en la carpeta Micro_micro_main-batterie_status.

Nota: si he cometido algún error agradecería que me lo dejéis en los comentarios.