ROOMBAKAR
Autores
- Santiago Rivas Martín
- Álvaro Lafarga García
- Juan de la Torre Melero
- Fernando Rubio Moreno
Objetivo
Nuestro proyecto final de de la asignatura de SEyTR, es el Roombakar, es un coche autónomo fabricado a partir de un Arduino Uno, cartón para el chasis, un par de ruedas, motores, tanto para las ruedas como para el aspirador, sensores de ultrasonidos, un servo y muchos cables.
La funcionalidad del mismo, es localizar obstáculos con un sensor de ultrasonidos para así poder evitarlos y tomar una ruta alternativa que le permita seguir avanzando mientras aspira con una manguera. Además, hicimos que el Roombakar emitiera sonidos cuando detectaba un objeto delante.
Materiales
Material | Cantidad | |
Arduino UNO | 2 | |
Componente de ultrasonido | 1 | |
Fuente de alimentación USB tipo C | 1 | |
Arduino Sensor Shield | 1 | |
Motor Drive Controller Board Module L298N | 1 | |
Buzzer/Speaker | 1 | |
Resistencia 550 Ω | 1 | |
Componentes empleados para el chasis (cartón, material reciclado..) | *** | |
Interruptor | 1 | |
9V Battery Modulo 4 baterías (1.5V) | 1 1 | |
Motores Makeblock 6V 200rpm | 2 | |
CABLES PROTOBOARD M-M 65 | 25 |
Planificación y reparto de tareas
A lo largo de la asignatura se han realizado entorno a 5 sesiones de trabajo destinadas a la búsqueda de materiales y al propio desarrollo del proyecto. Debido a las restricciones horarias, nos hemos visto obligados a reducir estas reuniones y trabajar tambien de forma remota en el proyecto. Por lo que las tareas quedaron repartidas de la siguiente forma:
- En base al servomotor y el zumbador el trabajo lo realizaron Álvaro Lafarga García y Juan de la la Torre Melero
- El sistema formado por los motores del propio vehículo junto al sistema de recogida formó parte del trabajo realizado por Santiago Rivas Martín y Fernando Rubio Moreno
Una vez el grupo disponía de los materiales necesarios nos reunimos para realizar el ensamblado y poner a prueba el proyecto.
Explicación del código
En cuanto al código, vemos que predomina la simplicidad.
Cuenta con 8 subprogramas, además del loop() y del setup(),
Podemos dividirlos en 2 tipos, los que están relacionados con los motores, y los que están relacionados con el servo y el sensor.
Los del servo y sensor, son 3, leer(), que devuelve el valor medido por el sonar, medida en centímetros, y pone un valor estándar si la distancia es muy grande y no detecta nada el sensor.
Los otros 2 métodos orientan el servo hacia la izquierda o la derecha y llaman a leer() para conseguir el valor.
Los otros 5, relacionados con el movimiento de los motores también son muy sencillos, tenemos un método llamado parada(), que como su nombre indica, para el coche, pero además, como funcionalidad extra, reutilizamos el circuito de la primera práctica para hacer que cuando sea llamado este método, que haga un pitido. Los subprogramas continuar() y atras(), ponen en HIGH los pines que controlan el movimiento de los motores en cada orientación haciendo que giren hacia delante y hacia detras respectivamente. Los 2 restantes, giro_derecha() y giro_izquierda(), son para girar, haciendo que el Roombakar gire sobre sí mismo, hacia uno de los 2 lados, con un delay de 300ms para rotar en torno a 90º sobre la posición original y después haciendo que las ruedas giren hacia delante otra vez, pero con su nueva orientación.
Finalmente, en setup(), configuramos los pines de salida, orientamos el servo hacia delante, y leemos los valores de distancia iniciales para estar seguros que no hay obstáculos delante.
En loop(), ajustamos valores iniciales, y constantemente, checkeamos la distancia a la que se encuentra el obstáculo, y llamamos a los métodos anteriormente descritos, para parar el coche y reproducir un pitido que avisa que hemos encontrado un objeto, y mirar cual de los 2 lados está más despejado de obstáculos y elegir ese, en caso de que la distancia actual sea menor que 25.
#include <Servo.h> //Libreria servomotor
#include <NewPing.h> //Libreria sensor ultrasonidos. Descaragada
#include <TimerFreeTone.h> //Libreria para el uso de zumbador. Descaragada
//L298N pines de control
const int MotorIzqDelante = 4;
const int MotorIzqDetras = 5;
const int MotorDerDelante = 3;
const int MotorDerDetras = 2;
//Pines del sensor
#define trig_pin A1
#define echo_pin A3
#define maximum_distance 450
boolean continua_hacia_delante = false;
int dist = 100;
NewPing sonar(trig_pin, echo_pin, maximum_distance);
Servo servo_motor;
//Zumbador
#define TONE_PIN 8
int melodia[] = {900};
int duracion[] = {250};
void setup() {
pinMode(MotorIzqDelante, OUTPUT);
pinMode(MotorIzqDetras, OUTPUT);
pinMode(MotorDerDelante, OUTPUT);
pinMode(MotorDerDetras, OUTPUT);
pinMode(TONE_PIN, OUTPUT);
servo_motor.attach(12);
//Orientarlo hacia delante
servo_motor.write(90);
delay(2000);
dist = leer();
delay(100);
dist = leer();
delay(100);
dist = leer();
delay(100);
dist = leer();
delay(100);
//Leer valores distancia
}
void loop() {
//distancia a la derecha
int distDer = 0;
//distancia a la izquierda
int distIzq = 0;
delay(50);
//distancia a la que se encuentra el objeto
if (dist <= 25) {
parada();
delay(300);
atras();
delay(400);
parada();
delay(300);
distDer = miraDerecha();
delay(300);
distIzq = miraIzquierda();
delay(300);
//si puede girar a derecha
if (dist >= distIzq) {
giro_derecha();
parada();
}
//si no, gira izquierda
else {
giro_izquierda();
parada();
}
}
//si la distancia al objeto es mayor
else {
continuar();
}
dist = leer();
}
void parada() {
digitalWrite(MotorIzqDetras, LOW);
digitalWrite(MotorIzqDelante, LOW);
digitalWrite(MotorDerDelante, LOW);
digitalWrite(MotorDerDetras, LOW);
//Hacemos sonar el zumbador al detectar algo
TimerFreeTone(TONE_PIN, melodia[0], duracion[0]);
delay(50);
}
void continuar() {
if (!continua_hacia_delante) {
continua_hacia_delante = true;
digitalWrite(MotorIzqDelante, HIGH);
digitalWrite(MotorDerDelante, HIGH);
digitalWrite(MotorIzqDetras, LOW);
digitalWrite(MotorDerDetras, LOW);
}
}
void atras() {
continua_hacia_delante = false;
digitalWrite(MotorIzqDetras, HIGH);
digitalWrite(MotorDerDetras, HIGH);
digitalWrite(MotorIzqDelante, LOW);
digitalWrite(MotorDerDelante, LOW);
}
void giro_derecha() {
//rotar sobre si mismo
digitalWrite(MotorIzqDelante, HIGH);
digitalWrite(MotorDerDetras, HIGH);
digitalWrite(MotorIzqDetras, LOW);
digitalWrite(MotorDerDelante, LOW);
delay(300);
//continuar hacia delante
digitalWrite(MotorIzqDelante, HIGH);
digitalWrite(MotorDerDelante, HIGH);
digitalWrite(MotorIzqDetras, LOW);
digitalWrite(MotorDerDetras, LOW);
}
void giro_izquierda() {
//rotar sobre si mismo
digitalWrite(MotorIzqDetras, HIGH);
digitalWrite(MotorDerDelante, HIGH);
digitalWrite(MotorIzqDelante, LOW);
digitalWrite(MotorDerDetras, LOW);
delay(300);
//continuar hacia delante
digitalWrite(MotorIzqDelante, HIGH);
digitalWrite(MotorDerDelante, HIGH);
digitalWrite(MotorIzqDetras, LOW);
digitalWrite(MotorDerDetras, LOW);
}
int miraDerecha() {
//giramos sensor hacia la derecha
servo_motor.write(10);
delay(500);
int dist = leer();
delay(100);
servo_motor.write(90);
return dist;
}
int miraIzquierda() {
//giramos sensor hacia la izquierda
servo_motor.write(170);
delay(500);
int dist = leer();
delay(100);
servo_motor.write(90);
return dist;
delay(100);
}
int leer() {
delay(70);
int cm = sonar.ping_cm();
if (cm == 0) {
//si la distancia al objeto es mayor que lo que lee
//ponemos una distancia estandar
cm = 250;
}
return cm;
}
Montaje del proyecto
El proyecto está formado por una carcasa la cual hemos fabricado a partir de cartón y componentes de plastico reutilizados. El Arduino junto al resto de componentes vendría dentro de la caja entregada a principio de la asignatura o comprado mas tarde por el grupo de trabajo.
Se compone de un servomotor se conecta a un lector de ultrasonidos el cual nos permite reconocer el entorno, no es perfecto ya que necesitábamos hacer modificaciones en el sistema para que el arco del servomotor no llegara a identificar al propio vehículo como obstáculo.
Implementado el circuito y ya puesto a prueba, tanto motores como sensor de ultrasonidos, decidimos añadir un zumbador para incluirle un sonido al detectar con el sensor un obstáculo. Este está conectado a GND y comparte la señal del sensor de ultrasonidos (La conexiones se muestran en la segunda fotografía, donde el lector de ultrasonidos ocupa el pin 8 y el zumbador el pin 9), también se le ha añadido a esa parte del circuito una resistencia de 550 ohmios como incluimos en la Practica obligatoria entregada anteriormente en la asignatura.
A partir de aquí, en la misma proto placa conectaremos la batería y las entradas del motor y concluimos conectandola batería externa a la placa de Arduino
Problemas y soluciones
Uno de los principales problemas que hemos tenido, es el funcionamiento de las ruedas.
Al contar solamente con 2 motores, el peso del chasis hacia que se redujera su velocidad notablemente. También, hemos notado que algunas veces, en el lateral más pesado, la rueda no giraba del todo bien, haciendo que o bien gire sobre sí mismo o gire más hacia ese lado.
En cuanto a la otra rueda, la que no lleva motor, hemos notado también, que no se pone recta después de hacer giros, haciendo que cuando vuelva a ir en línea recta, la trayectoria del Roombakar sea orientada hacia ese lado.
Otro de los problemas que hemos tenido, no tiene que ver con la parte Hardware, si no con el Software, y Arduino.
En nuestro caso, hicimos que el Roombakar emitiera sonidos cuando detectaba un objeto delante. Al parecer, al contar con un sensor de ultrasonidos, el código usaba un Timer para controlar el valor medido, y cuando incluímos el zumbador, al realizar la operación tone(), nos saltaba un fallo por que al parecer, tone usa el mismo Timer y no es compatible el uso con el mismo Timer. La solución, después de buscar y leer información relativa a este fallo, en los foros de Arduino, encontramos una solución en la que una persona que realizó una librería para hacer la operación tone(), pero, sin el uso de Timers, por lo que descargándola y añadiéndola mediante .ZIP pudimos implementar dicha funcionalidad.
Además de estos problemas, también llegamos a implementar la idea de reducir la velocidad del motor para que el Roombakar pudiese recoger la basura mejor, sin embargo, acabamos descartando esta opción ya que cuando le pusimos la botella y la batería externa para que funcionase, esto objetos produjeron un peso extra que daba a lugar a que ya fuera a una velocidad deseada y no tuviese problemas al limpiar
Pese a esto, dejamos por aquí el código y una explicación de esta funcionalidad por si alguien en el futuro quisiera utilizarla. Este código habría que añadirlo al que ya está para su correcto funcionamiento.
// ENA y ENB para controlar la velocidad de los motores
const int ENA = 13;
const int ENB = 11;
pinMode(ENA, OUTPUT);
pinMode(ENB, OUTPUT);
void parada() {
analogWrite(ENA, 0);
analogWrite(ENB, 0);
}
void continuar() {
analogWrite(ENA, 120);
analogWrite(ENB, 120);
}
}
void atras() {
analogWrite(ENA, 120);
analogWrite(ENB, 120);
}
void giro_derecha() {
analogWrite(ENA, 120);
analogWrite(ENB, 0);
delay(500);
analogWrite(ENA, 120);
analogWrite(ENB, 120);
}
void giro_izquierda() {
analogWrite(ENA, 0);
analogWrite(ENB, 120);
delay(500);
analogWrite(ENA, 120);
analogWrite(ENB, 120);
}
Esta implementación básicamente consiste en ponerle un ENB y ENA los cuales determinarán a qué velocidad girará nuestras ruedas. Es por esto que nos ayudaremos del analogWrite para meterle un valor exacto en vez de un valor máximo o mínimo como High o Low.