Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Construye un Robot Wall-E de LEGO con Arduino Nano: Guía Paso a Paso

Componentes y suministros

LEGO Wall-E ×1 Tuve que conseguir uno de segunda mano porque ya no los fabrican
Arduino Nano R3 ×1
Motor DC (genérico) ×2
Controlador de Motor Dual L298N ×1
LED Bicolor ×1 con 3 pines
Sensor Infrarrojo ×1
Zumbador (Buzzer) ×1 Uno que pueda tocar diferentes tonos
Batería 9V ×1
Resistencia 330 ohm ×3
Cables jumper (genéricos) ×20

Herramientas y máquinas necesarias

Aplicaciones y servicios en línea

Sobre este proyecto

Todo el mundo conoce la película Wall-E (¡y si no, ve a verla ya!) y al héroe amarillo que intenta limpiar la Tierra. En este proyecto, usé una versión de Lego de nuestro pequeño amigo y le enseñé a evitar obstáculos. Este fue mi primer proyecto y una gran experiencia de aprendizaje para entender los fundamentos de la electrónica.

Paso 1 - El Código

Como desarrollador de software de oficio, pensé en qué quería que hiciera y empecé con el código.

// Este programa controla el robot Wall-E de Lego.
// Wall-E conduce por ahí. Cuando ve un obstáculo, se detiene a mirar alrededor y elige otro camino.
// Arduino Nano tiene 21 pines para digitalRead y digitalWrite
// Pines PWM 3, 5, 6, 9, 10, 11 para analogWrite
// Pines 0 y 1 para TTL
// Pines 2 y 3 para interrupciones externas
// Pines 10, 11, 12, 13 para comunicación SPI
// Pin 13 para LED interno
// Pines 14 a 21 son también pines analógicos A0 a A7 para analogRead

#define INFRA_RED 9 // puede ser cualquier pin
#define GREEN_LED 7 // cualquier pin pero necesita resistencia, quizá 220 Ohm - o pin ground 1 kOhm
#define RED_LED 8 // cualquier pin pero necesita resistencia, quizá 220 Ohm - o pin ground 1 kOhm
#define BUZZER 10 // debe ser pin PWM para frecuencia, necesita resistencia, quizá 1 kOhm

// MR es motor derecho, ML es motor izquierdo
#define MR_1 A1 // cualquier pin, hagamos que correspondan a números de pines en shield L298N
#define MR_2 A2
#define MR_ENABLE 5 // necesita ser pin PWM para control de velocidad
#define ML_1 A3
#define ML_2 A4
#define ML_ENABLE 6 // necesita ser pin PWM para control de velocidad

// Velocidad normal al máximo
const int NORMAL_SPEED = 255;

void setup() {
  // justo después de presionar reset, esperar un poco para poder apagarlo sin dañar componentes por picos de voltaje
  delay(2000);
  // inicializar LEDs y buzzer
  pinMode(GREEN_LED, OUTPUT);
  pinMode(RED_LED, OUTPUT);
  // pinMode(BUZZER, OUTPUT); // no necesario
  // reset LED a verde
  digitalWrite(RED_LED, LOW);
  digitalWrite(GREEN_LED, HIGH);
  // pines motor DC
  pinMode(MR_ENABLE, OUTPUT); // motor derecho
  pinMode(MR_1, OUTPUT);
  pinMode(MR_2, OUTPUT);
  pinMode(ML_ENABLE, OUTPUT); // motor izquierdo
  pinMode(ML_1, OUTPUT);
  pinMode(ML_2, OUTPUT);
  // inicializar infrarrojo
  pinMode(INFRA_RED, INPUT);
  // inicializar generador aleatorio para giros aleatorios
  randomSeed(analogRead(0));
  // decir hola
  playHello();
}

