Robot con Arduino y sensor ultrasónico para calcular las distancias a los objetos cercanos y evitarlos

robot-ultrasonic-upRobot con detector de proximidad mediante ultrasonidos al que nos referimos en este artículo  ya montado y funcionando, nuestro objetivo es el ir probando el funcionamiento de diferentes Shields y aprender a utilizarlos en otros proyectos.

Parte del software se basa en el artículo indicado, pero se ha modificado para adaptarlo al tipo de robot utilizado, el modelo original utilizaba servos de rotación continua y los he substituido por dos motores estandar de 5 a 9 voltios.

También he añadido una plataforma de cámara con dos servos, para poder orientar el sensor de distancia en cualquier posición, así  tambien podemos medir la altura de los obstáculos.

En esta primera versión de código seguimos con un software básico, como para que el robot se mueva por una habitación con bastante fluidez y sin demasiados problemas con los obstáculos.

Iremos avanzando con el software y añadiéndole algunas nuevas shields para mejorar su «inteligencia» y operatividad.

Para completar este interesante proyecto hemos utilizados estos materiales:

Puedes comprar el Kit completo en nuestra tienda

Montaje

Shields conectadasEl montaje es muy sencillo como podéis observar en las fotos, solamente es necesario unir nuestros Arduino UNO con el Screw Shield y este a su vez con el Motor Drive Shield Expansion, no es necesario ningún cable, ni ninguna soldadura adicional.

Para montar el robot tienes que seguir sus instrucciones, hemos utilizado este modelo que pronto vamos a tener en nuestro catálogo, es muy funcional y trae todo listo, incluyendo el portapilas y los motores, el material es de acrílico transparente, pero en mi caso no lo he retirado para evitar rayones durante el desarriyo del prototipo, además permite adherir con cinta de doble cara (yo uso 3M) los elementos como la placa, la plataforma de la cámara, etc.. de forma provisional y cuando el robot esté listo ya podremos poner todos los componentes de forma definitiva utilizando los agujeros que tiene la placa del mini-robot.

Hemos utilizado el Screw Shield para la conexión del sensor de distancia, este shield facilita la conexión a pines ocupado por otros shields y evita la utilización de protoboard, como en este caso que hubíeramos tenido que soldar dos pines en el shield del motor, para poder conectarlo.

Además permite añadir nuevos sensores y actuadores, a medida que el proyecto va creciendo y sin necesidad de desmontar los circuitos que ya están funcionando.

En nuestro caso hemos conectado  he conectado directamente los terminales del sensor ultrasónico directamente al Screw Shield, positivo del sensor al terminal marcado como 5V, el negativo a GND, el trigger al pin 5 y el echo al pin 6.

robot-ultrasonic-headDe todo el manejo de los motores y los servos se encarga el Motor Drive Shield Expansion que permite controlar dos servos y cuatro motores de inducción o dos paso a paso.

Los dos servos van conectados directamente a sus conectores en el Motor Drive Shield, igual que los motores, que van conectados a los terminales marcados como M1 y M2 respectivamente.

La alimentación de todo el circuito, incluyendo Arduino, se hace conectando las baterías también al Motor Drive Shield en los terminales marcados como M+ al positivo y GND al negativo y dejando cerrado el jumper de la placa marcado como PWR

El código

Está todavía en fase beta, con muchos comentarios y cosas por ordenar, pero funciona y su finalidad es que sirva para entender como se manejan, los servos, los motores y el medidor de distancia, a partir de aquí, cada uno se tiene que «fabricar» su propia inteligencia, por ejemplo se le puede añadir unos sensores para convertirlo en un seguidor de línea.

Poco a poco lo ire ampliando, corrigiendo y añadiéndole nuevas funciones que permitan ir conociendo el funcionamiento de los distintos sensores y shields para utilizarlos en tus proyectos.

Utiliza las librerias estándar de servo Arduino , para el sensor y las de J.Rodrigo  y de Adafruit para el motor Shield.

