Робот следующий за объектом – Arduino

Содержание

Робот Arduino с возможностью сканирования используя Unity 3D

Робот следующий за объектом - Arduino

В этом проекте мы соберём робота на Arduino, работающий с MCU ESP-8266 Node, который обменивается данными с мобильным телефоном (и может передвигаться внутри помещения). На телефоне работает приложение, созданное на движке видеоигр Unity 3D, которое выполняет 3 вещи:

  • Первая функция позволяет Вам управлять роботом с помощью передачи видеопотока на компьютер. Вы можете использовать клавиши со стрелками, чтобы управлять роботом в любом направлении, видеопоток позволяет Вам продолжать движение, даже когда робот скрыт из виду.
  • Вторая функция позволяет роботу отслеживать все, что вы ставите перед ним. Вы можете щелкнуть по экрану, чтобы инициализировать трекер, а затем робот будет следить за этим объектом.
  • Третья функция позволяет Вам управлять роботом с помощью компьютера используя клавиши со стрелками. Приложение использует SDK дополненной реальности, чтобы найти стены и потолок, которые он отправляет обратно на ваш ноутбук, давая вам цифровое представление о окружающей среде среде.

Шаг 1: Что потребуется.

1. ESP-8266 Node MCU – AliExpress

2. Драйвер двигателя L298N: AliExpress

3. Набор проводов для подключения AliExpress

4. Автомобильная полно приводное шасси AliExpress

Приложение на Unity – https://github.com/MatthewHallberg/AR_Robot или Зеркало – https://github.com/robotoss/AR_Robot

Шаг 2: Сборка робота.

Я построил своего робота используя дополнительные части распечатанные на  3D-принтере, которые у меня были, но Вы можете использовать запчасти от DVD или любой другой маленький плоский кусок пластика.

Я использовал шасси с Aliexpress, Вы можете использовать другое шасси для своего проекта, но код Arduino будет немного отличаться. У меня все моторы, стояли в направлении передней части.

В предварительно собранном шасси расположение направления двигателей расположено друг к другу, поэтому просто имейте это в виду.

В любом случае, используйте горячий клей или какой-либо другой клей, чтобы прикрепить ваши двигатели и детали Arduino к шасси.

Приклейте отсек для батареек к нижней части робота. Колеса будут защелкиваться к редукторам двигателя постоянного тока.

У меня есть вторая батарея под моим роботом. Я приклеил горячим клеем usb power bank на нижнею сторону в дополнение к 9-вольтовой батарее для того, чтобы подключить MCU Node отдельно для более продолжительного времени автономной работы во время разработки, но вы можете просто использовать 9-вольтовую батарею, если хотите.

Чтобы удержать телефон на месте, я использовал пластмассовую Г-образную пластину и пластиковый хомут. Я уверен, что есть другие (лучшие) варианты исполнения.

Шаг 3: Схема подключения.

Для подключения моторов и платы Arduino мы будем использовать мост L298N с двойным H, что, помимо прочего, позволяет нам вращать двигатели в разных направлениях, чтобы наш робот мог поворачиваться в любом направлении.

Мощность на входе моста до 12В он имеет встроенный регулятор напряжения, который выводит 5В, идеальное напряжения для питания нашего Arduino.

Подключите все согласно приведенной выше схеме.

Убедитесь, что двигатели направлены в одном направлении.

По существу, двигатели с каждой стороны соединяются друг с другом, поэтому их можно контролировать как один двигатель. Это связано с тем, что в контроллер двигателя можно подключить только 3 двигателя. Даже в этом случае с двумя моторами мы все равно можем заставить робота поворачивать в любом направлении, заставляя обе стороны двигаться в противоположных направлениях.

Шаг 4: Загрузка кода Arduino.

#include #include #include int incomingByte = 0; int speed = 1023;//0 to 1023 int enA = 16;//d0 int in1 = 5;//d1 int in2 = 4;//d2 int enB = 14;//d5 int in3 = 0;//d3 int in4 = 2;//d4 //wifi stuff const char* ssid = “***********************”; // wifi network name const char* password = “*****************”; // wifi network password WiFiUDP Udp; unsigned int localUdpPort = 1998; char incomingPacket[255]; void setup(){ Serial.begin(115200); delay(10); Serial.println(“Motor test!”); // We start by connecting to a WiFi network Serial.print(“Connecting to “); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print(“.”); } Serial.println(“WiFi connected”); Serial.println(“IP address: “); Serial.println(WiFi.localIP()); Serial.println(“Starting UDP”); Udp.begin(localUdpPort); pinMode(enA, OUTPUT); pinMode(enB, OUTPUT); pinMode(in1, OUTPUT); pinMode(in2, OUTPUT); pinMode(in3, OUTPUT); pinMode(in4, OUTPUT); } void right() { digitalWrite(in1, LOW); digitalWrite(in2, HIGH); analogWrite(enA, speed); digitalWrite(in3, LOW); digitalWrite(in4, HIGH); analogWrite(enB, speed); } void left() { digitalWrite(in1, HIGH); digitalWrite(in2, LOW); analogWrite(enA, speed); digitalWrite(in3, HIGH); digitalWrite(in4, LOW); analogWrite(enB, speed); } void forward() { digitalWrite(in1, LOW); digitalWrite(in2, HIGH); analogWrite(enA, speed); digitalWrite(in3, HIGH); digitalWrite(in4, LOW); analogWrite(enB, speed); } void backward() { digitalWrite(in1, HIGH); digitalWrite(in2, LOW); analogWrite(enA, speed); digitalWrite(in3, LOW); digitalWrite(in4, HIGH); analogWrite(enB, speed); } void stop() { digitalWrite(in1, LOW); digitalWrite(in2, LOW); digitalWrite(in3, LOW); digitalWrite(in4, LOW); } void ListenPacketRoutine(){ //listen for packets int packetSize = Udp.parsePacket(); if (packetSize){ int len = Udp.read(incomingPacket, 255); Serial.printf(“UDP packet contents: %s”, incomingPacket); if (incomingPacket[0] == 'f'){ forward(); } else if (incomingPacket[0] == 'b'){ backward(); } else if (incomingPacket[0] == 'l'){ left(); } else if (incomingPacket[0] == 'r'){ right(); } else if (incomingPacket[0] == 's'){ stop(); } } } void ListenKeyboardRoutine(){ if (Serial.available() > 0) { incomingByte = Serial.read(); } switch(incomingByte) { case 's': { stop(); Serial.println(“Stop”); incomingByte='*';} break; case 'f': { forward(); Serial.println(“Forward”); incomingByte='*';} break; case 'b': { backward(); Serial.println(“Backward”); incomingByte='*';} break; case 'r': { right(); Serial.println(“Rotate Right”); incomingByte='*';} break; case 'l': { left(); Serial.println(“Rotate Left”); incomingByte='*';} break; } } void loop() { ListenPacketRoutine(); ListenKeyboardRoutine(); }

