Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Сборка робота Wall-E из LEGO с Arduino Nano: пошаговое руководство

Компоненты и материалы

LEGO Wall-E ×1
Arduino Nano R3 ×1
DC-мотор (универсальный) ×2
Двухканальный драйвер двигателей L298N ×1
Двухцветный светодиод (3 вывода) ×1
Инфракрасный датчик ×1
Зуммер (способный играть разные тона) ×1
Крона 9В ×1
Резистор 330 Ом ×3
Перемычки (универсальные) ×20

Необходимые инструменты и станки

Паяльник (универсальный)

Приложения и онлайн-сервисы

Arduino IDE

О проекте

Все знают фильм Wall-E (а если нет — срочно смотрите!) и жёлтого героя, пытающегося очистить Землю. В этом проекте я использовал LEGO-версию нашего маленького друга и научил его избегать препятствий. Это был мой первый проект и отличный опыт изучения основ электроники.

Шаг 1 — Код

Как разработчик ПО по профессии, я подумал о том, чего хочу от него, и начал с кода.

// Эта программа управляет LEGO-роботом Wall-E.
// Wall-E ездит по округе. Увидев препятствие, он останавливается, оглядывается и выбирает другой путь.
// Arduino Nano имеет 21 пин для digitalRead и digitalWrite
// PWM-пины 3, 5, 6, 9, 10, 11 для analogWrite
// Пины 0 и 1 для TTL
// Пины 2 и 3 для внешних прерываний
// Пины 10, 11, 12, 13 поддерживают SPI
// Пин 13 — встроенный светодиод
// Пины 14–21 — аналоговые A0–A7 для analogRead

#define INFRA_RED 9 // может быть любым пином
#define GREEN_LED 7 // любой пин, но нужен резистор, ~220 Ом — или на земле 1 кОм
#define RED_LED 8   // любой пин, но нужен резистор, ~220 Ом — или на земле 1 кОм
#define BUZZER 10   // должен быть PWM-пином для частоты, нужен резистор, ~1 кОм

// MR — правый мотор, ML — левый мотор
#define MR_1 A1 // любой пин, сделаем соответствующими пинам на L298N
#define MR_2 A2
#define MR_ENABLE 5 // PWM-пин для управления скоростью
#define ML_1 A3
#define ML_2 A4
#define ML_ENABLE 6 // PWM-пин для управления скоростью

// Нормальная скорость — максимум
const int NORMAL_SPEED = 255;

void setup() {
  // Сразу после нажатия Reset ждём, чтобы можно было выключить без повреждения от скачков напряжения
  delay(2000);
  // Инициализация светодиодов и зуммера
  pinMode(GREEN_LED, OUTPUT);
  pinMode(RED_LED, OUTPUT);
  // pinMode(BUZZER, OUTPUT); // не обязательно
  // Сброс LED на зелёный
  digitalWrite(RED_LED, LOW);
  digitalWrite(GREEN_LED, HIGH);
  // Пины DC-моторов
  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);
  // LED зелёный
  digitalWrite(RED_LED, LOW);
  digitalWrite(GREEN_LED, HIGH);
  // Проверка препятствий
  if (digitalRead(INFRA_RED) == LOW) { // LOW = препятствие обнаружено
    // LED красный
    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);
      // Писк при заднем ходе 5 секунд
      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); // 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); // C4
  delay(300);
  tone(BUZZER, 330, 250); // E4
  delay(300);
  tone(BUZZER, 392, 250); // G4
  delay(300);
  tone(BUZZER, 523, 500); // C5
  delay(550);
}

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

При отключении работающего мотора могут возникнуть скачки напряжения, повреждающие электронику. Поэтому Wall-E ждёт 2 секунды перед действием. Это значит, что я могу нажать Reset на Arduino и быстро отключить батарею без повреждений.

Он играет мелодию при пробуждении и начинает ехать. Увидев препятствие, останавливается, играет звук «Упс» и оглядывается. Используемый ИК-датчик имеет винтик на задней стороне для настройки дистанции срабатывания. Поэтому в коде нет расчётов расстояния. (Сначала хотел ультразвуковой датчик, но он не влезает в глаза.)

Wall-E сначала проверяет левую сторону, потом правую. Если обе заблокированы — едет назад с писком как строительная техника, затем случайный поворот и продолжение. Если заблокирована только одна сторона — едет на другую. Если обе свободны — выбирает случайно.

Пытался заставить его делать случайные повороты, но эта часть не доделана. Пытаюсь использовать встроенный таймер Arduino. Напишите в комментариях, если есть идеи по оптимизации!

Шаг 2 — Проводка