// Adafruit Motor shield library
// copyright Adafruit Industries LLC, 2009
// this code is public domain, enjoy!<
// Ultrasonic - Library for HR-SC04 Ultrasonic Ranging Module.
// Rev.4 (06/2012)
// J.Rodrigo ( http://www.jra.so )
// more info at http://www.ardublog.com<
#include <AFMotor.h>
#include <Servo.h>
#include <Ultrasonic.h>
int pichx = -7; // Ajuste para que mire al centro depende de la montura del servo
int pichy = -20; // Ajuste para que mire al centro depende de la montura del servo
int centerX = 89 + pichx; // Posicion central para Y
int centerY = 89 + pichy; // Posicion central para Y
const int develop_mode = false; // En modo develop no funcionan los motores solo debug en serial
const int scanservopin = 9; // Pin number for scan servo
const int scanservopinY = 10; // Pin number for scan servo
int turntime = 650 ; // Tiempo necesario para dar una vuelta completa.
int turnaroundtime = turntime *2 ;
const int distancelimit = 20; //Limite de distancia a un obejo
const int max_mesure_distance = 100; //Maxima distancia a medir en cm.
AF_DCMotor motor(1,MOTOR12_8KHZ);
AF_DCMotor motor2(2,MOTOR12_8KHZ);
Servo scanservo; //Ping Sensor Servo
Servo scanservoY; //Ping Sensor Servo
// Declare ultrasonic
Ultrasonic ultrasonic(5,6,max_mesure_distance * 58); // (Trig PIN,Echo PIN, Max.TimeOut) centímetros * 58 = Max.TimeOut
int speed = 220;
int pitch = 0; // Diferencia de velocidad para que vaya recto si un motor es mas r´pido que el otro
void setup() {
 Serial.begin(9600); // set up Serial library at 9600 bps
 Serial.println("Robot test!");
 scanservo.attach(scanservopin); // Attach the scan servo
 scanservoY.attach(scanservopinY); // Attach the scan servo
 // turn on motor
 motor.setSpeed(speed);
 motor2.setSpeed(speed+pitch); 
 motor.run(RELEASE);
 motor2.run(RELEASE);
 scan_to_center();
 delay(2000);
} // End setup
void loop() {
 go(); // if nothing is wrong the go forward using go() function below.
 int distance = ping(); // us the ping() function to see if anything is ahead.
 if (distance < distancelimit){
 stopmotors(); // If something is ahead, stop the motors.
 char turndirection = scan(); //Decide which direction to turn.
 switch (turndirection){
 case 'l': {
 turnleft(turntime);
 backward(turntime);
 break;
 }
 case 'r':
 turnright(turntime);
 backward(turntime);
 break;
 case 's':
 turnleft(turnaroundtime);
 break;
 }
 }
} // End Loop<
void go(){
 if ( develop_mode ) {
 ; // Serial.println("Go()");
 }
 else {
 motor.run(FORWARD);
 motor2.run(FORWARD);
 motor.setSpeed(speed); 
 motor2.setSpeed(speed+pitch);
 } 
}
void turnleft(int t){
 if ( develop_mode ) {
 Serial.println("turnleft()");
 }
 else
 {
 motor.run(FORWARD);
 motor2.run(BACKWARD);
 }
 delay(t);
}

