Робот Мариачи

  • Платформы: Arduino Leonardo ETH
  • Языки программирования: Arduino (C++)
  • Тэги: Arduino Leonardo ETH, робот, уведомитель, маракасы, конструктор ПВХ.

Что это?

В этой статье мы расскажем вам как собрать музыкального робота Мариачи, который умеет подключаться к разным веб-серверам, считывать данные и в зависимости от заданных условий играть на маракасах. А условия могут быть самыми разнообразными:

  • Новое сообщение в социальных сетях
  • Ваше видео набрало очередную сотню просмотров
  • Кто-то хочет добавить вас в друзья

В нашем случае Мариачи будет оповещать нас о новых заказах в магазине Амперка.

Что нам понадобится?

Как собрать?

  1. Возьмите платформу Arduino Leonardo ETH и нижнюю панель кубa (7x7), соедините её с помощью винтов и гаек, так чтобы гайки располагались между панелью и платформой.
  2. Установите Troyka Shield через контактные колодки сверху на Arduino Leonardo ETH.
  3. Боковые панели куба (7x7) соедините с нижней панелью (7x7). Заднюю панель куба (7x3) закрепите между левой и правой панелями внизу, напротив разъёмов USB, Ethernet и внешнего питания платформы Arduino Leonardo ETH, заранее отделив бокорезами секции, мешающие ей устойчиво зафиксироваться.
  4. Возьмите микросервопривод FS90 и с помощью двух специальных панелей для крепления сервоприводов, двух панелей (3x3) и двух панелей (3x2) нашего конструктора сделайте домик для микросервопривода. Это будет плечо робота. Повторите процесс со вторым микросервоприводом.
  5. Из комплектации микросервопривода возьмите качельку овальной формы и через специальную панель (5x2) с вырезом для неё, закрепите к валу сервопривода болтиком также входящим в комплектацию сервомотора. Далее к этой панели с помощью двух панелей конструктора (5x2) и одной панели (6x2) соберите кисть робота. В итоге мы получили руку робота, где кисть — подвижная часть, а плечо — статичная. Повторите процесс со вторым микросервоприводом.
  6. Теперь к левой и правой боковым стенкам куба закрепите руки робота. Подключите микросервоприводы левой и правой руки через 3-проводные шлейфы к 8 и 9 пину Troyka Shield соответственно.
  7. Возьмите два красных светодиода «Пиранья» и прикрутите их с помощью акриловых болтов к панели для крепления двух Troyka-модулей.
  8. Далее используя панель с закреплёнными светодиодами, две панели (6x3) и две панели (3x3) конструктора ПВХ сделайте голову роботу, заранее подключив 3-проводные шлейфы от светодидов.
  9. Возьмите заднюю панель куба (7x2) и установите её между левой и правой панелями в верхней части. Далее возьмите панель крестиков (1x6) и установите между задними панелями (7x3) и (7x2). С помощью заранее выведенных 3-проводных шлейфов из головы робота подключите светодиоды «Пиранья» к 5 и 6 пину Troyka Shield. Установите верхнюю панель куба (7x7) на левую и правую панели.
  10. Так как регулятор напряжения, установленный на плате Arduino Leonardo ETH, не может выдавать ток, обеспечивающий стабильную работу сервомоторов, мы будем запитывать всю конструкцию от отдельного источника питания на 5V. Для этого возьмите гнездо питания 2,1 мм и с помощью проводов «папа-папа» через верхнюю панель куба соедините пин 5V Arduino с плюсом клеммника, а пин GND Arduino с минусом клеммника. В результате должна получиться такая схема:
  11. Возьмите четыре панели крестиков (1x3) и установите две из них на нижнюю часть головы робота, а другие две на верхнюю часть куба.
  12. Установите голову робота через панели крестиков (1x3) на верхнюю панель куба. Соедините переднюю панель куба (6x7) с нижней панелью.
  13. Используя две панели (3x7) и четыре панели (2x4) конструктора ПВХ сделаем ноги для робота.
  14. Поставьте робота на ноги.
  15. Какой же музыкант без инструмента и шляпы. Установите в руки робота маракасы и сделайте для своего Мариачи праздничное сомбреро

Настройка Arduino IDE на работу с платой Arduino Leonardo ETH

