Главная chevron_right Наши уроки chevron_right Arduino chevron_right Управление роботом через беспроводной UART

Управление роботом через беспроводной UART

Собираем радиоуправляемого гусеничного робота SMARS на базе Piranha Ultra и модулей HC-12. Корпус печатается на 3D-принтере, управление — через беспроводной UART с пульта на сен...

Видео-обложка запускается при наведении

Описание:

В данном примере мы сделаем радио-управляемого робота при помощи радио модулей HC-12, которые будет передавать и принимать состояния кнопок на пульте управления. Робот будет управляться в режиме трактора: каждая гусеница управляется отдельно. Сделаем мы это при помощи Trema-модулей Сенсорных кнопок и радио-модуля HC-12. Так же мы применим Trema Motor Shield и два мотора 1:200, 50rpm. Корпус робота мы распечатаем на 3D принтере на основе популярной модели робота SMARS (Screwless/Screwed Modular Assemblable Robotic System), файлы стерео-литографии Вы можете найти в разделе Ссылки.

Видео:

Нам понадобится:

Подключение:

Пульт:

Для удобства подключения мы воспользуемся Trema Set Shield. Так же нам понадобятся Battery Shield, Piranha Ultra, пять Trema-модулей Сенсорных кнопок и радио модуль HC-12.

Для начала установим Battery Shield на Piranha Ultra:

Затем установим Trema Set Shield:

Теперь можно установить пять сенсорных кнопок:

И финальной нотой будет радио-модуль HC-12:

Робот:

Для робота мы будем использовать Trema Motor Shield, Battery Shield, Piranha Ultra, Trema-модуль Светодиод и радио модуль HC-12.

Как и при сборке пульта первым делом мы установим Battery Shield:

Затем установим Trema Motor Shild:

Подключим радио модуль HC-12 и модуль светодиода к Trema Motor Shield по следующей таблице:

Trema ShieldHC-12Светодиод
9RX-
8TX-
3S-
2-S

И последним шагом подключим моторы:

Сборка робота:

Для сборки робота нам понадобятся заранее напечатанные детали на 3D принтере. Файлы для печати можно скачать по этой ссылке. Помимо распечатанных файлов, ещё нам понадобятся несколько винтов М3х6 для крепления Trema-модулей к держателю и сборки конструкции держателя. На рисунке ниже показаны все детали, которые необходимо распечатать для сборки робота.

Все детали распечатаны, приступим к сборке. Для начала закрепим ведомые колёса и моторы на корпусе:

Затем устанавливаем ведущие колёса на валы моторов и сборку держателя Trema-модулей в корпус.

И нам остаётся только установить платы управления, собрать и одеть гусеницы. Робот готов!

Скетчи проекта:

Пульт:

#define FRAME_HEADER        0xAA                // Определяем заголовок пакета
#define FRAME_FOOTER        '\n'                // Определяем конец пакета
#define button_left_up      6                   // Определяем номер вывода верхней левой кнопки пульта
#define button_left_down    A0                  // Определяем номер вывода нижней левой кнопки пульта
#define button_right_up     11                  // Определяем номер вывода верхней правой кнопки пульта
#define button_right_down   A3                  // Определяем номер вывода нижней правой кнопки пульта
#define radio_pin           3                   // Определяем номер вывода S модуля
#define button_led_k        2                   // Определяем номер вывода K кнопки переключения светодиода
#define button_led_t        A2                  // Определяем номер вывода T кнопки переключения светодиода
                                                //
byte data[5];                                   // Создаём массив данных для хранения и отправки значений через UART
                                                //
void setup() {                                  //
  Serial1.begin(9600);                          // Инициируем второй аппаратный последовательный порт Piranha Ultra на скорости 9600 бит/сек
  pinMode(button_led_t, OUTPUT );               // Конфигурируем вывод к которому подключен вывод Т кнопки управления светодиодом как выход
  digitalWrite(button_led_t, HIGH);             // Конфигурируем модуль работать в режиме переключателя
}                                               //
                                                //
