En esta entrada se muestran un robot omni direccional, su descripción, componentes, amplificaciones, código y esquema de la interfaz del usuario.
El robot diseñado es un robot omni direccional, aquel capaz de moverse en cualquier dirección cambiando o no la orientación del cuerpo. Esta movilidad única se consigue gracias al uso de un tipo especial de ruedas, las Mecanum wheels. Estas ruedas, pese a ser caras, proporcionan una seguridad a la hora del funcionamiento.

Materiales:
El excel con la lista de materiales, links y precios: Materiales
- Kit de robot de rueda Mecanum
- Kit de iniciación RFID para Arduino UNO R3
- Shield para controlar los motores
- Shield para controlar los motores
- Bluetooth HC05
- Cables Arduino M-H 10cm
- Cables Arduino M-M 10cm
- Cables Arduino H-H 10cm
- Sensor de seguimiento de líneas TCRT5000
- Pilas recargables AA 2800mAh
- Portapilas 4xAA con interruptor
- Mini Power Bank 5000mAh
Todos los materiales los he pegado a la base del coche con cinta de doble cara de los chinos. Una floja para pegar los componentes como la batería, arduino y pilas, que no se vayan a mover nada. Y una fuerte para pegar los sensores de seguimiento de líneas, para el servomotor y para el sensor de distancia.
Aplicaciones:
Las tres aplicaciones principales que realiza el robot de forma autónoma son evitar obstáculos, seguir la línea y conectarse mediante bluetooth.
Evita obstáculos: este robot tiene un sensor de distancia VL53L0X que está apoyado sobre un servomotor que gira y va orientando al sensor. Una vez que el sensor detecte un objeto o pared, hace un barrido de 90 a 130 y otro de 90 a 50, dependiendo de dónde haya mayor distancia dará la orden de girar hacia ese lado y continuará con su camino hasta que vuelva a encontrarse con otro obstáculo.
Sigue líneas: el robot tiene dos sensores TCRT5000, sensor de infrarrojos capaz de detectar el color del suelo. Mediante el uso de este sensor deberá de seguir por sí solo y sin salirse, una línea oscura que está sobre una superficie clara.
Conexión por bluetooth: se conecta por bluetooth al móvil y a través de una aplicación se da una serie de órdenes que el robot sigue.
Interfaz del usuario:
He creado con MIT App Inventor, la interfaz del usuario. Está compuesta por tres pantallas, cada una con su propio diagrama de bloques. Las imágenes para los botones han sido obtenidas de la página web Flaticon.
En la primera pantalla, aparecen los comandos de direcciones y desplazamientos que puede realizar el robot. Los dos botones inferiores son para cambiar a una de las otras dos pantallas.

Con el primer botón inferior se accede a la segunda pantalla, que es la encargada de enviar los comandos para el sigue líneas y el evita obstáculos. El último botón es para regresar a la pantalla inicial.

Con el segundo botón inferior se accede a la tercera pantalla, que dependiendo del ángulo de inclinación del móvil moverá el robot en una dirección u otra.

Material adicional:
Numeración de las ruedas, para entender qué número corresponde a cada rueda en el código.

Movimientos de cada rueda para cada desplazamiento (esto también es para comprender mejor el código):

Por último, añado un esquema sencillos de los módulos que se han utilizado y las conexiones de cada uno de sus pines.