Отредактируйте код, чтобы использовать имя и пароль вашей Wi-Fi сети. Мы делаем это, чтобы ваш Node MCU мог подключаться к вашей сети WIFI и отправлять пакеты между телефоном и компьютером.

Шаг 5: Подключение к сети.

Все связь здесь выполнена через WIFI, поэтому убедитесь, что ваш телефон и компьютер подключены к одной локальной сети WIFI.

С помощью USB порта подключите 115200 BAUD к компьютеру, откройте последовательный монитор в программе Arduino IDE до 115200 BAUD.

Нажмите «Сброс» на NODE MCU и дождитесь, когда плата подключится к вашей сети. Он отобразит свой IP-адрес.

Скопируйте это адрес в свой буфер обмена, потому что он нам потребуется в нашем приложении Unity.

Пойдите в мой Github скачайте проект, и откройте его в Unity:

https://github.com/MatthewHallberg/AR_Robot или Зеркало – https://github.com/robotoss/AR_Robot

Шаг 6: Сцена «Камера».

Сначала откройте сцену «Камера». Если Вы посмотрите на сценарий сервера ARCamera,  то поймёте что принцип работы в том что берется видео-канал от Vuforia и передает его на компьютер через TCP.

Сцена «контроллера» – это то, что получает видеопоток, а также позволяет использовать клавиши со стрелками для управления роботом.

Прежде чем Вы сможете использовать это, убедитесь, что ваш телефон и компьютер подключены к одной и той же сети WIFI. Перейдите в игровой объект videoClient и разместите там IP-адрес вашего телефона.

Теперь перейдите на объект игры и введите IP-адрес Node MCU в сценарий отправки сообщения.

Инструкция для запуска сцены не простая, для начала нужно запустить сцену «камеры» на вашем телефоне (мы перейдем к этому позже), а затем, когда она уже запущена, нажмите кнопку воспроизведения на сцене контроллера в редакторе и Вы должны получить контроль над управлением робота. Качество картинки является сверхнизким для производительности, но вы можете изменить его в сценарии сервера сцены «камеры», если хотите.

Шаг 6: Сцена «Сопровождение».

Следующая сцена – «Сопровождение». Эта сцена использует заданные пользователем объекты Vuforia, поэтому Вы можете создать отслеживаемый объект во время использования, если у него есть достаточное количество точек. В настройках робота следуйте за менеджером, не забудьте указать IP-адрес вашего Node MCU в сценарии отправки сообщения.

Когда Вы откроете эту сцена на своем телефоне, поставьте какой-то предмет перед камерой и щелкните по экрану, чтобы инициализировать новый трекер. Если изображение имеет достаточное количество точек, он скажет, что качество изображения будет высоким, и начнется отслеживание.

Я заметил, что при уменьшении мощности аккумулятора — это поведение немного меняется, но, по крайней мере, оно будет работать стабильно какое-то время с новой батареей.

Если мы откроем поведение робота, Вы увидите, что этот скрипт проверяет, находится ли текущий целевой объект изображения в определенном наборе границ, и если он не видит объект, то отправляет команду роботу для перемещения для одного кадра перед остановкой. Движения робота из-за этого не плавные, но движения робота работают довольно прилично.

Шаг 6: Сцена «Сканирования».

Последняя сцена использует ARkit от Apple, потому что я хотел, чтобы робот обнаруживал вертикальные и горизонтальные плоскости (которые Vuforia еще не определяет), поэтому преокт будет работать только на IOS.

Если мы откроем сцену “Сканирования», обязательно измените  IP-адрес своих устройств в сценарий SendMessageBehavior.cs.

Этот скрипт отправляет имя, положение, поворот и масштаб сгенерированных плоскостей обратно на ваш компьютер, когда ARkit создает их. Это получает от сцены MapController, где все поверхности будут отображаться на вашем компьютере.

Здесь обязательно измените IP-адрес вашего Node MCU в сценарий отправки данных, чтобы вы могли управлять им с помощью клавиш со стрелками.

Шаг 7: Установка приложения на телефон.

Сначала перейдите в file -> build settings -> player settings -> и введите любые данные в bundle identifier. Кроме того, убедитесь, что есть данные в поле для описания использования камеры.

Если вы создаете Android-приложение, перейдите к настройкам и переключите свою платформу на Android, снимите Android TV в настройках сборки. Нажмите на – build and run с подключенным телефоном.