void loop() {                                   //
  if (digitalRead(button_left_up)) {            // Если зажата верхняя левая кнопка
    data[0] = 1;                                // Записываем единицу в первый элемент массива
  }                                             //
  else if (digitalRead(button_left_down)) {     // Если зажата нижняя левая кнопка
    data[0] = -1;                               // Записываем 255 в первый элемент массива
  }                                             // Если ни одна из правых кнопок не зажата
  else data[0] = 0;                             // Записываем ноль в первый элемент массива
                                                //
  if (digitalRead(button_right_up)) {           // Если зажата верхняя правая кнопка
    data[1] = 1;                                // Записываем единицу во второй элемент массив
  }                                             //
  else if (digitalRead(button_right_down)) {    // Если зажата нижняя правая кнопка
    data[1] = -1;                               // Записываем 255 во второй элемент массива
  }                                             // Если ни одна из правых кнопок не зажата
  else data[1] = 0;                             // Записываем ноль во второй элемент массива
                                                //
  if (digitalRead(button_led)) {                // Если переключатель светодиода в положении вкл
    data[2] = 1;                                // Записываем единицу в третий элемент массива
  }                                             //
  else data[2] = 0;                             // Иначе записываем ноль
                                                //
  Serial1.write(FRAME_HEADER);                  // Выводим заголовок пакета в последовательный порт
  for (int i = 0; i < sizeof(data); i++) {      // Побайтово выводим данные
    Serial1.write(data[i]);                     // в последовательный порт
  }                                             //
  Serial1.write(FRAME_FOOTER);                  // Выводим байт конца пакета в последовательный порт
  delay(100);                                   // Ждём сто миллисекунд
}                                               //

Робот:

#define FRAME_HEADER 0xAA                                       // Определяем заголовок пакета
#define FRAME_FOOTER '\n'                                       // Определяем конец пакета
#define pinH1         7                                         // Определяем номер вывода H1 MotorShield (он управляет направлением 1 мотора)
#define pinE1         6                                         // Определяем номер вывода E1 MotorShield (он управляет скоростью    1 мотора)
#define pinE2         5                                         // Определяем номер вывода E2 MotorShield (он управляет скоростью    2 мотора)
#define pinH2         4                                         // Определяем номер вывода H2 MotorShield (он управляет направлением 2 мотора)
#define radio_pin     3                                         // Определяем номер вывода S радио модуля
#define led_pin       2                                         // Определяем номер вывода S модуля светодиода
                                                                //
uint8_t mSpeed    =   0;                                        // Создаём переменную для хранения скорости моторов
bool    mDirect   =   HIGH;                                     // Создаём переменную для хранения направления моторов
byte    b         =   0;                                        // Создаём переменную для хранения текущего байта последовательного порта
byte    data[5];                                                // Создаём массив для хранения данных пакета
                                                                //