Из за конфликта между Arduino LLC и Arduino SRL для работы платы Arduino Leonardo ETH в стандартной Arduino IDE от Arduino.cc, надо выполнить некоторые настройки.

  1. Зайдите в директорию, где установлена Arduino IDE. В стандартной установке она находиться по адресу C:\Program Files\Arduino\.
  2. Далее зайдите в поддиректорию среды Arduino IDE по адресу \hardware\arduino\avr\.
  3. Найдите в ней файл boards.txt и откройте его с помощью любого текстового редактора.
  4. Добавьте в него текст, приведённый ниже.
    ##############################################################
     
    leonardoeth.name=Arduino Leonardo ETH
    leonardoeth.vid.0=0x2a03
    leonardoeth.pid.0=0x0040
    leonardoeth.vid.1=0x2a03
    leonardoeth.pid.1=0x8040
     
    leonardoeth.upload.tool=avrdude
    leonardoeth.upload.protocol=avr109
    leonardoeth.upload.maximum_size=28672
    leonardoeth.upload.maximum_data_size=2560
    leonardoeth.upload.speed=57600
    leonardoeth.upload.disable_flushing=true
    leonardoeth.upload.use_1200bps_touch=true
    leonardoeth.upload.wait_for_upload_port=true
     
    leonardoeth.bootloader.tool=avrdude
    leonardoeth.bootloader.low_fuses=0xff
    leonardoeth.bootloader.high_fuses=0xd8
    leonardoeth.bootloader.extended_fuses=0xcb
    leonardoeth.bootloader.file=caterina/Caterina-LeonardoEthernet.hex
    leonardoeth.bootloader.unlock_bits=0x3F
    leonardoeth.bootloader.lock_bits=0x2F
     
    leonardoeth.build.mcu=atmega32u4
    leonardoeth.build.f_cpu=16000000L
    leonardoeth.build.vid=0x2a03
    leonardoeth.build.pid=0x8040
    leonardoeth.build.usb_product="Arduino Leonardo ETH"
    leonardoeth.build.board=AVR_LEONARDO
    leonardoeth.build.core=arduino
    leonardoeth.build.variant=leonardo
    leonardoeth.build.extra_flags={build.usb_flags}
     
    ##############################################################
  5. Перезапустите Arduino IDE.

Ответ веб-сервера Амперки

В данном проекте мы используем метод GET на URL Амперки. Пример ответа сервиса приведён ниже.

HTTP/1.1 200 OK
Server: nginx/1.6.0
Date: Fri, 10 Jul 2015 14:27:55 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 1
Connection: close
 
2

Цифра 2 — это количество необработанных заказов. Наша задача отлавливать эту цифру в приходящих данных с сервера и фиксировать её изменения каждую минуту.

Алгоритм

  • Сразу после подачи питания устанавливаем Ethernet-соединение.
  • Соединяемся с сервером и отправляем ему HTTP-запрос.
  • Считываем все пришедшие данные и находим среди них информацию о количестве заказов.
    • Если это был первый ответ сервера, то записываем текущее количество заказов в переменную, которая будет хранить это значение при новом HTTP-запросе.
  • Если текущее количество заказов больше предыдущего, то робот начнёт молотить маракасами в течении некоторого времени.
    • Если количество заказов больше нуля, зажигаем светодиоды.
    • Иначе — гасим светодиоды.
  • Повторяем HTTP-запрос и его обработку каждую минуту.

Исходный код

Для работы ниже приведённого скетча вам понадобиться скачать и подключить библиотеку Ethernet2.

musicrobot.ino
#include <SPI.h>
// библиотека для подсоединения Arduino Leonardo ETH к Интернету
#include <Ethernet2.h>
// библиотека для работы с сервоприводами
#include <Servo.h>
 
// интервал между отправками HTTP-запроса в миллисекундах
#define INTERVAL 60000
 
// даём разумное имя пинам к которым подключены светодиоды
#define LED_1 5
#define LED_2 6
 
// даём разумное имя пинам к которым подключены сервомоторы
#define SERV_L 8
#define SERV_R 9
 
// создадим два объекта для управления сервоприводами
// левая и правая рука робота
Servo myservo_L;
Servo myservo_R;
 
// MAC-адрес контроллера, напечатан на обратной стороне платы
byte mac[] = { 0x90, 0xA2, 0xDA, 0x10, 0x01, 0x00 };
// впишите сюда адрес вашего сервера
char server[] = "your.server.ru";
// переменная для хранения последнего состояния подключения
boolean lastConnected = false;
// количество заказов
char buff[5] = {0};
// индекс массива buff[]
int i = 0;
 
// первый для проверки первый ли раз был запуск программы
boolean flag = 0;
// состояние работы программы
int state = 0;
 
// переменная для хранения времени работы программы
// с последней отправки HTTP-запроса
long previousMillis = 0;
// переменная для хранения времени работы программы
// с момента запуска функции движения руками
long robotTime = 0;
 
// текущее количество заказов
int value = 0;
// предыдущее количество заказов
int previous_value = 0;
 
// задаем статический IP-адрес
// на тот случай, если у DHCP выдать IP-адрес не получится
IPAddress ip(192, 168, 0, 177);
 
// создаём клиента, который будет подключаться
// к необходимому для нас серверу и порту
// портом по умолчанию для HTTP является 80
EthernetClient client;
 
void setup()
{
  // очищаем буфер
  clearbuff();
  // настраиваем пины светодиодов в режим выхода
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);
 
  // открываем последовательный порт для мониторинга действий в программе
  Serial.begin(9600);
 
  // запускаем Ethernet-соединение:
  if (Ethernet.begin(mac) == 0) {
    // если не удалось сконфигурировать Ethernet при помощи DHCP
    Serial.println("Failed to configure Ethernet using DHCP");
    // продолжать дальше смысла нет, поэтому вместо DHCP
    // попытаемся сделать это при помощи IP-адреса:
    Ethernet.begin(mac, ip);
  }
  // даем Ethernet 3 секунды на инициализацию
  delay(3000);
  // получаем  и выводим локальный IP адрес
  Serial.print("My IP address: ");
  Serial.println(Ethernet.localIP());
 
  // отправляем HTTP-запрос
  httpRequest();
}
 
