Hola otra vez.
Después del primer intento de realizar un robot autónomo con más o menos éxito, he decidido mejorar ligeramente su estructura y su funcionamiento.
En este caso he decidido prescindir del servo para la dirección y realizar un montaje con dos ruedas accionada cada una con su propio motor-reductor, y una rueda libre como tercer punto de apoyo. El escaneado del entorno lo realizaremos con los mismos sensores de ultrasonidos que en el montaje anterior, que según el fabricante tienen un ángulo de visión de 15º. Lo demás, como la batería o el estabilizador a 5V es idéntico al primer robot.
Como en el modelo anterior, lleva luz de posición-freno y luz de marcha atrás. Y mi intención es nuevamente utilizar un Arduino. Pero en lugar de un Arduino Uno, decidí adquirir algo más pequeño, un Arduino Nano, que podéis encontrar a muy buenos precios en ebay.
Para controlar los motores, he utilizado el mismo módulo que en la versión anterior, equipado con un L298N y dos puentes en H. La única diferencia en este caso ha sido la forma de utilizarlo.
Este controlador utiliza para cada motor, dos pines para el sentido y uno para la velocidad, en PWM. Para que vaya adelante, hay que darle la configuración HIGH y LOW respectivamente a las dos patillas de control, y para que vaya marcha atrás, hay que darle LOW y HIGH respectivamente. En caso de recibir LOW y LOW, o HIGH y HIGH el motor se para. Y eso también podemos conseguirlo indicando en el pin de la velocidad voltaje 0V. De modo que para manejar el motor nos basta con HIGH y LOW, o LOW y HIGH. La primera parte de la parte contratante será considerada como la parte contratante de la primera parte….
Esta tabla lo ilustra mejor:
En el robot anterior, habia que conectar dos salidas de Arduino para cada motor, y antes de indicar HIGH en una de ellas, debías cambiar a LOW la otra. Esta vez he decidido intercalar un inversor entre el Arduino y el controlador, de modo que en el Arduino solo utilizamos una salida por motor, y el inversor se encarga de “crear” la otra salida. Así cuando le indiquemos un HIGH, la otra salida automáticamente cambiará a LOW, y viceversa.
Este es el sencillo esquema del inversor, que tendremos que realizar por partida doble, uno por cada motor.
Y aquí os pego el extenso código. Esta vez he realizado varias funciones para reducir el código y he guardado en dos variables el sentido de giro de cada rueda para en el siguiente loop continuar moviéndose, o en caso de cambiar de sentido, empezar acelerando, más que nada para suavizar el movimiento y reducir el consumo.
#include <Ultrasonic.h> /* Este modesto codigo pertenece a RosHardware. Se autoriza el uso parcial o total del mismo siempre y cuando se indique la procedencia del mismo. http://www.entremaqueros.com/bitacoras/roshardware */ Ultrasonic ultraright(10,11); // (Trig PIN,Echo PIN) DERECHA Ultrasonic ultraleft(12,8); // (Trig PIN,Echo PIN) IZQUIERDA int r = 0; //distancia derecha int l = 0; //distancia izquierda byte antr = LOW; //variable que guarda el sentido de giro de la rueda derecha en el loop anterior byte antl = LOW; //variable que guarda el sentido de giro de la rueda izquierda en el loop anterior int ledoutput1 = 7; //luz marcha atras int ledfreno = 6; //luz freno int direccionderecha = 4; //sentido de giro de la rueda derecha (HIGH adelante, LOW atras) int direccionizquierda = 2; //sentido de giro de la rueda izquierda (HIGH adelante, LOW atras) int vderecha = 5; //velocidad rueda derecha con PWM int vizquierda = 3; //velocidad rueda izquierda con PWM int lederror = 13; //led de error cuando se de el caso "else" en comparaciones de lecturas void movimiento(int right, int left, int vright, int vleft) //movimiento b�sico { analogWrite(vderecha, vright); //velocidad derecha analogWrite(vizquierda, vleft); //velocidad izquierda digitalWrite(direccionderecha, right); //direcci�n derecha digitalWrite(direccionizquierda, left); //direcci�n izquierda } void acelerar(int right, int left, int vright, int vleft) //si cambia el sentido de giro, //realizaremos una aceleraci�n { int i; movimiento(LOW,LOW,0,0); //paramos digitalWrite(direccionderecha, right); digitalWrite(direccionizquierda, left); for(i=4; i>=1; i--) //acelera progresivamente hasta las velocidades m�ximas indicadas { analogWrite(vderecha, (vright/i)); analogWrite(vizquierda, (vleft/i)); delay(25); } } void frenar() { movimiento(LOW, LOW, 0, 0); //paramos analogWrite(ledfreno, 250); delay(200); analogWrite(ledfreno, 70); } void error() //en caso desconocido { digitalWrite(lederror, HIGH); delay(200); digitalWrite(lederror, LOW); delay(200); } void setup() { pinMode (ledoutput1, OUTPUT); //luz marcha atras pinMode (ledfreno, OUTPUT); //luz marcha atras pinMode (direccionderecha, OUTPUT); //direccion de giro de la rueda derecha pinMode (direccionizquierda, OUTPUT); //direccion de giro de la rueda izquierda pinMode (lederror, OUTPUT); } void loop() { analogWrite(ledfreno, 70); delay(100); //Retardo entre lecturas de ultrasonidos para evitar interferencias. r=ultraright.Ranging(CM); // lectura derecha en CM delay(100); l=ultraleft.Ranging(CM); // lectura izquierda en CM if(r>60 || l>60) //v�a libre { digitalWrite(ledoutput1, LOW); //luz marcha atr�s apagada if(antr==HIGH && antl==HIGH) //si ya iban hacia adelante ambas { movimiento(HIGH, HIGH, 250, 235); //por cuestiones de hardware, una rueda //tiene m�s velocidad que la otra } else { frenar(); acelerar(HIGH, HIGH, 250, 235); } antr=HIGH; //guardamos sentido antl=HIGH; //guardamos sentido } else if(r<20 || l<20) //al menos una distancia menor de 20cm { digitalWrite(ledoutput1, HIGH); //luz marcha atras encendida if(r<20 && l<20) { if(antr==LOW && antl==LOW) { movimiento(LOW, LOW, 200, 180); } else { frenar(); acelerar(LOW, LOW, 200, 180); } delay(500); } //inicio fragmento rotaci�n sobre eje central else if(r<20 && l>40) { frenar(); acelerar(HIGH, LOW, 200, 180); delay(500); } else if(r>40 && l<20) { frenar(); acelerar(LOW, HIGH, 200, 180); delay(500); } //final fragmento rotaci�n sobre eje central else if(r<20 && l>20) { if(antr==LOW && antl==LOW) { movimiento(LOW, LOW, 0, 200); } else { frenar(); acelerar(LOW, LOW, 0, 200); } delay(1000); } else if(r>20 && l<20) { if(antr==LOW && antl==LOW) { movimiento(LOW, LOW, 200, 0); } else { frenar(); acelerar(LOW, LOW, 200, 0); } delay(1000); } else { error(); } antr=LOW; //guardamos sentido antl=LOW; //guardamos sentido } else if(r<40 || l<40) //almenos una distancia menor de 40cm { digitalWrite(ledoutput1, LOW); //luz marcha atr�s apagada if(antr==HIGH && antl==HIGH) { if(r<40 && l<40) { if(r>l) { movimiento(HIGH, HIGH, 150, 200); } else { movimiento(HIGH, HIGH, 200, 150); } } else if(r<40 && l>40) { movimiento(HIGH, HIGH, 250, 100); } else if(r>40 && l<40) { movimiento(HIGH, HIGH, 100, 250); } else { error(); } } else { frenar(); if(r<40 && l<40) { if(r>l) { acelerar(HIGH, HIGH, 150, 200); } else { acelerar(HIGH, HIGH, 200, 150); } } else if(r<40 && l>40) { acelerar(HIGH, HIGH, 250, 100); } else if(r>40 && l<40) { acelerar(HIGH, HIGH, 100, 250); } else { error(); } } antr=HIGH; //guardamos sentido antl=HIGH; //guardamos sentido } else { error(); } }
Estoy abierto a todo tipo de críticas constructivas, todo código es mejorable. Esta librería, como en el caso anterior, os hará falta para controlar los sensores de ultrasonidos de 4 pines y está arreglada para el IDE 1.x de Arduino.
Esta vez sí funciona la luz de freno y posición. Y su comportamiento es bastante bueno, salvo porque algunas veces, cuando avanza recto, parece que está unos segundos sin realizar lecturas de ultrasonidos. Tengo mis dudas de si el problema es debido a la función acelerar. Quizás por algún motivo no termina el bucle for.
Os cuelgo algunos vídeos de su comportamiento. Mientras los véis, yo iré pensando en el tercer prototipo…
Hasta pronto!











Pingback: Arduino rover evolves to a trike design - Hack a Day
Pingback: Vehículo autónomo con Arduino | Ros Hardware
Pingback: Arduino rover evolves to a trike design / Cooking Hacks Blog