void loop() {
  // operaciones normales
  driveForwards(NORMAL_SPEED);
  // LED verde
  digitalWrite(RED_LED, LOW);
  digitalWrite(GREEN_LED, HIGH);
  // comprobar obstáculos
  if (digitalRead(INFRA_RED) == LOW) { // LOW significa obstáculo detectado
    // cambiar LED a rojo
    digitalWrite(GREEN_LED, LOW);
    digitalWrite(RED_LED, HIGH);
    // parar motores
    stopDriving();
    // sonido uh-oh
    playUhOh();
    // comprobar izquierda
    turnLeft(500);
    boolean obstacleLeft = false;
    if (digitalRead(INFRA_RED) == LOW) {
      obstacleLeft = true;
    }
    // volver al centro
    delay(100);
    turnRight(500);
    // esperar un poco, no queremos parecer apurados
    delay(500);
    // comprobar derecha
    turnRight(500);
    boolean obstacleRight = false;
    if (digitalRead(INFRA_RED) == LOW) {
      obstacleRight = true;
    }
    // volver al centro
    delay(100);
    turnLeft(500);
    // ahora ver cómo salir
    if (obstacleLeft && obstacleRight) {
      driveBackwards(NORMAL_SPEED / 3);
      // beep mientras retrocede por 5 segundos
      for (int i = 0; i < 5; i++) {
        tone(BUZZER, 1000, 500);
        delay(1000);
      }
      // para evitar atascarse, girar aleatoriamente antes de continuar
      randomTurn(800, 1600);
    } else if (obstacleLeft) {
      turnRight(1000);
    } else if (obstacleRight) {
      turnLeft(1000);
    } else {
      randomTurn(1000, 1800);
    }
  }
  // cosas aleatorias para más interacción
  int number = random(100); // número aleatorio 0-99
  if (number == 0) {
    randomTurn(200,2000);
  }
}

void driveForwards(int speed) {
  digitalWrite(MR_1, LOW);
  digitalWrite(MR_2, HIGH);
  digitalWrite(ML_1, HIGH);
  digitalWrite(ML_2, LOW);
  setSpeed(speed);
}

void driveBackwards(int speed) {
  digitalWrite(MR_1, HIGH);
  digitalWrite(MR_2, LOW);
  digitalWrite(ML_1, LOW);
  digitalWrite(ML_2, HIGH);
  setSpeed(speed);
}

void turnLeft(int duration) {
  digitalWrite(MR_1, HIGH);
  digitalWrite(MR_2, LOW);
  digitalWrite(ML_1, HIGH);
  digitalWrite(ML_2, LOW);
  setSpeed(NORMAL_SPEED / 2);
  delay(duration);
  stopDriving();
}

void turnRight(int duration) {
  digitalWrite(MR_1, LOW);
  digitalWrite(MR_2, HIGH);
  digitalWrite(ML_1, LOW);
  digitalWrite(ML_2, HIGH);
  setSpeed(NORMAL_SPEED / 2);
  delay(duration);
  stopDriving();
}

void stopDriving() {
  digitalWrite(MR_1, LOW);
  digitalWrite(MR_2, LOW);
  digitalWrite(ML_1, LOW);
  digitalWrite(ML_2, LOW);
  digitalWrite(MR_ENABLE, LOW);
  digitalWrite(ML_ENABLE, LOW);
}

void setSpeed(int speed) {
  speed = constrain(speed, 0, 255);
  analogWrite(MR_ENABLE, speed);
  analogWrite(ML_ENABLE, speed);
}

void randomTurn(int minimum, int maximum) {
  unsigned long time = millis();
  int duration = random(minimum, maximum);
  if (time % 2) {
    turnRight(duration);
  } else {
    turnLeft(duration);
  }
}

void playHello() {
  tone(BUZZER, 262, 250); // Do4
  delay(300);
  tone(BUZZER, 330, 250); // Mi4
  delay(300);
  tone(BUZZER, 392, 250); // Sol4
  delay(300);
  tone(BUZZER, 523, 500); // Do5
  delay(550);
}

void playUhOh() {
  tone(BUZZER, 523, 250); // Do5
  delay(300);
  tone(BUZZER, 415, 500); // Sol#4
  delay(600);
}