void turnright(int t){
 if ( develop_mode ) {
 Serial.println("turnright()");
 }
 else
 { 
 motor.run(BACKWARD);
 motor2.run(FORWARD);
 }
 delay(t);
} 
void forward(int t){
 if ( develop_mode ) {
 Serial.println("forward()");
 }
 else
 {
 motor.run(FORWARD);
 motor2.run(FORWARD);
 }
 delay(t);
}
void backward(int t){
 if ( develop_mode ) {
 Serial.println("backward()");
 }
 else
 {
 motor.setSpeed(speed); 
 motor2.setSpeed(speed-pitch); 
 motor.run(BACKWARD);
 motor2.run(BACKWARD);
 }
 delay(t);
}
void stopmotors(){
 if ( develop_mode ) {
 Serial.println("stopmotors()");
 }
 else
 {
 motor.run(RELEASE);
 motor2.run(RELEASE);
 }
}
// Mira al frente 
void scan_to_center(){
 scanservo.write(centerX);
 scanservoY.write(centerY);
 delay(100); // waits 100ms for the servo to reach the position 
}
// Se le pasa posicion X e Y y mueve los dos servos para posicionar
void movexy(int x, int y){
 scanservo.write(x); // tell servo to go to position in variable 'pos' 
 scanservoY.write(y); // tell servo to go to position in variable 'pos' 
 delay(20); // waits 20ms for the servo to reach the position 
}
int ping(){
 long cm;
 cm = ultrasonic.Ranging(CM);
 // Serial.print("Ping : cm. ");
 // Serial.println(cm);
 return round(cm);
}
char scan(){
 int leftscanval, centerscanval, rightscanval;
 char choice;
 //Look left
 movexy(40,95);
 //scanservo.write(30);
 delay(300);
 leftscanval = ping();
 // look center
 movexy(centerX,centerY);
 delay(300);
 centerscanval = ping();
 //Look right
 movexy(160,95);
 delay(300);
 rightscanval = ping();
 //center scan servo
 scan_to_center();
 Serial.print("leftscanval ");
 Serial.println(leftscanval);
 Serial.print("rightscanval ");
 Serial.println(rightscanval);
 Serial.print("centerscanval ");
 Serial.println(centerscanval);
if (leftscanval>rightscanval && leftscanval>centerscanval){
 choice = 'l';
 }
 else if (rightscanval>leftscanval && rightscanval>centerscanval){
 choice = 'r';
 }
 else{
 choice = 's';
 }
 Serial.print("Choice: ");
 Serial.println(choice);
 return choice;
}