void setup(){                                                   //
  Serial1.begin(9600);                                          // Инициируем второй аппаратный последовательный порт Piranha Ultra на скорости 9600 бит/сек
  pinMode(led_pin, OUTPUT);                                     // Конфигурируем вывод S модуля светодиода как выход
  pinMode(pinH1, OUTPUT);                                       // Конфигурируем вывод pinH1 как выход и
  digitalWrite(pinH1, LOW);                                     // устанавливаем на нём уровень логического нуля
  pinMode(pinE1, OUTPUT);                                       // Конфигурируем вывод pinE1 как выход и
  digitalWrite(pinE1, LOW);                                     // устанавливаем на нём уровень логического нуля
  pinMode(pinE2, OUTPUT);                                       // Конфигурируем вывод pinE2 как выход и
  digitalWrite(pinE2, LOW);                                     // устанавливаем на нём уровень логического нуля
  pinMode(pinH2, OUTPUT);                                       // Конфигурируем вывод pinH2 как выход и
  digitalWrite(pinH2, LOW);                                     // устанавливаем на нём уровень логического нуля
}                                                               //
void loop(){                                                    //
  memset(data, 0, sizeof(data));                                // Обнуляем массив данных
  if (Serial1.available() && Serial1.read() == 0xAA){           // Если в буфере последовательного порта есть данные
    for (int i = 0; (b = Serial1.read()) != FRAME_FOOTER; ++i){ // Читаем байт до тех пор пока он не равен символу конца пакета
    data[i] = b;                                                // Записываем байт в массив
    }                                                           //
    switch (data[0]) {                                          // Проверяем значение первого элемента массива
      case 0x01:                                                // Еcли в элементе 1
      digitalWrite(pinH1, mDirect);                             // Устанавливаем направление
      digitalWrite(pinE1, HIGH);                                // Устанавливаем максимальную скорость вращения
      break;                                                    //
      case 0xFF:                                                // Еcли в элементе -1
      digitalWrite(pinH1, !mDirect);                            // Устанавливаем противоположное направление
      digitalWrite(pinE1, HIGH);                                // Устанавливаем максимальную скорость вращения
      break;                                                    //
      default: digitalWrite(pinE1, 0);                          // Если в элементе не 1 и не -1, останавливаем мотор
    }                                                           //
    switch (data[1]) {                                          // Проверяем значение второго элемента массива
      case 0x01:                                                // Еcли в элементе 1
      digitalWrite(pinH2, mDirect);                             // Устанавливаем направление
      digitalWrite(pinE2, HIGH);                                // Устанавливаем максимальную скорость вращения
      break;                                                    //
      case 0xFF:                                                // Еcли в элементе -1
      digitalWrite(pinH2, !mDirect);                            // Устанавливаем противоположное направление
      digitalWrite(pinE2, HIGH);                                // Устанавливаем максимальную скорость вращения
      break;                                                    //
      default: digitalWrite(pinE2, 0);                          // Если в элементе не 1 и не -1, останавливаем мотор
    }                                                           //
    if (data[2]) digitalWrite(led_pin, HIGH);                   // Если в третьем элементе массива 1, включаем светодиод
    else digitalWrite(led_pin, LOW);                            // Иначе выключаем cветодиод
  }                                                             //
  delay(50);                                                    // Ждём 50 миллисекунд в основном цикле скетча
}                                                               //

Ссылки:

Комплект для повторения проекта

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

Это быстрый ориентир по основным модулям и деталям. Полный список для повторения проекта смотрите в самой статье.

10 позиций
Мотор-редуктор 1:298, 50rpm Миниатюрный 12 мм мотор-редуктор для различных робототехнических проектов Открыть в iArduino Радио модуль 433.4МГц, HC-12 (Trema-модуль) Радио модуль 433.4МГц, 100 каналов, 8 режимов мощности передатчика, UART, антенна 3dBi Открыть в iArduino Piranha Ultra R3 Улучшенный аналог Arduino Uno R3 c микроконтроллером ATmega1284P на ядре AVR для разработки электронных устройств на языке C++ Открыть в iArduino Battery Shield (Li-po, 2300 мА·ч) Battery Shield Открыть в iArduino Светодиод - красный (Trema-модуль) Trema-модуль светодиод красный Открыть в iArduino Trema Set Shield Плата расширения, которая упрощает процесс подключения модулей к Arduino. Открыть в iArduino Motor Shield, 2 канала (до 10.8В, 2А) Позволяющая управлять моторами с напряжением 3-10,8V и током до 2А Открыть в iArduino Сенсорная кнопка (Trema-модуль) Емкостная сенсорная кнопка Открыть в iArduino Светодиод - оранжевый (Trema-модуль) Trema-модуль светодиод красный Открыть в iArduino Trema Shield Плата расширения для удобного подключения периферийных устройств Открыть в iArduino
Все уроки Arduino