Código completo:
Se adjunta un zip del código completo del robot en Arduino.
#include <SoftwareSerial.h> //Libreria bluetooth
#include <AFMotor.h> //Libreria motores
#include «Adafruit_VL53L0X.h» //Libreria sensor de distancia
#include <Servo.h> //Libreria servo
//BLUETOOTH
#define TX_PIN A2 //Pines para el Bluetooth
#define RX_PIN A3
SoftwareSerial BT(RX_PIN,TX_PIN); //Bluetooth
//MOTORES
AF_DCMotor motor1(1); //Detras izquierda
AF_DCMotor motor2(2); //Detras derecga
AF_DCMotor motor3(3); //Delante derecha
AF_DCMotor motor4(4); //Delante izquierda
//SENSORES DE LUZ
#define SDer A0
#define SIzq A1
int LSD, LSI;
int memoria;
//SENSOR DE DISTANCIA
Adafruit_VL53L0X lox = Adafruit_VL53L0X();
int i, sumD=0, sumI=0;
//SERVOMOTOR
Servo servoMotor; //Creamos el objeto Servo
//ESTADO QUE SE LEE CON EL BLUETOOTH
int estado=4;
void setup()
{
Serial.begin(9600);
BT.begin(38400);
motor1.setSpeed(250);
motor2.setSpeed(250);
motor3.setSpeed(250);
motor4.setSpeed(250);
pinMode(SDer,INPUT);
pinMode(SIzq,INPUT);
Serial.println(«VL53L0X test»);
if (!lox.begin()) {
Serial.println(F(«Failed to boot VL53L0X»));
while(1);
}
servoMotor.attach(10); //Definimos el Servo en el pin 10
}
void loop()
{
if(BT.available())
estado = BT.read();
Serial.println(estado);
switch(estado)
{
case 0: //Izquierda delante
motor1.run(FORWARD); //Delante M1
motor2.run(RELEASE); //Parada M2
motor3.run(FORWARD); //Delante M3
motor4.run(RELEASE); //Parada M4
break;
case 1: //Delante
motor1.run(FORWARD); //Delante M1
motor2.run(FORWARD); //Delante M2
motor3.run(FORWARD); //Delante M3
motor4.run(FORWARD); //Delante M4
break;
case 2: //Derecha delante
motor1.run(RELEASE); //Parada M1
motor2.run(FORWARD); //Delante M2
motor3.run(RELEASE); //Parada M3
motor4.run(FORWARD); //Delante M4
break;
case 3: //Izquierda
motor1.run(FORWARD); //Delante M1
motor2.run(BACKWARD); //Detras M2
motor3.run(FORWARD); //Delante M3
motor4.run(BACKWARD); //Detras M4
break;
case 4: //Parada
motor1.run(RELEASE); //Parada M1
motor2.run(RELEASE); //Parada M2
motor3.run(RELEASE); //Parada M3
motor4.run(RELEASE); //Parada M4
break;
case 5: //Derecha
motor1.run(BACKWARD); //Detras M1
motor2.run(FORWARD); //Delante M2
motor3.run(BACKWARD); //Detras M3
motor4.run(FORWARD); //Delante M4
break;
case 6: //Izquierda detras
motor1.run(RELEASE); //Parada M1
motor2.run(BACKWARD); //Detras M2
motor3.run(RELEASE); //Parada M3
motor4.run(BACKWARD); //Detras M4
break;
case 7: //Detras
motor1.run(BACKWARD); //Detras M1
motor2.run(BACKWARD); //Detras M2
motor3.run(BACKWARD); //Detras M3
motor4.run(BACKWARD); //Detras M4
break;
case 8: //Derecha detras
motor1.run(BACKWARD); //Detras M1
motor2.run(RELEASE); //Parada M2
motor3.run(BACKWARD); //Detras M3
motor4.run(RELEASE); //Parada M4
break;
case 9: //Giro izquierda/antihorario
motor1.run(BACKWARD); //Detras M1
motor2.run(FORWARD); //Delante M2
motor3.run(FORWARD); //Delante M3
motor4.run(BACKWARD); //Detras M4
break;
case 10: //Giro derecha/horario
motor1.run(FORWARD); //Delante M1
motor2.run(BACKWARD); //Detras M2
motor3.run(BACKWARD); //Detras M3
motor4.run(FORWARD); //Delante M4
break;
case 11: //Sigue lineas
LSD=digitalRead(SDer);
LSI=digitalRead(SIzq);
if(LSI==1 && LSD==1) //Ambos sobre oscuro
{
//Delante
motor1.run(FORWARD); //Delante M1
motor2.run(FORWARD); //Delante M2
motor3.run(FORWARD); //Delante M3
motor4.run(FORWARD); //Delante M4
memoria=0;
}
if(LSI==1 && LSD==0) //Derecha fuera linea
{
//Girar a la izquierda
motor1.run(BACKWARD); //Detras M1
motor2.run(FORWARD); //Delante M2
motor3.run(FORWARD); //Delante M3
motor4.run(BACKWARD); //Detras M4
memoria = 2;
}
if(LSI==0 && LSD==1) //Izquierda fuera linea
{
//Girar a la derecha
motor1.run(FORWARD); //Delante M1
motor2.run(BACKWARD); //Detras M2
motor3.run(BACKWARD); //Detras M3
motor4.run(FORWARD); //Delante M4
memoria = 1;
}
if(LSI==0 && LSD==0) //Si se sale de la linea
{
//Si ha salido yendo recto
if (memoria == 0)
{
//Detras
motor1.run(BACKWARD); //Detras M1
motor2.run(BACKWARD); //Detras M2
motor3.run(BACKWARD); //Detras M3
motor4.run(BACKWARD); //Detras M4
}
//Si se ha salido en un giro a la izquierda
if (memoria == 1)
{
//Girar a la derecha
motor1.run(FORWARD); //Delante M1
motor2.run(BACKWARD); //Detras M2
motor3.run(BACKWARD); //Detras M3
motor4.run(FORWARD); //Delante M4
}
//Si se ha salido en un giro a la derecha
if (memoria == 2)
{
//Girar a la izquierda
motor1.run(BACKWARD); //Detras M1
motor2.run(FORWARD); //Delante M2
motor3.run(FORWARD); //Delante M3
motor4.run(BACKWARD); //Detras M4
}
}
break;
case 12: //Evita obstaculos
VL53L0X_RangingMeasurementData_t measure;
Serial.print(«Leyendo sensor… «);
lox.rangingTest(&measure, false); // si se pasa true como parametro, muestra por
//puerto serie datos de debug
if (measure.RangeStatus != 4)
{
Serial.print(«Distance (mm): «);
Serial.println(measure.RangeMilliMeter);
//———————————————
//LO QUE SE AÑADE
sumD=0, sumI=0;
motor1.run(FORWARD); //Delante M1
motor2.run(FORWARD); //Delante M2
motor3.run(FORWARD); //Delante M3
motor4.run(FORWARD); //Delante M4
if (measure.RangeMilliMeter<250)
{
//Parada
motor1.run(RELEASE); //Parada M1
motor2.run(RELEASE); //Parada M2
motor3.run(RELEASE); //Parada M3
motor4.run(RELEASE); //Parada M4
for (i=90;i<130;i++)
{
servoMotor.write(i);
sumI+=lox.readRange();
delay(5);
}
for (i=130;i>90;i–)
{
servoMotor.write(i);
sumI+=lox.readRange();
delay(5);
}
for (i=90;i>50;i–)
{
servoMotor.write(i);
sumD+=lox.readRange();
delay(5);
}
for (i=50;i<90;i++)
{
servoMotor.write(i);
sumD+=lox.readRange();
delay(5);
}
if (sumD>sumI)
{
//Giro derecha/horario
motor1.run(FORWARD); //Delante M1
motor2.run(BACKWARD); //Detras M2
motor3.run(BACKWARD); //Detras M3
motor4.run(FORWARD); //Delante M4
delay(500);
}
else
{
//Giro izquierda/antihorario
motor1.run(BACKWARD); //Detras M1
motor2.run(FORWARD); //Delante M2
motor3.run(FORWARD); //Delante M3
motor4.run(BACKWARD); //Detras M4
delay(500);
}
}
//———————————————
}
else {
Serial.println(«Fuera de rango»);
}
delay(100);
break;
}
}