Cuando desconectas un motor en marcha, pueden ocurrir picos de voltaje y dañar tu electrónica. Por eso hago que Wall-E espere dos segundos antes de hacer algo. Eso significa que puedo simplemente presionar el botón Reset en el Arduino y desconectar rápidamente la batería sin dañar nada.

Él reproduce una pequeña melodía al despertar y luego empieza a conducir. Cuando ve un obstáculo, se detiene, reproduce un sonido "Uh-oh", y mira alrededor para determinar el mejor camino. El tipo de sensor infrarrojo que usé tiene un tornillo en su parte trasera que permite determinar la distancia a la que crea una señal. Por eso no hay cálculos de distancia en el código. (Quería usar un sensor ultrasónico primero, pero no cabe con sus ojos.)

Wall-E primero verifica si el lado izquierdo está libre, y luego si el derecho está libre. Si ambos lados están bloqueados, retrocede mientras pita como maquinaria pesada en una obra, y luego gira en una dirección aleatoria y continúa. Si solo un lado está bloqueado, continúa por el otro. Si ambos lados están libres, elige uno al azar y continúa su camino.

Intenté que hiciera giros aleatorios, pero esa parte no está del todo completada. Estoy intentando usar el temporizador interno de Arduino. ¡Avísame en los comentarios si tienes idea de cómo optimizarlo!

Paso 2 - Cableándolo

Lo primero fue integrar el sensor infrarrojo en el ojo para que no se note mucho. Lo desarmé, pegué un pin de Lego al sensor (para que su ojo pueda moverse arriba y abajo) y luego usé blu-tack para volver a poner las piezas de Lego alrededor del sensor:

Construye un Robot Wall-E de LEGO con Arduino Nano: Guía Paso a Paso

Lo más importante de los motores era que tuvieran suficiente torque, porque la configuración de las ruedas de Wall-E necesita bastante fuerza para moverse. Tuve que soldar cables a los motores y fijarlos de forma que conectaran de forma segura al Lego. Desarmé sus ruedas, pedí una bolsa llena de pines Technic de Lego, envolví cinta de yeso (¿así se llama? Es como cinta suave que va sobre la piel) alrededor de los ejes de los motores, y los metí en dos pines que se convirtieron en el eje principal de cada rueda. Esto funcionó unos minutos, pero luego la fricción fue demasiado alta para que el pegamento de la cinta aguantara. Por suerte, los pines Technic tienen pequeñas ranuras en el lateral, así que la cinta sí tuvo donde agarrarse, lo cual hicieron felizmente después de empaparse en superpegamento.

Construye un Robot Wall-E de LEGO con Arduino Nano: Guía Paso a Paso

También quité un poco de su pecho para meter el LED. Luego conecté todas las partes y el Arduino.

Construye un Robot Wall-E de LEGO con Arduino Nano: Guía Paso a Paso

El shield del motor justo cabía en su barriga:

Construye un Robot Wall-E de LEGO con Arduino Nano: Guía Paso a Paso

El diagrama no es muy claro tampoco, pero intenté codificar los cables por colores para mejor visión:

Construye un Robot Wall-E de LEGO con Arduino Nano: Guía Paso a Paso

Por convención, todos los cables rojos son positivos ("entregan" electricidad) y todos los negros son negativos ("reciben" electricidad). El cable amarillo en la esquina superior derecha lleva la señal del sensor infrarrojo; los cables naranja y verde son para el LED bicolor de tres pines, los cables morados son para decirle al shield del motor en qué dirección girar los motores, y los cables azules le dicen al shield qué tan rápido girarlos.

El shield del motor tenía un muy buen tutorial que facilitó su conexión y uso. Desafortunadamente, la pieza de Fritzing no tenía los dos pines para configurar la velocidad, así que los cables azules terminan aleatoriamente en el shield en el diagrama.