20 comentarios sobre “Robot con Arduino y sensor ultrasónico para calcular las distancias a los objetos cercanos y evitarlos”

    1. No, no difiere mucho, pero creo que no es el más adecuado para este tipo de proyectos, es delicado por los componentes que integra y los robots al principio se dan golpes con todo….

      Te aconsejo que compres un Arduino UNO y lo utilices para tu plataforma de robot, cuando avances un poco con esto, podrás utilizar tu explora para manejar tu robot, que para eso si es mucho más adecuado.

    1. No hay diferencia, excepto que deberás conectar los cables directamente a los pines de tu Arduino, el Screw Shield te facilita mucho el trabajo, ya que te permite hacer conexiones a cualquier pin, aunque tengas una shield conectada.

  1. Buenas tardes, tengo una duda: si un servo encontrara un obstáculo que interrumpiera su movimiento, se podría hacer que se mostrara un fallo mediante un LED y que para que terminase su recorrido tubieramos que accionar un pulsador? para que te hagas una idea, como las ventanillas de algunos coches, que cuando se sube automáticamente y se topa con una mano (por ejemplo), detiene su recorrido y vuelve a bajar. Solo que en mi caso me gustaría que se detubiera en ese punto y para que terminase el recorrido tubieramos que darle a un botón.

    Muchas gracias y disculpa si es mucha molestia.

    1. Es posible de hacerlo mediante el código, puedes utilizar una interrupción, para que cuando se pulsa el botón se ejecute lo que necesites, encender el led, para el motor, etc…

  2. #include
    Ayuda en mi programación no puedo programas varios sensores ultrasonidos
    Servo servo1;
    #include
    int disparo=7;
    int eco=6;
    int disparo1=5;
    int eco1=4;
    int disparo2=3;
    int eco2=2;
    int disparo3=1;
    int eco3=0;

    void setup() {
    Serial.begin(9600);

    servo1.attach(9);
    pinMode(8,OUTPUT);
    pinMode(9,OUTPUT);
    pinMode(10,OUTPUT);
    pinMode(11,OUTPUT);
    }
    void adelante(){
    digitalWrite(8,HIGH);
    digitalWrite(9,LOW);
    digitalWrite(10,HIGH);
    digitalWrite(11,LOW);
    }

    void atras(){
    digitalWrite(8,LOW);
    digitalWrite(9,HIGH);
    digitalWrite(10,LOW);
    digitalWrite(11,HIGH);
    }

    void derecha(){
    digitalWrite(8,HIGH);
    digitalWrite(9,LOW);
    digitalWrite(10,LOW);
    digitalWrite(11,HIGH);
    }

    void izquierda(){
    digitalWrite(8,LOW);
    digitalWrite(9,HIGH);
    digitalWrite(10,HIGH);
    digitalWrite(11,LOW);
    }

    void detener(){
    digitalWrite(8,LOW);
    digitalWrite(9,LOW);
    digitalWrite(10,LOW);
    digitalWrite(11,LOW);
    }

    void loop() {
    long duracion, cm;

    if(160>cm && cm>7){
    pinMode(disparo,OUTPUT);
    digitalWrite(disparo,LOW);
    delayMicroseconds(2);
    digitalWrite(disparo,HIGH);
    delayMicroseconds(5);
    digitalWrite(disparo,LOW);

    pinMode(eco,INPUT);
    duracion = pulseIn(eco,HIGH);
    cm = microsecondsToCentimeters(duracion);
    void adelante();

    }
    if(7>cm && cm>0){
    pinMode(disparo,OUTPUT);
    digitalWrite(disparo,LOW);
    delayMicroseconds(2);
    digitalWrite(disparo,HIGH);
    delayMicroseconds(5);
    digitalWrite(disparo,LOW);

    pinMode(eco,INPUT);
    duracion = pulseIn(eco,HIGH);
    cm = microsecondsToCentimeters(duracion);
    void adelante();
    servo1.write(180);
    }
    if(160>cm && cm>0){

    pinMode(disparo1,OUTPUT);
    digitalWrite(disparo1,LOW);
    delayMicroseconds(2);
    digitalWrite(disparo1,HIGH);
    delayMicroseconds(5);
    digitalWrite(disparo1,LOW);

    pinMode(eco1,INPUT);
    duracion = pulseIn(eco1,HIGH);
    cm = microsecondsToCentimeters(duracion);
    void izquierda();
    delay(6000);

    }
    if(160>cm && cm>0){

    pinMode(disparo2,OUTPUT);
    digitalWrite(disparo2,LOW);
    delayMicroseconds(2);
    digitalWrite(disparo2,HIGH);
    delayMicroseconds(5);
    digitalWrite(disparo2,LOW);

    pinMode(eco2,INPUT);
    duracion = pulseIn(eco2,HIGH);
    long duracion, cm;
    cm = microsecondsToCentimeters(duracion);
    void derecha();
    delay(6000);

    }
    if(160>cm && cm>0){

    pinMode(disparo3,OUTPUT);
    digitalWrite(disparo,LOW);
    delayMicroseconds(2);
    digitalWrite(disparo3,HIGH);
    delayMicroseconds(5);
    digitalWrite(disparo3,LOW);

    pinMode(eco3,INPUT);
    duracion = pulseIn(eco3,HIGH);
    cm = microsecondsToCentimeters(duracion);
    void derecha();
    delay(6000);

    }
    int sensor1 = analogRead (A0);
    int sensor2 = analogRead (A1);

    if(sensor1>800){
    void detener();
    void adelante();
    delay(4000);

    }

    if(sensor2>800){
    void detener();
    void atras();
    delay(4000);

    }
    }
    long microsecondsToCentimeters(long microseconds){
    return microseconds / 29 / 2;
    }

    1. No deberías tener problemas con eso, revisa bien tu código y comprueba que los pines estén correctamente conectados con los sensores, te aconsejo que empieces las pruebas de los sensores sin conectar nada más a tu Arduino.

  3. Hola,estoy empezando a meterme en el mundo de arduino,segun algunos le ponen alimentacion separada,ya que el arduino funciona con 5v, la alimentacion a traves del motor shield que ea mayor, no puede dañar la placa arduino?.
    Gracias desde ya y muy buenos tus proyectos

  4. Conviene hacerlo con un arduino mega porque tiene mas pines o me quedo con el arduino uno mas la expancion, porque al momento de montar el motor shield driver no quedan pines libres. Y una duda, ¿si le pongo una fuente de 9V o 12V no pasaria nada?

Deja una respuesta

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.