Если вы компилируете для  iPhone или iPad, обязательно загрузите Xcode из магазина приложений. Также зарегистрируйте бесплатную учетную запись разработчика Apple с сайта www.apple.developer.com. Перейдите в файл и нажмите build. Откройте файл, который был создан из Xcode и подключите ваш телефон. Выберите команду разработчиков и нажмите кнопку запуска.

Источник

Источник: https://robotos.in/proekty/zemlya/robot-arduino-s-vozmozhnostyu-skanirovaniya-ispolzuya-unity-3d

Урок 33. Обучаем Arduino робота ездить по линии

Робот следующий за объектом - Arduino

В этом уроке мы создадим машинку, которая будет ездить по траектории нарисованной линии, а также останавливаться при обнаружении препятствий.

При создании любого робота, его нужно оснастить датчиками (показания которых будет считывать робот), управляющими модулями (для вывода результатов работы робота), и скетчем (по алгоритму которого должен работать робот). В нашем случае, мы оснастим машинку, тремя аналоговыми датчиками линий и одним ультразвуковым датчиком расстояния, а в роли управляющих модулей выступят два закрепленных к каркасе моторчика, с колёсами на валах.

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

Для реализации проекта нам необходимо установить библиотеку:

О том как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki – Установка библиотек в Arduino IDE.

Схема подключения:

Моторчики подключаются к клеммам M1 (левый мотор) и M2 (правый мотор) расположенным на Motor Sield. Аналоговые датчики линии подключаются к любым аналоговым входам Arduino Uno, в нашем примере используются входы A5 (для правого датчика), A4 (для центрального датчика) и A3 (для левого датчика).

Вывод TRIG ультразвукового датчика расстояния подключается к любому выводу Arduino Uno, в нашем случае вывод D2. Вывод ECHO, при использовании библиотеки iarduino_HC_SR04_int, может подключаться только к тем выводам Arduino Uno, которые используют внешние прерывания, в нашем случае это вывод D3. Все датчики запитаны от напряжения 5 В.

Напряжение питания на Arduino Unoподаётся через Motor Shield (клеммник Vin), для чего нужно установить перемычку, рядом с клеммником, в позицию «Общ. Пит.».

Входы Motor Shield H1 (направление 1 мотора), E1 (ШИМ 1 мотора), E2 (ШИМ 2 мотора), H2 (направление 2 мотора), по умолчанию, подключены к выводам D7, D6, D5 и D4 соответственно, но их можно поменять, сняв перемычку и соединив вывод Motor Shield с нужным выводом Arduino Uno.

Алгоритм работы:

  • Если центральный датчик находится на линии, а боковые вне линии, то машинка едет прямо.
  • Если левый датчик находится на линии, а правый вне линии, то машинка поворачивает налево (независимо от показаний центрального датчика)
  • Если правый датчик находится на линии, а левый вне линии, то машинка поворачивает направо (независимо от показаний центрального датчика)
  • Если правый и левый датчики находятся на линии (вне зависимости от показаний центрального датчика), то такое состояние является неопределённым, машинка продолжает предыдущее движение (прямо или с поворотом) в течении 2 секунд (можно менять в скетче). Если в течении этого времени состояние не изменится, то она остановится.
  • Если все три датчика находятся вне линии, то такое состояние является неопределённым (потеря линии). Если этому состоянию предшествовал поворот, то машинка продолжит поворот в течении 2 секунд (можно менять в скетче). Если в течении этого времени состояние не изменится, то она остановится. Если этому состоянию не предшествовал поворот (машинка ехала прямо и линия оборвалась), то машинка сразу остановится.
  • Если перед машинкой появилось препятствие, на расстоянии менее 10 см (можно менять в скетче), то машинка остановится и продолжит движение, как только препятствие исчезнет.

Скорость движения задаётся в константе valSpeed, от 1 до 255. Крутизна поворотов задаётся в константе valTurning, от 1 до 255. Время продолжения движения, при неопределённом состоянии, задаётся в константе tmrDelay, в микросекундах. Направление движения моторов указывается логическими значениями элементов массива arrRoute (0 элемент – правый мотор, 1 элемент – левый мотор), по умолчанию все элементы равны «1». Если вы перепутали полярность при подключении мотора, то измените значение соответствующего элемента этого массива на «0».

Калибровка для светлых, слабоконтрастных или цветных линий:

Машинка настроена на движение по темной линии, но она может ездить по светлым, слабоконтрастным или цветным линиям.

Для этого её нужно откалибровать, указав значения для констант valSensor1 (показание датчика находящегося на линии) и valSensor0 (показание датчика находящегося вне линии).

Для чего, в коде setup скетча, предусмотрен вывод показаний центрального датчика в монитор последовательного порта.

  • Поместите машинку так, чтобы центральный датчик находился над линией.
  • Подключите Arduino Uno по USB кабелю.
  • Откройте монитор последовательного порта. В мониторе высветится показание датчика на линии.
  • Поместите машинку так, чтобы центральный датчик находился вне линии.
  • Нажмите кнопку reset на Motor Shield. В мониторе высветится показание датчика вне линии.
  • Укажите первое значение константе valSensor1, а второе значение константе valSensor0 и повторно загрузите скетч.

Код программы:

