Robot móvil mejorado controlado con Arduino

Vamos a mejorar el comportamiento de nuestro robot móvil basado en Arduino mediante la adición de unos sensores de detección de obstáculos por infrarrojos.

La anterior versión del robot tenía el defecto de disponer de único un sensor de distancia, basado en ultrasonidos, que aseguraba la detección de obstáculos frontales dentro del ángulo para el que éste está diseñado. Por tal motivo quedaban zonas ciegas que habrán de ser cubiertas con nuevos sensores.

Montaje del circuito

Realizaremos el montaje mostrado en la figura basado en los siguientes componentes:R1F2

Como se puede comprobar en la figura, respecto a la versión anterior tan sólo se ha sustituido el miniprotoboard que sostenía el sensor de ultrasonidos por otro más pequeño, se ha añadido un segundo que hará de distribuidor de alimentación y tierra y se ha incorporado una pareja de sensores de obstáculos.

Las salidas de los nuevos sensores irán conectadas a los pines 11 y 12 de nuestro Arduino.

Programación de Arduino

Utilizaremos el siguiente código para controlar nuestro robot:

///
/// Robot R1-F2
///
/// by RafaG
///

/// Definición de pines
///
// Pines de sensores IR
const int ir_izq = 11;
const int ir_der = 12;

// Pines de HC-SR04
const int trigger = 10;
const int echo = 9;

// Motor A
const int ENA = 5; // Pin PWM
const int IN1 = 2;
const int IN2 = 3;

// Motor B
const int ENB = 6; // Pin PWM
const int IN3 = 4;
const int IN4 = 7;
///
/// Fin de definición de pines

/// Estados de movimiento y velocidad
///
int dirActualA = 0; // 0->detenido, 1->avanza, -1->retrocede
int velActualA = 0;
int dirActualB = 0; // 0->detenido, 1->avanza, -1->retrocede
int velActualB = 0;

int VELOCIDAD_MAX = 250;
int VELOCIDAD_MIN = 100;
int VELOCIDAD_ARRANQUE = 200;
int VELOCIDAD_NORMAL = 150;

enum estados {
    detenido,
    avanzando,
    girando_izq,
    girando_der,
    retrocediendo
};

estados estadoActual = detenido;
///
/// Fin de estados de movimiento y velocidad

///
float DISTANCIA_MAX = 450.0;

float distancia_anterior = 0.0;
///

/// Funciones básicas
///
void setup() {
    Serial.begin(9600);

    /// Inicialización de pines
    ///
    // IR
    pinMode(ir_izq, INPUT);
    pinMode(ir_der, INPUT);

    // HC-SR04
    pinMode(trigger, OUTPUT);
    pinMode(echo, INPUT);

    // Motores
    pinMode(ENA, OUTPUT);
    pinMode(ENB, OUTPUT);
    pinMode(IN1, OUTPUT);
    pinMode(IN2, OUTPUT);
    pinMode(IN3, OUTPUT);
    pinMode(IN4, OUTPUT);
    ///
    /// Fin de inicialización de pines

    // Motores parados
    detenerAB();
}

void loop() {
 /// Medida en sensor ultrasonidos
 ///
 // Trigger inicial
 digitalWrite(trigger, LOW);
 delayMicroseconds(5);
 // Comienzo de la medida
 digitalWrite(trigger, HIGH);
 delayMicroseconds(10);
 digitalWrite(trigger, LOW);
 // Adquisición y conversión a centímetros
 float distancia = pulseIn(echo, HIGH);
 distancia = distancia * 0.01657;

 if (distancia > DISTANCIA_MAX) { // Filtrado de distancias mal tomadas
 distancia = distancia_anterior;
 }
 else {
 distancia_anterior = distancia;
 }
 ///
 /// Fin medida en sensor ultrasonidos

 /// Lectura de sensores de distancia IR
 ///
 int lectura_ir_izq = digitalRead(ir_izq);
 int lectura_ir_der = digitalRead(ir_der);
 ///
 /// Fin de lectura de sensores de distancia IR

 /// Lógica de navegación de robot
 ///
 int velocidad;

 if( (distancia > 10.0) && (lectura_ir_izq == HIGH) && (lectura_ir_der == HIGH) ) { // Distancia de seguridad
   avanzaB();
   avanzaA();

   float velocidadCandidata = distancia * 255.0 / 30.0;
   if (velocidadCandidata < VELOCIDAD_MIN) velocidadCandidata = VELOCIDAD_MIN;
   velocidad = (int) velocidadCandidata;
   velocidad = (estadoActual != avanzando) ? VELOCIDAD_ARRANQUE : velocidad;
   setVelocidadAB(velocidad);

   estadoActual = avanzando; // Actualiza estado de vehículo

   Serial.print("- ESTADO: FF");
 }
 else { // No se puede avanzar
   velocidad = VELOCIDAD_NORMAL;

   if(lectura_ir_izq == HIGH) { // Gira izquierda
     rotar();

     velocidad = (estadoActual != girando_izq) ? VELOCIDAD_ARRANQUE : velocidad;
     setVelocidadAB(velocidad);

     estadoActual = girando_izq; // Actualiza estado de vehículo

     Serial.print("- ESTADO: R-Izq");
   }
   else if(lectura_ir_der == HIGH) { // Gira derecha
     antirotar();

     velocidad = (estadoActual != girando_der) ? VELOCIDAD_ARRANQUE : velocidad;
     setVelocidadAB(velocidad);

     estadoActual = girando_der; // Actualiza estado de vehículo

     Serial.print("- ESTADO: R-Der");
   }
   else { // Retrocede
     retrocedeA();
     retrocedeB();

     velocidad = (estadoActual != retrocediendo) ? VELOCIDAD_ARRANQUE : velocidad;
     setVelocidadAB(velocidad);

     estadoActual = retrocediendo; // Actualiza estado de vehículo

     Serial.print("- ESTADO: Atrás");
   }
 }
 Serial.print(" - Distancia: ");
 Serial.print(distancia);
 Serial.print(" - Velocidad: ");
 Serial.println(velocidad);
 ///
 /// Fin de lógica de navegación de robot

 delay(100);
}
///
/// Fin funciones básicas