Un problema más que enfrenté al montarlo todo fue la falta de pines de Voltaje y Tierra. Quería alimentar los motores directamente a través del shield para que obtuvieran la mayor potencia posible, pero de alguna manera tenía que alimentar 5V al Arduino y al sensor infrarrojo también. Así que hice lo que prácticamente todo el mundo en la web dice que no debería hacer: conecté la salida 5V del shield al pin 5V del Arduino como entrada. Ahora con el shield que uso, puedo estar absolutamente seguro de que entrega 5V regulados sin picos feos que puedan dañar mi Arduino. Si conectas una fuente no regulada a ese pin, probablemente frías algo. Quería usar el pin Vin al principio, pero ese tiene un mecanismo interno que regula todo hacia abajo, así que mis 5V habrían pasado a 3.8V más o menos, lo cual no es suficiente para que el Arduino funcione correctamente. En su lugar, usé el Vin libre para alimentar el sensor infrarrojo con 5V, porque no tenía divisores de cable, y sabía que también saldrían 5V de ahí. Sí, empezó a sentirse un poco como Frankenstein en este punto. ¡Pero funcionó!

Paso 3 - Wall-E en Acción

Aquí hay un par de videos mostrándolo en acción.

Y aquí probé qué haría si estaba atrapado en una esquina.

Así que este fue mi primer pequeño proyecto. Ahora planeo optimizar las conexiones de cable y tal vez añadir un motor servo para que pueda girar la cabeza. ¡Incluso podría comprar divisores y un shield de motor y placa más pequeños para que todo quepa en su barriga!

Y así Wall-E vivió feliz para siempre. Fin.

Código

Wall_e_control

// Este programa controla el robot Wall-E de Lego.
// Wall-E conduce por ahí. Cuando ve un obstáculo, se detiene a mirar alrededor y elige otro camino.
// Arduino Nano tiene 21 pines para digitalRead y digitalWrite
// Pines PWM 3, 5, 6, 9, 10, 11 para analogWrite
// Pines 0 y 1 para TTL
// Pines 2 y 3 para interrupciones externas
// Pines 10, 11, 12, 13 para comunicación SPI
// Pin 13 para LED interno
// Pines 14 a 21 son también pines analógicos A0 a A7 para analogRead

#define INFRA_RED 9
#define GREEN_LED 7
#define RED_LED 8
#define BUZZER 10

// MR es motor derecho, ML es motor izquierdo
#define MR_1 A1
#define MR_2 A2
#define MR_ENABLE 5
#define ML_1 A3
#define ML_2 A4
#define ML_ENABLE 6

const int NORMAL_SPEED = 255;

void setup() {
  delay(2000);
  pinMode(GREEN_LED, OUTPUT);
  pinMode(RED_LED, OUTPUT);
  digitalWrite(RED_LED, LOW);
  digitalWrite(GREEN_LED, HIGH);
  pinMode(MR_ENABLE, OUTPUT);
  pinMode(MR_1, OUTPUT);
  pinMode(MR_2, OUTPUT);
  pinMode(ML_ENABLE, OUTPUT);
  pinMode(ML_1, OUTPUT);
  pinMode(ML_2, OUTPUT);
  pinMode(INFRA_RED, INPUT);
  randomSeed(analogRead(0));
  playHello();
}

void loop() {
  driveForwards(NORMAL_SPEED);
  digitalWrite(RED_LED, LOW);
  digitalWrite(GREEN_LED, HIGH);
  if (digitalRead(INFRA_RED) == LOW) {
    digitalWrite(GREEN_LED, LOW);
    digitalWrite(RED_LED, HIGH);
    stopDriving();
    playUhOh();
    turnLeft(500);
    boolean obstacleLeft = false;
    if (digitalRead(INFRA_RED) == LOW) {
      obstacleLeft = true;
    }
    delay(100);
    turnRight(500);
    delay(500);
    turnRight(500);
    boolean obstacleRight = false;
    if (digitalRead(INFRA_RED) == LOW) {
      obstacleRight = true;
    }
    delay(100);
    turnLeft(500);
    if (obstacleLeft && obstacleRight) {
      driveBackwards(NORMAL_SPEED / 3);
      for (int i = 0; i < 5; i++) {
        tone(BUZZER, 1000, 500);
        delay(1000);
      }
      randomTurn(800, 1600);
    } else if (obstacleLeft) {
      turnRight(1000);
    } else if (obstacleRight) {
      turnLeft(1000);
    } else {
      randomTurn(1000, 1800);
    }
  }
  int number = random(100);
  if (number == 0) {
    randomTurn(200,2000);
  }
}