// БИБЛИОТЕКИ:#include // подключаем библиотеку для работы с датчиком// НОМЕРА ВЫВОДОВ:const uint8_t pinSensorL = A3; // Вывод к которому подключен датчик находящийся слева (по направлению движения)const uint8_t pinSensorC = A4; // Вывод к которому подключен датчик находящийся по центру (по направлению движения)const uint8_t pinSensorR = A5; // Вывод к которому подключен датчик находящийся справа (по направлению движения)const uint8_t pinSens_TRIG = 2; // Вывод к которому подключен датчик расстояния HC_SR04 (вывод обозначенный на датчике как TRIG)const uint8_t pinSens_ECHO = 3; // Вывод к которому подключен датчик расстояния HC_SR04 (вывод обозначенный на датчике как ECHO)const uint8_t pinShield_LH = 7; // Вывод направления к которому подключен левый мотор (по направлению движения)const uint8_t pinShield_LE = 6; // Вывод ШИМ к которому подключен левый мотор (по направлению движения)const uint8_t pinShield_RE = 5; // Вывод ШИМ к которому подключен левый мотор (по направлению движения)const uint8_t pinShield_RH = 4; // Вывод направления к которому подключен левый мотор (по направлению движения)// ОБЪЕКТЫ:iarduino_HC_SR04_int hcsr(pinSens_TRIG, pinSens_ECHO); // Объект hcsr для работы с библиотекой iarduino_HC_SR04 (вывод TRIG, вывод ECHO)// УСТАНАВЛИВАЕМЫЕ ЗНАЧЕНИЯ:const uint16_t valSensor1 = 930; // Показание датчика находящегося на линии (указывается для конкретной трассы)const uint16_t valSensor0 = 730; // Показание датчика находящегося вне линии (указывается для конкретной трассы)const uint8_t valSpeed = 255; // Максимальная скорость (число от 1 до 255)const uint32_t tmrDelay = 2000; // Время в течении которого требуется остановиться (если в течении этого времени состояние остаётся неопределённым (линия не обнаружена), то требуется остановиться)const uint8_t valTurning = 10; // Крутизна поворотов (скорость реакции) (число от 1 до 255)const uint8_t valDistance = 20; // Минимально допустимое расстояние до объекта в сантиметрах (если расстояние будет меньше, то требуется остановитьтся)const bool arrRoute[2] = {1,1}; // Направление движения для каждого мотора (зависит от полярности, нулевой элемент – правый мотор, первый элемент – левый мотор)// РАССЧИТЫВАЕМЫЕ ЗНАЧЕНИЯ: uint8_t arrSpeed[2]; // Рассчитываемая скорость для каждого мотора (число от 1 до valSpeed, нулевой элемент – правый мотор, первый элемент – левый мотор) uint16_t valSensorM; // Рассчитываемое среднее значение датчика (значение между цветом линии и цветом вне линии) uint8_t valSensor; // Биты рассчитываемых логических уровней всех датчиков (0bxxxxxLCR) bool flgLine; // Флаг указывающий на то, что используется светлая линия (0 – тёмная линия, 1 – светлая линия) int8_t flgTurning; // Флаг наличия и направления поворота (0 – не поворачиваем, -1 – поворачиваем налево, +1 – поворачиваем направо) bool flgPWM; // Флаг указывающий на то, что требуется изменить ШИМ моторов (0 – тёмная линия, 1 – светлая линия) bool flgStop; // Флаг указывающий на необходимость остановиться (0 – без остановки, 1 – требуется остановиться) bool flgDistance; // Флаг обнаружения препятствия (0 – не обнаружено, 1 – обнаружено) uint32_t tmrMillis; // Время совершения последней операции (в миллисекундах)void setup(){// Узнаём цвет линии используемой на трассе, если он светлый, то устанавливаем флаг lineColor тёмный flgLine = (valSensor0>valSensor1); // Если условие (valSensor0>valSensor1) выполняется значит линия светлая и флаг flgLine установится в 1, иначе он сбросится в 0// Вычисляем среднее значение между показаниями датчиков на линии и все линии if(flgLine){valSensorM=valSensor1+(valSensor0-valSensor1)/2;} // Если на трассе используется светлая линия else {valSensorM=valSensor0+(valSensor1-valSensor0)/2;} // Если на трассе используется тёмная линия// Устанавливаем значение скорости обоих моторов arrSpeed[1]=valSpeed; // Максимальная скорость на левом моторе arrSpeed[0]=valSpeed; // Максимальная скорость на правом моторе// Устанавливаем флаг ШИМ, сбрасываем флаг наличия поворота, флаг остановки и флаг обнаружения припятствий flgPWM=1; flgTurning=0; flgStop=0; flgDistance=0;// Устанавливаем режим работы выводов и направление обоих моторов pinMode (pinSensorL, INPUT ); // Конфигурируем вывод pinSensorL как вход (для получения данных от левого датчика линии) pinMode (pinSensorC, INPUT ); // Конфигурируем вывод pinSensorC как вход (для получения данных от центрального датчика линии) pinMode (pinSensorR, INPUT ); // Конфигурируем вывод pinSensorR как вход (для получения данных от правого датчика линии) pinMode (pinShield_LH, OUTPUT ); // Конфигурируем вывод pinShield_LH как выход (для управления направлением движения левого мотора) pinMode (pinShield_LE, OUTPUT ); // Конфигурируем вывод pinShield_LE как выход (для управления скоростью вращения левого мотора, при помощи ШИМ) pinMode (pinShield_RE, OUTPUT ); // Конфигурируем вывод pinShield_RE как выход (для управления скоростью вращения правого мотора, при помощи ШИМ) pinMode (pinShield_RH, OUTPUT ); // Конфигурируем вывод pinShield_RH как выход (для управления направлением движения правого мотора) digitalWrite(pinShield_LH, arrRoute[1]); // Устанавливаем на выходе pinShield_LH уровень arrRoute[1] (направление движения левого мотора) digitalWrite(pinShield_RH, arrRoute[0]); // Устанавливаем на выходе pinShield_RH уровень arrRoute[0] (направление движения правого мотора)// Выводим показания центрального датчика линии Serial.begin(9600); while(!Serial){} // Инициируем передачу данных по последовательному порту (на скорости 9600 бит/сек) Serial.println(analogRead(pinSensorC)); // Выводим показания центрального датчика линии (для указания значений константам valSensor0 и valSensor1)// Устанавливаем задержку и обновляем время совершения последней операции delay(2000); tmrMillis = millis();}void loop(){// Читаем показания датчиков и преобразуем их в логические уровни // (1 – датчик на линии, 0 – датчик вне линии) valSensor = 0; // сбрасываем все биты переменной valSensor valSensor |= ((analogRead(pinSensorL)>valSensorM)flgLine)