/// Funciones de motores
///
void detenerA() {
 digitalWrite(ENA, LOW);// Motor A desactivado
}

void detenerB() {
 digitalWrite(ENB, LOW);// Motor B desactivado
}

void detenerAB() {
 detenerA();
 detenerB();
}

void avanzaA() {
 if(dirActualA == 1) return;

 detenerA();
 dirActualA = 1;
 digitalWrite(IN1, LOW);
 digitalWrite(IN2, HIGH);
}

void retrocedeA() {
 if(dirActualA == -1) return;

 detenerA();
 dirActualA = -1;
 digitalWrite(IN1, HIGH);
 digitalWrite(IN2, LOW);
}

void avanzaB() {
 if(dirActualB == 1) return;

 detenerB();
 dirActualB=1;
 digitalWrite(IN3,LOW);
 digitalWrite(IN4,HIGH);
}

void retrocedeB() {
 if(dirActualB==-1) return;

 detenerB();
 dirActualB=-1;
 digitalWrite(IN3,HIGH);
 digitalWrite(IN4,LOW);
}

void setVelocidadA(int velocidad) {
 if(dirActualA == 0) return;
 velActualA = (velocidad >= VELOCIDAD_MAX) ? VELOCIDAD_MAX : velocidad;
 analogWrite(ENA, velActualA);
}

void setVelocidadB(int velocidad) {
 if(dirActualB == 0) return;
 velActualB = (velocidad >= VELOCIDAD_MAX) ? VELOCIDAD_MAX : velocidad;
 analogWrite(ENB, velActualB);
}

void setVelocidadAB(int velocidad) {
 setVelocidadA(velocidad);
 setVelocidadB(velocidad);
}

void rotar() {
 avanzaA();
 retrocedeB();
}

void antirotar() {
 avanzaB();
 retrocedeA();
}
///
/// Fin funciones de motores

Como se observa en el código, el sistema leerá la distancia proveniente del sensor de ultrasonidos para determinar si avanza o, por el contrario, gira. En caso de que la distancia sea superior a 10 cm, el robot hará girar las ruedas en el mismo sentido, haciendo que el robot avance. Si la distancia es inferior a la señalada, ambas ruedas girarán en sentido opuesto, forzando la rotación del robot sobre su propio eje. El sentido del giro vendrá determinado por la detección de obstáculos por parte de algunos de los sensores IR. Se contempla un último caso que implique ambos sensores IR detectando obstáculos, que conllevarán el giro de ambos motores en sentido inverso, lo que supondrá el desplazamiento de nuestro robot en marcha atrás.

El estado del sistema será periódicamente transmitido por el puerto serie de Arduino.

Realización de las pruebas y resultados

Una vez realizado el montaje anterior -e introducido el código en nuestro Arduino- se comprueba cómo el comportamiento del robot es bastante aceptable. El vehículo sortea con bastante destreza los obstáculos que encuentra en su camino.

Esta entrada fue publicada en Arduino y etiquetada , , . Guarda el enlace permanente.

5 respuestas a Robot móvil mejorado controlado con Arduino

  1. Manuel Cornejo dijo:

    hola me sale un erro al compilar …´detenerAB´ was not declared in this scope, parece que hay un error en la librería, por favor puedes resubirla o en todo caso probar copiando el código de muestra y ver si sale error…

    • Rafa G dijo:

      Hola, acabo de comprobar lo que dices. Efectivamente, faltaba en el código la función a la que haces referencia. Ya está actualizado el artículo con el código corregido. Gracias por la observación.

  2. Pingback: Contador de vueltas por efecto Hall aplicado a robot controlado por Arduino | Notas sobre robótica, sistemas operativos y programación

  3. Pingback: Navegación por estima en robot controlado por Arduino | Notas sobre robótica, sistemas operativos y programación

  4. antonio tudela dijo:

    Hola es la primera vez que hago algo con arduino ,confieso que no tenia ninguna fe en conseguirlo
    aun no se como (BUENO SI LO SE GRACIAS A VOSOTROS) os aseguro que funciono perfectamente apenas unos pequeños ajustes en los ir
    LO UNICO QUE NUEVAMENTE OS QUIRO DECIR ES “GRACIAS.GRACIAS Y GRACIAS

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s