void driveForwards(int speed) {
  digitalWrite(MR_1, LOW);
  digitalWrite(MR_2, HIGH);
  digitalWrite(ML_1, HIGH);
  digitalWrite(ML_2, LOW);
  setSpeed(speed);
}

void driveBackwards(int speed) {
  digitalWrite(MR_1, HIGH);
  digitalWrite(MR_2, LOW);
  digitalWrite(ML_1, LOW);
  digitalWrite(ML_2, HIGH);
  setSpeed(speed);
}

void turnLeft(int duration) {
  digitalWrite(MR_1, HIGH);
  digitalWrite(MR_2, LOW);
  digitalWrite(ML_1, HIGH);
  digitalWrite(ML_2, LOW);
  setSpeed(NORMAL_SPEED / 2);
  delay(duration);
  stopDriving();
}

void turnRight(int duration) {
  digitalWrite(MR_1, LOW);
  digitalWrite(MR_2, HIGH);
  digitalWrite(ML_1, LOW);
  digitalWrite(ML_2, HIGH);
  setSpeed(NORMAL_SPEED / 2);
  delay(duration);
  stopDriving();
}

void stopDriving() {
  digitalWrite(MR_1, LOW);
  digitalWrite(MR_2, LOW);
  digitalWrite(ML_1, LOW);
  digitalWrite(ML_2, LOW);
  digitalWrite(MR_ENABLE, LOW);
  digitalWrite(ML_ENABLE, LOW);
}

void setSpeed(int speed) {
  speed = constrain(speed, 0, 255);
  analogWrite(MR_ENABLE, speed);
  analogWrite(ML_ENABLE, speed);
}

void randomTurn(int minimum, int maximum) {
  unsigned long time = millis();
  int duration = random(minimum, maximum);
  if (time % 2) {
    turnRight(duration);
  } else {
    turnLeft(duration);
  }
}

void playHello() {
  tone(BUZZER, 262, 250);
  delay(300);
  tone(BUZZER, 330, 250);
  delay(300);
  tone(BUZZER, 392, 250);
  delay(300);
  tone(BUZZER, 523, 500);
  delay(550);
}

void playUhOh() {
  tone(BUZZER, 523, 250);
  delay(300);
  tone(BUZZER, 415, 500);
  delay(600);
}

Esquemáticos

Significado de los colores de cables:
rojo = voltaje (positivo)
negro = tierra (negativo)
amarillo = señal para sensor infrarrojo
naranja y verde = conexiones para entrada LED rojo y verde
morado = control dirección motor
azul = control velocidad motor (desafortunadamente, la pieza Fritzing no tenía los dos pines que mi puente H tenía para estas conexiones, así que parece cables sueltos por el momento)

Proceso de manufactura

  1. Sensor K30 CO₂: Monitorización en tiempo real de la calidad del aire interior
  2. Facilitar la comunicación sordo‑ciego usando 1Sheeld y Arduino
  3. Alcancía Inteligente: Controla un Aceptador de Monedas con Arduino Nano
  4. Construye un lanzador automático LEGO Star Wars con Arduino Uno
  5. Robot evasor de obstáculos con servo: Construcción con Arduino y HC-SR04
  6. Controla un LED por Bluetooth con Arduino – Guía DIY paso a paso
  7. Integración del sensor de huella capacitivo DFRobot (ID809) con Arduino o ESP8266
  8. Robot Seguidor de Línea Autónomo con Arduino UNO: Guía Paso a Paso
  9. Proyecto HMI Interactivo con Nextion, Arduino Mega y Múltiples Sensores
  10. Brazo Robótico de 6 Grados de Libertad Controlado por Nunchuk con Arduino
  11. Control Preciso de Servo con Arduino y MPU6050 (SG90 / MG996R)