Источник: https://lesson.iarduino.ru/page/urok-33-obuchaem-arduino-robota-ezdit-po-linii

Ведроид-мобиль — робот на Arduino — Часть 4. Подключаем ультразвуковой дальномер

Робот следующий за объектом - Arduino

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

А прошлой статье я описывал процесс реализации управления роботом по Bluetooth через смартфон на Android. Это был первый режим работы робота. После этой статьи у нас появится второй режим. В будущем я планирую добавить еще несколько.

Создание шилда управления роботом

Для переключения между различными режимами работы я решил сделать отдельный шилд. В прошлый раз я уже использовал Proto Shield. Сегодня я его немного модернизирую под свои потребности.

Для этого нам понадобятся следующие детали:

  • Светодиоды – 7 штук
  • Кнопки – 3 штуки
  • Резисторы на 220 Ом – 6 штук
  • Резисторы на 10 кОм – 2 штуки
  • Перемычки – 5 штук
  • Разъём PBS (мама) на 16 контактов – 1 штука
  • Миниатюрная макетная плата – 1 штука

Все компоненты запаиваем на Proto Shield по указанной схеме (вид со стороны деталей):

Размещение элементов на плате:

В левом нижнем углу я вывел кнопку RESET. Она замыкает выводы RESET и GND. В левом верхнем – разъем подключения сервоприводов. Вверху светодиод с 13 дискретного вывода. Справа 2 кнопки переключения режимов (след / пред).

Каждая кнопка подтянута к земле резистором на 10 кОм.

Далее размещены 6 светодиодов, которые подключены к панельке контактов через резисторы на 220 Ом.

Светодиоды будут служить индикаторами режимов работы робота.

Для разводки дополнительных модулей, я еще решил добавить в шилд управления миниатюрную макетную плату.

Подключение шилда управления роботом

Подключим провода к разъему на 16 контактов. Описывать буду назначение контактов сверху вниз. LED 1..6 – выводы светодиодов, BTN 1..2 – кнопки.

  • 1 – LED 1 – к 22 дискретному выводу Arduino
  • 2
  • 3
  • 4 – LED 2 – к 23 дискретному выводу Arduino Mega 2560
  • 5
  • 6 – BTN 1 – к 28 дискретному выводу Arduino Mega 2560
  • 7 – LED 3 – к 24 дискретному выводу Arduino Mega 2560
  • 8 – GND – к GND Arduino Mega 2560
  • 9 – +5 V – к +5 V Arduino Mega 2560
  • 10 – LED 4 – к 25 дискретному выводу Arduino Mega 2560
  • 11 – BTN 2 – к 29 дискретному выводу Arduino Mega 2560
  • 12
  • 13 – LED 5 – к 26 дискретному выводу Arduino Mega 2560
  • 14
  • 15
  • 16 – LED 6 – к 27 дискретному выводу Arduino Mega 2560

Сразу восстановим подключение Bluetooth модуля JY-MCU к Arduino Mega 2560

  • VCC на JY-MCU подключаем к +5В Arduino
  • GND на JY-MCU подключаем к GND Arduino
  • TXT на JY-MCU подключаем к дискретному PIN 50 на Arduino
  • RXD на JY-MCU подключаем к дискретному PIN 51 на Arduino

Подключение ультразвукового дальномера HC-SR04

Процесс подключения ультразвукового дальномера HC-SR04 к Arduino  и работу с ним я описывал ранее. В тонкости в этот раз вдаваться не буду, а лучше подробно распишу как я его закрепил на сервоприводе.

Для создания крепления под ультразвуковой дальномер HC-SR04 я использовал кусок платы от Proto Shield и панельку контактов.

Откусил от панельки контактов две части по 4 контакта и запаял их на плату параллельно.

Перед подключением дальномера я сперва “раскорячил” его контакты, чтобы они плотно держались в разъеме.

Проковырял в плате дырку под болт.

Закрепил модуль на сервоприводе.

В результате у меня получился такой девайс.

Осталось только подключить провода к контактной панельке на плате дальномера и завести их на контакты Arduino Mega 2560. Этим и займемся.

  • VCC HC-SR04 подключим к +5V на Arduino Mega 2560
  • Trig HC-SR04 к цифровому пину 31 на Arduino Mega 2560
  • Echo HC-SR04 к цифровому пину 30 на Arduino Mega 2560
  • GND HC-SR04 к GND на Arduino Mega 2560

Алгоритм объезда препятствий

С алгоритмом я особо не заморачивался. Все достаточно просто и интуитивно понятно.

Из исходного положения проверяем расстояние впереди. Если оно больше 30 сантиметров, то продолжаем двигаться вперед, иначе:

  • останавливаем двигатели
  • поворачиваем сервопривод на углы от 0 до 180 градусов с шагом в 15 градусов и измеряем расстояния на этих углах
  • заносим полученные значения в массив
  • поворачиваем сервопривод на угол 90 градусов (прямо)
  • ищем в массиве позицию с максимальным значением данных
  • если это значение меньше 30 сантиметров, то едем назад
  • если это значение больше 30 сантиметров, то проверяем какому углу поворота сервопривода оно соответствует и в зависимости от этого поворачиваем влево или вправо

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

Скетч реализации алгоритма объезда препятствий

#include // Подключаем библиотеку для управления двигателями#include    // Подключаем библиотеку для сервоприводов

#include // Подключаем библиотеку для работы с Serial через дискретные порты

