Arduino Autonomous Rover Technology Santiapps

Arduino Honduras Santiapps Marcio Valenzuela

Tutorial Robot Autónomo: Parte II

Ahora terminaremos con el proyecto completo!

Requisitos:

  1. Computadora (mac)
  2. Arduino UNO.
  3. Llantas (2)
  4. Motores DC (2)
  5. Sensor Ultrasonico
  6. Mini Servo
  7. Arduino IDE (https://www.arduino.cc/en/Main/Software)

Primero hagamos un plan de ataque, plan de negocio o plan de diseño.  La idea es la misma, planificar una ruta general de la cual nos podemos salir en cualquier momento pero que al menos nos da un norte a seguir en caso de no haber excepciones que cambien el juego.

  1. Primero tendremos que crear 4 objetos: 2 motores DC (izquierdo y derecho), 1 motor servo para girar el sensor ultrasonico y 1 sensor ultrasonico.
  2. Antes de tomar la primera medición, asignamos 0 a todo y comenzamos:
    1. Escribímos al servo para que gire “y vea” hacia el frente.
    2. Revisamos el camino frente a nosotros
    3. Arrancamos hacia el frente
    4. Estos pasos los hacemos 1 sola vez al arrancar operaciones.
  3. Luego repetidamente necesitamos:
    1. Revisamos que los motores esten listos al frente en cada ciclo
    2. Revisamos el camino frente a nosotros en cada ciclo
  4. Que significa?

Este algoritmo es sencillo.  Claro uno mas sencillo seria simplemente detener la marcha de ambos DC si hay un obstáculo, pero entonces no seria un robot muy emocionante.  La idea es ir refinando este algoritmo.

Desglosemos las acciones concretas en 4 funciones principales:

  • checkPath()
    • Hacemos un sweep de 144 a 36 (izquierda a derecha)
    • checkForward() se usa para asegurarnos que vemos al frente
    • leemos la distancia con readPing()
    • Si la distancia es < 10cm = checkCourse y salir del sweep
    • Si la distancia es < 20cm = changePath
  • setCourse() – Si maxAngle < 90, turnRight() y vv
    • turnRight() & turnLeft() – Enceder motor1 al frente y vv
  • checkCourse() – retroceder, parar, setCourse()
  • changePath() – Si pos < 90, veerLeft() y vv
    • veerRight() & veerLeft() – Motores girar
  • readPing() – retorna distancia
  • checkForward() & checkBackward()
  • moveForward() & moveBackward – endereza y acelera lentamente
  • moveStop() – all stops

Veremos muchos problemas en al camino que nos exigirán refinar el algoritmo.  Por ejemplo, mediciones falsas.  En realidad no son mediciones falsas pero que tal si la onda del sensor de distancia pega en el suelo?  O que tal si pega en un material que la absorbe?  Esto resultaria en distancias al obstaculo increblemente cercas lo cual detendria el robot anticipadamente o peor, distancias erróneamente largas lo cual hara que el robot se estrelle con algo.  En el caso de una medición falsa momentánea la solución por ejemplo es usar promedios moviles.

Componentes

Arduino Robot Autonomo Movil Motor Shield Tutorial Santiapps Marcio Valenzuela
Arduino Robot Autonomo Movil Motor Shield

El sensor ultrasonido se puede pegar con silicon transparente escolar a la paleta del servo.  El alambrado es sencillo:

  • El servo se conecta a la terminal de Servo2 en la shield
  • El Sensor tiene 4 conexiones
    • Vcc al pin en la shield soldado a la fila 5V
    • GND al pin en la shield soldado a la fila GND
    • Trig al pin en la shield soldado en A5
    • Echo al pin en la shield soldado en A4
  • Luego se conectan los motores DC al shield
    • M1 en la shield al motor derecho
    • M4 en la shield al motor izquierdo
Arduino Tutorial Robot Autonomo Santiapps Marcio Valenzuela
Arduino Tutorial Robot Autonomo

Ahora solo resta conectar la shield sobre la Arduino UNO, el cable USB a la Arduino UNO y subimos la sketch.  Vamos a subir la sketch y no tendremos los motores conectados a las llantas ni mucho menos el chasis.  Solo queremos ver como funciona el sketch.  Una vez cargada a la UNO podremos ver como se mueven los motores.  Se debería mover tanto los DC como el servo.

Ahora podemos desconectar la UNO y comenzar a conectar los motores a las llantas y la UNO/Shield sobre el battery pack para luego montarlo a un chasis sobre las llantas.

Arduino Tutorial Robot Autonomo Motores Llantas Shield Ultrasonic Sensor Santiapps Marcio Valenzuela
Arduino Tutorial Robot Autonomo Motores Llantas Shield Ultrasonic Sensor

Estudiemos el código:

#include <AFMotor.h>
#include <Servo.h>
#include <NewPing.h>
#define TRIG_PIN A4 // Ping del sensor
#define ECHO_PIN A5 // Echo del sensor
#define MAX_DISTANCE 200 // Maxima distancia practica del sensor
#define MAX_SPEED 180 // Maxima velocidad practica de los motores
#define MAX_SPEED_OFFSET 10 // Offset de traction de los motores
#define COLL_DIST 10 // Distancia critica de colisión
#define TURN_DIST COLL_DIST+10 // Distancia de evasion
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE); // Objeto del sensor
AF_DCMotor motor1(1, MOTOR12_1KHZ); // Objeto para motor1 en M1
AF_DCMotor motor2(4, MOTOR12_1KHZ); // Objeto para motor2 en M4
Servo myservo; // Objeto para el servo
int pos = 0; // Inicializamos variables usadas en sketch
int maxDist = 0;
int maxAngle = 0;
int course = 0;
int curDist = 0;
String motorSet = "";
int speedSet = 0;
void setup() {
Serial.begin(9600);
myservo.attach(9); // Pin 9 para servo
myservo.write(90); // Ver frente
checkPath(); // Analizar mapa
motorSet = "FORWARD"; // Flag indicador para motores Forward
moveForward(); // Marcha al frente
}
void loop() {
checkForward(); // Asegurar que vamos marcha al frente
checkPath(); // Analizar mapa
void checkPath() {
Serial.println("Mapeando el camino...");
int curLeft = 0;
int curFront = 0;
int curRight = 0;
int curDist = 0;
myservo.write(144); // Mirar servo a la izquierda
delay(120); // Esperar que llegue el servo
for(pos = 144; pos &gt;= 36; pos-=18) // Loop para mover servo en incrementos de 18
{
myservo.write(pos); // Mover servo a pos
delay(90); // Esperar que servo llegue
checkForward(); // Asegurar que aun marchamos al frente
curDist = readPing(); // Leer distancia al objeto
// ALERTAS
if (curDist &lt; COLL_DIST) { // Peligro, retroceder, parar y buscar camino nuevo
checkCourse();
break; // Salir del loop
}
if (curDist &lt; TURN_DIST) { // Alerta, viremos para no chocar
changePath(); // Cambiar rumbo
}
if (curDist &gt; maxDist) { // Almacenar maxDist &amp; maxAngle
maxAngle = pos;
maxDist = curDist;
Serial.println("curDist &gt; maxDist, maxDist has been set!");
}
}
}
void setCourse() { // Nuevo curso basado en mapa
if (maxAngle &lt; 90) {turnRight();}
if (maxAngle &gt; 90) {turnLeft();}
maxLeft = 0;
maxRight = 0;
maxFront = 0;
}
void checkCourse() { // PELIGRO, vamos a chocar
moveBackward();
delay(500);
moveStop();
setCourse();
}
void changePath() {
if (pos &lt; 90) {veerLeft();} // ALERTA, virar para evadir
if (pos &gt; 90) {veerRight();}
}
int readPing() { // Leer distancia
delay(70);
unsigned int uS = sonar.ping();
int cm = uS/US_ROUNDTRIP_CM;
Serial.println(cm);
return cm;
}
void checkForward() { if (motorSet=="FORWARD") {motor1.run(FORWARD); motor2.run(FORWARD); } } // Asegurar marcha al frente
void checkBackward() { if (motorSet=="BACKWARD") {motor1.run(BACKWARD); motor2.run(BACKWARD); } } // Asegurar marcha atras
void moveStop() { motor1.run(RELEASE); motor2.run(RELEASE);} // Detener
void moveForward() {
motorSet = "FORWARD";
motor1.run(FORWARD); // Marcha al frente
motor2.run(FORWARD); // Marcha al frente
for (speedSet = 0; speedSet &lt; MAX_SPEED; speedSet +=2) // Acelerar lentamente
{
motor1.setSpeed(speedSet+MAX_SPEED_OFFSET);
motor2.setSpeed(speedSet);
delay(5);
}
}
void moveBackward() {
motorSet = "BACKWARD";
motor1.run(BACKWARD); // Marcha a atras
motor2.run(BACKWARD); // Marcha a atras
for (speedSet = 0; speedSet &lt; MAX_SPEED; speedSet +=2) // Acelerar lentamente
{
motor1.setSpeed(speedSet+MAX_SPEED_OFFSET);
motor2.setSpeed(speedSet);
delay(5);
}
}
void turnRight() {
motorSet = "RIGHT";
motor1.run(FORWARD); // Motor 1 al frente
motor2.run(BACKWARD); // Motor 2 atras
delay(400); // run motors this way for 400ms
motorSet = "FORWARD";
motor1.run(FORWARD); // Ambos hacia el frente
motor2.run(FORWARD);
}
void turnLeft() {
motorSet = "LEFT";
motor1.run(BACKWARD); // Motor 1 atras
motor2.run(FORWARD); // Motor 1 al frente
delay(400); // run motors this way for 400ms
motorSet = "FORWARD";
motor1.run(FORWARD); // Ambos hacia el frente
motor2.run(FORWARD); // Ambos hacia el frente
}
void veerRight() {motor2.run(BACKWARD); delay(400); motor2.run(FORWARD);} // Girar solo por 400ms
void veerLeft() {motor1.run(BACKWARD); delay(400); motor1.run(FORWARD);} // Girar solo por 400ms

Ese proyecto se puede ver operando en modo de prueba aquí:

Finalmente agreguemos una “llanta” frontal para ver como se mueve el robot

Nuestro robot comienza a agarrar forma:

  • Comunicación de datos (GPRS)
  • Reconocimiento de voz
  • Camara/PIR

Leave a Reply