void loop()
{
  // если от сервера есть какие-нибудь байты,
  // считываем их и выводим в Serial-порт
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
    // отслеживаем в пришедших байтах
    // данных которые показывают количество необработанных заказов
    // в нашем случае пустой строки
    testSymbol(c);
  }
  // если сервер отключился и последнее состояние подключение истинно
  if (!client.connected() && lastConnected) {
    // останавливаем работу клиента
    client.stop();
    lastConnected = false;
    Serial.println();
    Serial.println("Disconnect");
    Serial.println();
    buff[i]='\0';
    value = atoi(buff);
    state = 0;
    // очищаем буфер
    clearbuff();
 
    // если программа выполняется впервые, то
    // записываем текущее количества заказов
    if (flag == 0) {
      previous_value = value;
      flag = 1;
    }
 
    // если текущее количество заказов больше предыдущего
    // вызываем функцию движения руками робота
    if (value > previous_value) {
      robotHands();
    }
    // если текущее количество заказов больше 0
    if (value > 0) {
      // зажгём светодиоды
      digitalWrite(LED_1, HIGH);
      digitalWrite(LED_2, HIGH);
    } else {
      // погасим светодиоды
      digitalWrite(LED_1, LOW);
      digitalWrite(LED_2, LOW);
    }
    // записываем текущее количество заказов
    previous_value = value;
  }
 
  // проверяем не прошел ли нужный интервал времени
  if (millis() - previousMillis > INTERVAL) {
    // отправляем HTTP-запрос
    httpRequest();
    // сохраняем текущее время
    previousMillis = millis();
  }
}
 
// функция отправки HTTP-запроса
void httpRequest()
{
  // если подключение установлено, сообщаем об этом на Serial-порт:
  if (client.connect(server, 80)) {
    Serial.println("Connected");
    // делаем HTTP-запрос:
    // сюда вписывайте свои данные
    client.println("GET /yourorders/ HTTP/1.1");
    client.println("Host: your.server.ru");
    // если ваш сервер не требует авторизации, следующую строчку можете пропустить
    client.println("Authorization: your basic access authentication");
    client.println("Connection: close");
    client.println();
    lastConnected = true;
  } else {
    // если соединения с сервером нет, пишем об этом на Serial-порт:
    Serial.println("Connection failed");
  }
}
// функция очистки буфера
void clearbuff()
{
  for (int t = 0; t < 5; t++) {
    // очищаем буфер,
    // присваивая всем индексам массива значение 0
    buff[t] = 0;
  }
  // для записи с 0 индекса массива
  // после очистки массива
  i = 0;
}
 
// функция отслеживания пустой строки
void testSymbol(char c)
{
  if (c == '\n' && state == 0) {
    // если новый символ «перевод строки»
    // и программа находится в нулевом состоянии
    // переходим в первое состояние
    state = 1;
  } else if (c == '\r' && state == 1) {
    // если новый символ «возврат каретки»
    // и программа находится в первом состоянии
    // переходим во второе состояние
    state = 2;
  } else if (c == '\n' && state == 2) {
    // если новый символ «перевод строки»
    // и программа находится во втором состоянии
    // переходим в третье состояние
    state = 3;
  } else if (state == 3) {
    // если программа в третьем состоянии
    // это значит что пришедшие данные
    // будут содержать информацию о количестве заказов
    // считываем их в массив
    buff[i] = c;
    i++;
  } else {
    state = 0;
  }
}
 
void robotHands()
{
  // сохраняем текущее время работы программы
  robotTime = millis();
  // покаместь не прошла 1 секунда
  while (millis() - robotTime < 5000) {
    // подключаем сервоприводы
    myservo_L.attach(SERV_L);
    myservo_R.attach(SERV_R);
    // зажигаем светодиоды
    digitalWrite(LED_1, HIGH);
    digitalWrite(LED_2, HIGH);
    // устанавливаем угол 120 градусов
    myservo_L.write(120);
    myservo_R.write(120);
    // ждём 300 миллисекунд
    delay(300);
    // гасим светодиоды
    digitalWrite(LED_1, LOW);
    digitalWrite(LED_2, LOW);
    // устанавливаем угол 60 градусов
    myservo_L.write(60);
    myservo_R.write(60);
    // ждём 300 миллисекунд
    delay(300);
  }
  // останавливаем сервомоторы
  myservo_L.detach();
  myservo_R.detach();
}

Демонстрация работы устройства

Что дальше?

В данном проекте можно использовать любую другую плату с выходом в интернет. Если у вас, например, уже есть Iskra Neo, можно добавить к ней Ethernet Shield 2 или даже GPRS Shield, немного изменив скетч. Так как светодиоды подключены к пинам, поддерживающим ШИМ, вы можете плавно регулировать их яркость в зависимости от вашей задачи. А добавив ещё один сервопривод можно заставить робота вращать головой.