//Создаем объекты для двигателейAF_DCMotor motor1(1); //канал М1 на Motor Shield — задний левыйAF_DCMotor motor2(2); //канал М2 на Motor Shield — задний правыйAF_DCMotor motor3(3); //канал М3 на Motor Shield — передний левыйAF_DCMotor motor4(4); //канал М4 на Motor Shield — передний правый// Создаем объект для сервоприводаServo vservo;// Прописываем пины используемые модулем BluetoothSoftwareSerial BTSerial(50, 51); // RX, TX// Создаем переменную для команд Bluetoothchar vcmd;// Создаем переменные для запоминания скорости левых и правых двигателейint vspdL, vspdR;/* Создаем переменную, на значение которой будет уменьшаться скорость при плавных поворотах.Текущая скорость должна быть больше этого значения.  В противном случае двигатели со стороны направления поворота просто не будут вращаться */const int vspd = 200;// Заносим в массив пины, к которым подключены светодиодыconst int vledpins[6]={22,23,24,25,26,27};// Создаем переменную для сохранения режима работыint vmode;// Создаем переменную для сохранения предыдущего режима работыint vmodeprev = -1;// Заносим в массив пины, к которым подключены кнопкиconst int vbtn[2]={28,29};// Массив для хранения углов поворота сервопривода (шаг 15 градусов)const int vservo_array[13]={0,15,30,45,60,75,90,105,120,135,150,165,180};// Массив для хранения данных о расстоянии под различными углами поворота сервоприводаint vHC_SR04_array[13];// Пины, используемые ультразвуковым дальномеромconst int vTrig = 31;const int vEcho = 30;// Переменные, для хранения данных с дальномераunsigned int vtime_us=0;unsigned int vdistance_sm=0;// Минимальное расстояние в сантиметрах, при котором нужно искать новый маршрут движенияconst int vmindistance = 30;// Переменная для циклов перебора значения массивов vservo_array и vHC_SR04_arrayint vservo_int;// Переменные для цикла поиска максимального значения в массивахint vmaxarrayindex_int;

int vmaxarrayvalue_int;

void setup() {// Устанавливаем скорость передачи данных по BluetoothBTSerial.begin(9600);// Устанавливаем скорость передачи данных по кабелюSerial.begin(9600);// Выбираем пин к которому подключен сервоприводvservo.

attach(9); // или 10, если воткнули в крайний разъём// Поворачиваем сервопривод в положение 90 градусов при каждом включенииvservo.write(90);// Устанавливаем максимальную скорость вращения двигателейvspeed(255,255);/* Устанавливаем все выводы, к которым подключены светодиоды,в OUTPUT. Зажигаем и гасим светодиоды с интервалом в 0.

5 секдля проверки */for (vmode = 0; vmode < 6; vmode = vmode + 1) {pinMode(vledpins[vmode], OUTPUT);digitalWrite(vledpins[vmode], HIGH);delay (500);digitalWrite(vledpins[vmode], LOW);}/* Устанавливаем выводы, к которым подключены кнопки, в INPUT.

*/pinMode(vbtn[0], INPUT);pinMode(vbtn[1], INPUT);// Устанавливаем значение первого режима работы роботаvmode = 0;// Устанавливаем значение для пинов, к которым подключен ультразвуковой дальномерpinMode(vTrig, OUTPUT);pinMode(vEcho, INPUT);

}

void loop() {/* Переключение режимов работы робота */// Кнопка переключения на следующий режим – BTN1if (digitalRead(vbtn[0]) == HIGH) {vmode = vmode + 1;vmodeprev = vmode – 1;if (vmode > 5) {vmode = 0;vmodeprev = 5;}vrelease();delay (500);}// Кнопка переключения на предыдущий режим – BTN2if (digitalRead(vbtn[1]) == HIGH) {vmode = vmode – 1;vmodeprev = vmode + 1;if (vmode < 0) {vmode = 5;vmodeprev = 0;}vrelease();delay (500);}// Засвечиваем светодиод текущего режима работыdigitalWrite(vledpins[vmode], HIGH);// Гасим светодиод предыдущего режима работыif (vmodeprev > -1) {digitalWrite(vledpins[vmodeprev], LOW);}/* Выбор режима работы */switch (vmode) {case 0:// Режим ожиданияbreak;case 1:// Режим работы с использованием ультразвукового дальномераvultrasoundmode();break;case 2:// Режимbreak;case 3:// Режим управления через Bluetoothvbluetoothmode();break;case 4:// Режимbreak;case 5:// Режимbreak;}}/* Режим работы с использованием ультразвукового дальномера */void vultrasoundmode(){vservo.write(90);delay(200);Serial.print(“Now “);Serial.println(vHC_SR04());// Если расстояние меньше наименьшего, тоif (vHC_SR04() < vmindistance) {// Останавливаем двигателиvrelease();// Крутим серву измеряя расстояния и занося данные в массивfor (vservo_int = 0; vservo_int < 13; vservo_int = vservo_int + 1) {vservo.write(vservo_array[vservo_int]);delay(200);vHC_SR04_array[vservo_int] = vHC_SR04();// Выводим данные для отладкиSerial.print(vservo_int);Serial.print(" ");Serial.println(vHC_SR04_array[vservo_int]);}vservo.write(90);delay(500);// Поиск в массиве позиции с максимальным значениемvmaxarrayindex_int = 0;vmaxarrayvalue_int = 0;for (vservo_int = 0; vservo_int < 13; vservo_int = vservo_int + 1) {if (vHC_SR04_array[vservo_int] > vmaxarrayvalue_int) {vmaxarrayindex_int = vservo_int;vmaxarrayvalue_int = vHC_SR04_array[vservo_int];}}Serial.print(“Max index “);Serial.println(vmaxarrayindex_int);// Проверка – если максимальное значение массива меньше минимального расстояния, то едем назадif (vHC_SR04_array[vmaxarrayindex_int] < vmindistance) {vbackward();delay(500);}/* Проверка - если индекс максимального значения массива меньше 6 то поворачиваем вправо,иначе влево */if (vmaxarrayindex_int < 6) {vright();delay(500);}else{vleft();delay(500);}}else{// Едем прямоvforward();}

}

