Robot 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:
- Arduino Uno
- Base de robot con dos motores.
- Sensor Ultrasonic Module HC-SR04 Distance Measuring Transducer
- Motor Drive Shield Expansion Board L293D
- Screw Shield Screwshield Expansion Board (Opcional)
- Camera Platform Anti-Vibration Camera Mount con servos (Opcional)
Puedes comprar el Kit completo en nuestra tienda
Montaje
El 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.
De 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; }
Y si utiliso un arduino esplora difiere mucho ???
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.
Muy buena entrada!
Gracias, J.Rodrigo, estamos preparando un nuevo artículo con una versión más avanzada de control y con muchos sensores, por supuesto….
Seria muy diferente el montaje sin el «Screw Shield Screwshield Expansion Board»? como tendría que hacerlo? muy buena la pagina y el turorial
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.
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.
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…
#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;
}
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.
Hola
intento compilar el codigo y recibo varios errores.
tienes el código que utilizaste en un fichero para descargar?
me lo podrías pasar?
No deberiás tener ningún error, si nos dices cual es te podremos ayudar a resolverlo.
POR QUE ME SALE UN ERROR :
note: candidate expects 1 argument, 3 provided
no matching function for call to ‘Ultrasonic::Ultrasonic(int, int, int)’
Es muy probable que tengas una librería de Ultrasonic distinta a la usada en este proyecto, solamente tienes que ver cual es el tercer valor y añadirlo a código.
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
Es mejor tener alimentación separada.
También se puede usar la alimentación directa de tu Arduino desde la misma placa de control de motores, suelen tener una salida de 5V
hola,me podrias mandar el codigo ,o decirme que y como podria copiar el codigo al programa arduino
gracias
Podría hacerlo sin los serbos
Si por supuesto, los servos son solamente para enfocar el sensor hacia una dirección.
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?