Первое — встроить ИК-датчик в глаз, чтобы не было заметно. Разобрал его, суперклеем приклеил LEGO-шплинт к датчику (чтобы глаз мог двигаться вверх-вниз), а затем синим пластилином восстановил LEGO-детали вокруг датчика:

Сборка робота Wall-E из LEGO с Arduino Nano: пошаговое руководство

Главное про моторы — достаточный крутящий момент, так как конструкция колёс Wall-E требует значительной силы. Пришлось припаять провода к моторам и закрепить их так, чтобы они надёжно соединялись с LEGO. Разобрал колёса, заказал пакет LEGO Technic-шплинтов, обмотал валы моторов гипсовым пластырем (мягкая лента, которая клеится к коже) и вставил в два шплинта, ставших главными осями каждого колеса. Это работало пару минут, но трение было слишком высоким для клея. К счастью, у Technic-шплинтов по бокам есть желобки, куда пластырь зацепился после пропитки суперклеем.

Сборка робота Wall-E из LEGO с Arduino Nano: пошаговое руководство

Также немного снял грудь, чтобы просунуть светодиод. Затем соединил все детали и Arduino.

Сборка робота Wall-E из LEGO с Arduino Nano: пошаговое руководство

Драйвер моторов в точности влез в его животик:

Сборка робота Wall-E из LEGO с Arduino Nano: пошаговое руководство

Схема тоже не очень понятна, но я постарался цветово кодировать провода для наглядности:

Сборка робота Wall-E из LEGO с Arduino Nano: пошаговое руководство

По соглашению: все красные провода — плюс («дают» электричество), все чёрные — минус («принимают» электричество). Жёлтый провод справа сверху — сигнал ИК-датчика; оранжевый и зелёный — для трёхвыводного двухцветного светодиода; фиолетовые — управление направлением моторов; синие — управление скоростью (к сожалению, в Fritzing не было двух пинов для скорости, поэтому синие провода просто висят в воздухе).

У драйвера моторов был хороший туториал, упрощавший подключение. Проблема — нехватка пинов питания и земли. Я хотел питать моторы прямо через драйвер для максимальной мощности, но как-то нужно было подать 5В на Arduino и ИК-датчик. Сделал то, чего все в интернете говорят не делать: подключил 5В-выход драйвера к 5В-пину Arduino как вход. С моим драйвером я уверен, что он выдаёт стабильные 5В без скачков, способных повредить Arduino. Если подать нестабилизированное питание на этот пин — скорее всего, сгорит что-то. Сначала хотел использовать Vin, но он понижает напряжение до ~3.8В, чего мало для Arduino. Поэтому использовал свободный Vin для питания ИК-датчика 5В (нет разъёмов-разветвителей). Да, в этот момент чувствовал себя как Франкенштейн. Но заработало!

Шаг 3 — Wall-E в действии

Пара видео с демонстрацией:

И здесь тестировал, что будет, если он застрян в углу:

Это был мой первый маленький проект. Теперь планирую оптимизировать проводку и, возможно, добавить сервопривод для поворота головы. Можно даже купить разветвители и меньший драйвер/плату, чтобы всё влезло в животик.

И так Wall-E عاش долго и счастливо. Конец.

Код

Wall_e_control Arduino

Центральный файл управления Wall-E. Базовый, но всё, что ему нужно сейчас.

// Этот код полностью идентичен коду в Шаге 1
// ... (полный код приведён выше)

Схемы

Значение цветов проводов:
red = напряжение (плюс)
black = земля (минус)
yellow = сигнал ИК-датчика
orange и green = подключения красного и зелёного входов светодиода
purple = управление направлением моторов
blue = управление скоростью моторов (в Fritzing не было двух пинов, которые были у моего драйвера, поэтому выглядят как свободные провода)
wall-e2_3P6X71BCnP.fzz

Производственный процесс

  1. Датчик CO2 K30: мониторинг качества воздуха в реальном времени на Arduino
  2. Устройство для общения глухосліпых людей с помощью 1Sheeld и Arduino
  3. Умная копилка: управление монетоприёмником на Arduino Nano
  4. Автоматическая LEGO Star Wars пушка на Arduino Uno
  5. Робот-ускользатор на сервоприводе: сборка на Arduino и HC-SR04
  6. Управление светодиодом по Bluetooth с Arduino: простой DIY-гид
  7. Интеграция ёмкостного сканера отпечатков DFRobot с Arduino или ESP8266
  8. Автономный линий-следующий робот на Arduino UNO
  9. Интерактивный HMI-проект на Nextion с Arduino Mega и датчиками
  10. Роботизированная рука 6 степеней свободы на Arduino Mega с управлением через Nunchuk