/* Режим управления через Bluetooth */void vbluetoothmode() {// Если есть данные с Bluetoothif (BTSerial.available()){/* Читаем команды и заносим их в переменную.(char) преобразует код символа команды в символ */vcmd = (char)BTSerial.read();// Отправляем команду в порт, чтобы можно было их проверить в “Мониторе порта”

Serial.println(vcmd);

// Впередif (vcmd == 'F') {vforward();}// Назадif (vcmd == 'B'){vbackward();}// Влевоif (vcmd == 'L'){vleft();}// Вправоif (vcmd == 'R'){vright();}// Прямо и влевоif (vcmd == 'G'){vforwardleft();}// Прямо и вправоif (vcmd == 'I'){vforwardright();}// Назад и влевоif (vcmd == 'H'){vbackwardleft();}// Назад и вправоif (vcmd == 'J'){vbackwardright();}// Стопif (vcmd == 'S'){vrelease();}// Скорость 0%if (vcmd == '0'){vspeed(0,0);}// Скорость 10%if (vcmd == '1'){vspeed(25,25);}// Скорость 20%if (vcmd == '2'){vspeed(50,50);}// Скорость 30%if (vcmd == '3'){vspeed(75,75);}// Скорость 40%if (vcmd == '4'){vspeed(100,100);}// Скорость 50%if (vcmd == '5'){vspeed(125,125);}// Скорость 60%if (vcmd == '6'){vspeed(150,150);}// Скорость 70%if (vcmd == '7'){vspeed(175,175);}// Скорость 80%if (vcmd == '8'){vspeed(200,200);}// Скорость 90%if (vcmd == '9'){vspeed(225,225);}// Скорость 100%if (vcmd == 'q'){vspeed(255,255);}}

}

/* Функция определения расстояния с дальномера */int vHC_SR04() {digitalWrite(vTrig, HIGH); // Подаем сигнал на выход микроконтроллераdelayMicroseconds(10); // Удерживаем 10 микросекундdigitalWrite(vTrig, LOW); // Затем убираемvtime_us=pulseIn(vEcho, HIGH); // Замеряем длину импульсаvdistance_sm=vtime_us/58; // Пересчитываем в сантиметрыreturn vdistance_sm; // Возвращаем значение

}

/* Функции управления двигателями */

// Впередvoid vforward() {vspeed(vspdL,vspdR);vforwardRL();

}

// Вперед для RLvoid vforwardRL() {motor1.run(FORWARD);motor2.run(FORWARD);motor3.run(FORWARD);motor4.run(FORWARD);

}

// Назадvoid vbackward() {vspeed(vspdL,vspdR);vbackwardRL();

}

// Назад для RLvoid vbackwardRL() {motor1.run(BACKWARD);motor2.run(BACKWARD);motor3.run(BACKWARD);motor4.run(BACKWARD);

}

// Влевоvoid vleft() {vspeed(vspdL,vspdR);motor1.run(BACKWARD);motor2.run(FORWARD);motor3.run(BACKWARD);motor4.run(FORWARD);

}

// Вправоvoid vright() {vspeed(vspdL,vspdR);motor1.run(FORWARD);motor2.run(BACKWARD);motor3.run(FORWARD);motor4.run(BACKWARD);

}

// Вперед и влевоvoid vforwardleft() {if (vspdL > vspd) {vspeed(vspdL-vspd,vspdR);}else{vspeed(0,vspdR);}vforwardRL();

}

// Вперед и вправоvoid vforwardright() {if (vspdR > vspd) {vspeed(vspdL,vspdR-vspd);}else{vspeed(vspdL,0);}vforwardRL();

}

// Назад и влевоvoid vbackwardleft() {if (vspdL > vspd) {vspeed(vspdL-vspd,vspdR);}else{vspeed(0,vspdR);}vbackwardRL();

}

// Назад и вправоvoid vbackwardright() {if (vspdR > vspd) {vspeed(vspdL,vspdR-vspd);}else{vspeed(vspdL,0);}vbackwardRL();

}

// Стопvoid vrelease(){motor1.run(RELEASE);motor2.run(RELEASE);motor3.run(RELEASE);motor4.run(RELEASE);

}

// Изменение скоростиvoid vspeed(int spdL,int spdR){if (spdL == spdR) {vspdL=spdL;vspdR=spdR;}motor1.setSpeed(spdL);motor2.setSpeed(spdR);motor3.setSpeed(spdL);motor4.setSpeed(spdR);

}

В строках, на которые будет ругаться компилятор, поменяйте тире на минусы.

P.S

