Робот, объезжающий препятствия, является одним из самых популярных типов роботов, создаваемых энтузиастами-радиолюбителями. По сути, это обычный робот на колесах, который может двигаться в пространстве, не сталкиваясь ни с какими препятствиями. Существует много различных способов сконструировать подобного робота, но в нашем проекте мы будем использовать ультразвуковой датчик (front) и два инфракрасных датчика (Left/Right) – благодаря этому набору датчиков робот сможет анализировать обстановку сразу в трех направлениях, что позволит ему более эффективно передвигаться. Данного робота мы сконструируем на основе микроконтроллера PIC16F877A.
Принципы работы современных роботов-пылесосов во многом похожи на принцип работы рассматриваемого в нашей статье робота, хотя в них и используются значительно более дорогие датчики. Также ранее на нашем сайте мы рассматривали проекты роботов, объезжающих препятствия, на основе плат Arduino и Raspberry Pi. Дополнительно вы можете посмотреть и проекты других похожих роботов:
- робот для очистки пола на основе Arduino и ультразвукового датчика;
- вакуумный чистящий робот (пылесос) на Arduino;
- робот-пылесос на Arduino для автоматической уборки помещений;
- робот на Arduino для автоматической дезинфекции помещений.
Необходимые компоненты
- Микроконтроллер PIC16F877A (купить на AliExpress).
- Ультразвуковой датчик HC-SR04 (купить на AliExpress).
- Инфракрасный датчик – 2 шт. (купить на AliExpress).
- Электродвигатель постоянного тока – 2 шт.
- Драйвер двигателя L293D (купить на AliExpress — но его можно купить и в виде отдельной микросхемы).
- Держатель микросхем на 40 контактов (купить на AliExpress).
- Программатор PICkit 3 (купить на AliExpress).
- Кварцевый генератор 20 МГц (купить на AliExpress).
- Конденсаторы 22 пФ (2 шт.), 0,1 мкФ и 10 мкФ (купить на AliExpress).
- Регулятор напряжения 7805 (купить на AliExpress).
- Шасси робота (можно изготовить самостоятельно).
- Power bank.
- Перфорированная плата.
- Соединительные провода.
Реклама: ООО «АЛИБАБА.КОМ (РУ)» ИНН: 7703380158
Принципы работы робота объезжающего препятствия
Принцип работы нашего робота достаточно прост. Мы используем датчики для обнаружения препятствий в пространстве вокруг робота и на основе этих данных инструктируем робота чтобы он не сталкивался с ними. В качестве датчиков мы используем ультразвуковой датчик (расположенный спереди робота) и инфракрасные датчики (расположенные по краям робота). Робот будет двигаться прямо если впереди себя он не будет обнаруживать никакого препятствия.
Когда ультразвуковой датчик обнаружит впереди себя препятствие необходимо будет изменять направление движения робота. Мы можем повернуть вправо или влево. Принимать решение о том, в какую сторону (вправо или влево) поворачивать, мы будем на основе информации от инфракрасных датчиков – будут ли они обнаруживать препятствия справа и слева робота.
Если препятствие будет спереди и справа робота, то робот будет немного отъезжать назад (чтобы не столкнуться с препятствием во время поворота) и затем поворачивать влево.
Аналогичным образом, если препятствие будет спереди и слева робота, то робот будет немного отъезжать назад и затем поворачивать вправо.
Если робот будет доезжать до угла комнаты, то в этом случае он будет окружен препятствиями со всех трех сторон, на которых у него есть датчики. В этом случае он должен будет отъезжать назад до тех, пока с одной стороны препятствие не исчезнет.
Еще один возможный случай, это когда впереди робота есть препятствие, а справа и слева от него препятствий нет, в этом случае мы случайным образом должны решить в какую сторону нам двигаться – вправо или влево.
Схема проекта
Схема робота, объезжающего препятствия, на основе микроконтроллера PIC представлена на следующем рисунке.
№ п/п | Куда подключен в схеме | Контакт микроконтроллера PIC |
1 | IR sensor Left out pin | RD2 (pin 21) |
2 | IR sensor Right out pin | RD3 (pin 22) |
3 | Motor 1 Channel A pin | RC4 (pin 23) |
4 | Motor 1 Channel B pin | RC5 (pin 25) |
5 | Motor 2 Channel A pin | RC6 (pin 26) |
6 | Motor 2 Channel B pin | RC7 (pin 27) |
7 | контакт Trigger ультразвукового датчика | RB1 (pin 34) |
8 | контакт Echo ультразвукового датчика | RB2 (pin 35) |
Драйвер двигателей L293D (или подобный ему) является обязательным в нашей схеме поскольку тока, обеспечиваемого контактами ввода/вывода микроконтроллера PIC, не хватит для управления двигателями. Датчики и микроконтроллер в нашей схеме запитываются от напряжения +5V с выхода регулятора напряжения 7805. Драйвер двигателей L293D можно запитывать от +12V, однако в данной схеме мы запитали его от +5V.
В конечном итоге, все компоненты нашего робота запитываются от Power bank’а. Также можно использовать батарейки на 9V или 12V.
Внешний вид собранной конструкции робота показан на следующем рисунке.
Объяснение программы для микроконтроллера PIC
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
В начале программы мы объявим используемые контакты и зададим режимы их работы. Также инициализируем Timer 1 – он нам будет необходим для работы с ультразвуковым датчиком.
1 2 3 4 5 6 7 8 9 10 |
TRISD = 0x00; //PORTD declared as output for interfacing LCD TRISB1 = 0; //Trigger pin of US sensor is sent as output pin TRISB2 = 1; //Echo pin of US sensor is set as input pin TRISB3 = 0; //RB3 is output pin for LED TRISD2 = 1; TRISD3 = 1; //Both the IR sensor pins are declared as input TRISC4 = 0; TRISC5 = 0; //Motor 1 pins declared as output TRISC6 = 0; TRISC7 = 0; //Motor 2 pins declared as output T1CON=0x20; |
Затем запрограммируем функцию для определения расстояния до препятствия впереди робота с помощью ультразвукового датчика. Мы будем в программе выполнять эту операцию достаточно часто, поэтому вполне логично оформить ее в виде функции. Более подробно про работу микроконтроллера PIC с ультразвуковым датчиком HC-SR04 вы можете прочитать в этой статье.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void calculate_distance() //function to calculate distance of US { TMR1H =0; TMR1L =0; //clear the timer bits Trigger = 1; __delay_us(10); Trigger = 0; while (Echo==0); TMR1ON = 1; while (Echo==1); TMR1ON = 0; time_taken = (TMR1L | (TMR1H<<8)); distance= (0.0272*time_taken)/2; } |
На следующем шаге мы будем сравнивать значения с ультразвукового и инфракрасных датчиков с определенными в программе значениями и на основе результатов этого сравнения подавать команды на робот на его движение в соответствующем направлении. Все расстояния в нашей программе указаны в сантиметрах.
Если впереди робота нет препятствия он просто движется прямо.
1 2 3 4 5 |
if (distance>5) { RC4=0; RC5=1; //Motor 1 forward RC6=1; RC7=0; //Motor 2 forward } |
Если впереди робота будет обнаружено препятствие мы будем анализировать информацию с инфракрасных датчиков и на основании этого принимать решение в каком направлении двигаться. Задержка в 500 мс используется для того чтобы сделать моменты изменения направления движения робота более заметными.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
if (RD2==0 && RD3==1 && distance<=5) //Left sensor is blocked { back_off(); RC4=1; RC5=1; //Motor 1 stop RC6=1; RC7=0; //Motor 2 forward __delay_ms(500); } calculate_distance(); if (RD2==1 && RD3==0 && distance<=5) //Right sensor is blocked { back_off(); RC4=0; RC5=1; //Motor 1 forward RC6=1; RC7=1; //Motor 2 stop __delay_ms(500); } |
Если ультразвуковой датчик впереди себя будет обнаруживать препятствие, а справа или слева (по информации от инфракрасных датчиков) препятствия не будет, то робот по умолчанию будет поворачивать влево. Вы можете по своему усмотрению изменить его на поворот влево или на рандомный (случайный) поворот вправо или влево. Если расстояние обнаруживается со всех трех сторон робота (спереди, справа и слева), то робот будет двигаться назад.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
calculate_distance(); if (RD2==0 && RD3==0 && distance<=5)//Both sensor is open { back_off(); RC4=0; RC5=1; //Motor 1 forward RC6=1; RC7=1; //Motor 2 stop __delay_ms(500); } calculate_distance(); if (RD2==1 && RD3==1 && distance<=5)//Both sensor is blocked { back_off(); RC4=1; RC5=0; //Motor 1 reverse RC6=1; RC7=1; //Motor 2 stop __delay_ms(1000); } |
Тестирование работы робота
После сборки схемы робота и загрузки программы в микроконтроллер PIC вы можете протестировать его работу, поместив его на ровную поверхность. После подачи питания робот начнет двигаться прямо и по мере обнаружения препятствий он будет изменять направление своего движения. По своему желанию вы можете изменить алгоритмы движения робота. Для сборки схемы робота мы использовали перфорированную плату с установленным на нее микроконтроллером PIC из проекта мигания светодиодом.
Более подробно работу робота вы можете посмотреть на видео, приведенном в конце статьи.
Исходный код программы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
/* Obstacle avoider using PIC16F877A * Code by: B.Aswinth Raj * Dated: 03-10-2017 * More details at: www.CircuitDigest.com */ #include <xc.h> #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled) #pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled) #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming) #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control) #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off) #define _XTAL_FREQ 20000000 #define Trigger RB1 //34 is Trigger #define Echo RB2//35 is Echo int time_taken; int distance; void back_off() //движение робота назад { RC4=1; RC5=0; //Motor 1 reverse RC6=0; RC7=1; //Motor 2 reverse __delay_ms(1000); } void calculate_distance() //функция для определения расстояния до препятствия впереди робота { TMR1H =0; TMR1L =0; //clear the timer bits Trigger = 1; __delay_us(10); Trigger = 0; while (Echo==0); TMR1ON = 1; while (Echo==1); TMR1ON = 0; time_taken = (TMR1L | (TMR1H<<8)); distance= (0.0272*time_taken)/2; } void main() { TRISD = 0x00; //PORTD declared as output for interfacing LCD TRISB1 = 0; //Trigger pin of US sensor is sent as output pin TRISB2 = 1; //Echo pin of US sensor is set as input pin TRISB3 = 0; //RB3 is output pin for LED TRISD2 = 1; TRISD3 = 1; //Both the IR sensor pins are declared as input TRISC4 = 0; TRISC5 = 0; //Motor 1 pins declared as output TRISC6 = 0; TRISC7 = 0; //Motor 2 pins declared as output T1CON=0x20; while(1) { calculate_distance(); if (distance>5) { RC4=0; RC5=1; //Motor 1 forward (вперед) RC6=1; RC7=0; //Motor 2 forward (вперед) } calculate_distance(); if (RD2==0 && RD3==1 && distance<=5) //Left sensor is blocked (препятствие слева) { back_off(); RC4=1; RC5=1; //Motor 1 stop RC6=1; RC7=0; //Motor 2 forward __delay_ms(500); } calculate_distance(); if (RD2==1 && RD3==0 && distance<=5) //Right sensor is blocked (препятствие справа) { back_off(); RC4=0; RC5=1; //Motor 1 forward RC6=1; RC7=1; //Motor 2 stop __delay_ms(500); } calculate_distance(); if (RD2==0 && RD3==0 && distance<=5)//Both sensor is open (справа и слева препятствий нет) { back_off(); RC4=0; RC5=1; //Motor 1 forward RC6=1; RC7=1; //Motor 2 stop __delay_ms(500); } calculate_distance(); if (RD2==1 && RD3==1 && distance<=5)//Both sensor is blocked (и справа, и слева препятствия) { back_off(); RC4=1; RC5=0; //Motor 1 reverse RC6=1; RC7=1; //Motor 2 stop __delay_ms(1000); } } } |