В следующий раз я попробую реализовать алгоритм прохождения лабиринта по правилу правой руки или движение по белой линии.

    • source
    • Миниатюра:
    • Рубрика: Arduino от А до Я

    Источник: https://GeekElectronics.org/arduino/vedroid-mobil-robot-na-arduino-chast-4-podklyuchaem-ultrazvukovoj-dalnomer.html

    Занятие 5 Робот, проходящий лабиринт

    Робот следующий за объектом - Arduino

    Добавим роботувозможность объезжать препятствия. Дляэтого используем ультразвуковой датчикрасстояния HC-SR04

    Примечание:рекомендуется взять распечатку Занятия9. Цифровые датчики с информацией обиспользуемом датчике

    Практическоезанятие 1. Установка и тестирование

    Установите датчикрасстояния на робота, использовавдержатель. Подключите контакты датчикак Arduino(VCC– к 5V).Протестируйте датчик, загрузив вконтроллер программу Файл/ Примеры / Ultrasonic/ Ultrasonic2serial,исправив при необходимости номераконтактов.

    Практическоезанятие 2. Остановка у стены

    Запрограммируемробота на езду вперед и остановку упрепятствия. Скопируйте в программуразработанные в домашнем заданиифункции: forward,backward,left,rightс передачей значения, сколько времениработать моторам. Если таких функцийнет в наличии, шаблон функции дан в концепрошлого занятия

    float distance;

    int min_distance = 20;

    // переменные, setup и опрос датчика расстояния в переменную distance

    if (distance > min_distance) { // если расстояние впереди больше заданного

    forward (50); // едем вперед

    }

    else { // иначе, если расстояние впереди меньше заданного

    stop_motors (); // тормозим

    }

    // функции

    Примечание:возможна ситуация, когда на датчик неприходит ответный сигнал, в этом случаеdistanceможет приравняться к нулю. Чтобы избежатьнекорректного поведения робота в этомслучае, можно после опроса датчикадобавить строку if(distance= 0) { distance= 2000; }

    Практическоезанятие 3. Объезд препятствия

    Реализуйте следующийалгоритм:

    1. Ехать вперед до тех пор, пока дистанция до препятствия впереди не будет меньше заданной (аналогично прошлой программе)

    2. Если дистанция меньше – остановиться, отъехать назад, повернуть на определенный угол

    3. Вернуться к пункту 1

    Практическоезанятие 4. Случайный объезд

    Возможны ситуации,например, лабиринты, которые в случаеезды робота вдоль одной стены являютсянепроходимыми. Простым решением проблемыявляется добавление элемента случайностив движения робота. Добавьте в предыдущуюпрограмму при обнаружении препятствияслучайное направление поворота, используялогическую (boolean) переменную povorot дляхранения направления

    boolean povorot = false;

    if (distance > min_distance){ // если расстояние впереди больше заданного

    forward (50); // едем вперед

    }

    else { // если расстояние впереди меньше заданного

    stop_motors (); // тормозим

    delay(100);

    backward (200); // едем назад

    if (random(0, 2) == 0) {povorot = false;} // кидаем монетку на направление поворота 0 – false,

    else {povorot = true;} // 1 – true

    if (povorot == false){ // есливыпал 0

    left (turn_time); // едем налево

    }

    else { // если выпала 1

    right (turn_time); // едем направо

    }

    }

    Такжеможно добавить и случайное время поворота(в заданных пределах), соответственно,будет случайным угол поворота:

    turn_time =random (min, max+1)

    Практическоезанятие 4. Объезд с выбором направленияповорота

    Попробуем ускоритьдвижение робота по объезду препятствия,убрав отъезд назад и добавив осмысленныйвыбор направления объезда препятствия.Например, при подъезжании робота к стенепод углом (см. рисунок справа) имеетсмысл выбрать соответствующее направлениеповорота, обеспечивающее минимальноевремя поворота.

    Алгоритм работыв этом случае:

    1. Ехать вперед до тех пор, пока дистанция до препятствия впереди не будет меньше заданной (аналогично прошлой программе)

    2. Сохранить измеренную дистанцию, случайно выбрать направление поворота

    3. Повернуть на небольшое расстояние

    4. Измерить расстояние впереди

    5. Сравнить измеренное расстояние с сохраненным в начале. Если расстояние стало меньше – направление выбрано неправильно и его надо сменить

    6. Продолжать повороты до тех пор, пока расстояние впереди не станет больше заданного

    Приведен код дляданного алгоритма, его нужно проверить,провести подбор параметров (speed,turn_time и т.д.) для решения задачи оптимальногопрохождения лабиринта (за минимальноевремя) и продемонстрировать работу.Значение turn_timeв коде небольшое (порядка 50 мс), так какдля отворачивания от препятствиявыполняется несколько мелких поворотов,а не один большой

    distance = ultrasonic.Ranging(CM);

    if (distance > min_distance){ // еслирасстояниевпередибольшезаданного

    forward (50); // едем вперед

    }

    else { // если расстояние впереди меньше заданного

    if (random(0, 2) == 0) {povorot = false;} // кидаем монетку на направление поворота 0 – false,

    else {povorot = true;} // 1 – true

    // поворачиваем до тех пор, пока расстояние впереди не станет допустимым, при этом проводим проверку, правильно ли мы повернули

    while (ultrasonic.Ranging(CM) < min_distance){

    if (povorot == false){ // есливыпал 0

    left (turn_time); // едемналево

    }

    else { // есливыпала 1

    right (turn_time); // едемнаправо

    }

    // если дистанция впереди стала меньше исходной – поворот выполняется в неправильном направлении, меняем направление на противоположное

    if (ultrasonic.Ranging(CM) < distance) {povorot = !povorot;}

    }

    }

    Примечание 1:сохраните к себе получившийся кодпрограммы, он будет использован насоревновании по прохождению лабиринтана аттестационном занятии 8

    Примечание 2:теоретически, при определеннойконфигурации препятствия, возможно,что в обоих направлениях поворотоврасстояние впереди станет меньше, чембыло до поворота. В этом случае роботбудет дергаться вправо-влево бесконечно.Чтобы избежать этого, можно добавитьсчетчик смены направлений и при превышениисчетчика дать команду роботу выполнить,например, поворот на случайный большойугол.

    Источник: https://StudFiles.net/preview/5814399/

Поделиться:
Нет комментариев

    Добавить комментарий

    Ваш e-mail не будет опубликован. Все поля обязательны для заполнения.