Технически форум > Електроника

Ултразвуков сензор

(1/9) > >>

sv_shady:
Първия робот, който направих беше с инфраред сензори. От начало това ми се струваше много сложно, още навлизах и след като успях да накарам робота да "вижда" препядствия бях много радостен :) Постепенно започнах да се чувствам с свои води и вече само "виждането" на препядствия не ми беше достатъчно исках да знам на какво разстояние е предмета. За това започнах да търся начини. Първия метод на който попандах бяха готови инфраред сензори, мерещи до 3м, но както не е трудно да се досетите в бг няма такива. После попаднах на ултразвукови сензори, но за съжеление и тях ги няма в бг и реших да се захвана сам да си направя. Метода за мерене и при ифрареда и при ултразвука е следния : изпраща се сигнал светлина/звук с правилната честота (зависи от сензора) и се мери времето, за което ще отиде, ще се отрази от предмета и ще се върне и според скоростта се намира растоянието. Избрах ултразвука тъй като скоростта му е по-нормална от тази на светлината :P и времето не трябва да бъде отмерено с такава голяма точност.
Стига празни приказки да минаваме по съшество Това е схемата на самия сензор, има 2 оснотвни части - приемник и излъчвател на ултразвук с честота 40кНz. Излъчвателя е една схема 555 която генерира правоъгълни импулси на 40kHz и с транзистор се захранва предавателя. По характеристика максималното му напрежение е 20V и тогава дистанцията е 6м, аз съм го тествал на 12 и достига около 5м, като се раздели на 2 тъй като звука трябва да измине 2 пъти разстоянието до обекта на отиване и връщане, получаваме обхват 2.5м, което доста добре, е не като 3м, но си върши работа :) До тук всичко добре, но идва време да пристъпим до приемника, отне ми окло 3месеца докато го подкарам :cry:
Първата стъпка от приемането на сигнала е да се усили. Първата схема е ЛМ358, която е операционен усилвател. С помоща на R1, R2, R3 и R4 се задава коефициента на усилване. На първото стъпало е R2:R1 = 10, а на второто R4:R3 = 100  => усилваме сигнала 1000 пъти.  Следващата стъпка е да се пречисти, за целта ползвам ЛМ567. Това интегрална схема, която да кажем, че "сравнява честоти". На входа и се подава, честоа която се "сравнява" с друга, която се генерира от С4, TRIM1 и R7. Тя може да бъде настройвана с помоща на TRIM1. И така когато имаме oпорна честота 40кHz и на входа имаме честота 40kHz то изхода променя логическото си ниво от 1 към 0. Но тъй като ще използваме сигнал с продължителност 200микро секунди, това време няма да е достатъчно за да се свали изхода до абсолютна логическа нула за това слгаме един компарато - ЛМ393. С помоща на TRIM2 настройваме нивото, под което ако слезе сигнала от ЛМ567 на изхода на компаратора илиза логическа 1. И така вече този сигнал може да влезе в миктоконтролера. За засичането изплзвам един capture модул, защото доста по точно от ползване на прекъсване. Пристъпваме към сорса :

--- Код: ---#include <16F877A.h>
#device ICD=TRUE
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#priority CCP1, TIMER1

#define send_us PIN_D7
#define receive_us PIN_C2

float temp[10] = {0};
float distance;
float avg_dist;
float time;
float us_speed = 345.123;
int1 echo = 0;

#INT_TIMER1
void overflow()
{
   disable_interrupts(GLOBAL);
   clear_interrupt(INT_CCP1);
   clear_interrupt(INT_TIMER1);
   setup_timer_1(T1_DISABLED);
   setup_ccp1(CCP_OFF);
   distance = 512;
}

#INT_CCP1
void receive()
{
   if(!echo)
   {
      disable_interrupts(GLOBAL);
      clear_interrupt(INT_TIMER1);
      clear_interrupt(INT_CCP1);
      setup_ccp1(CCP_OFF);
      setup_timer_1(T1_DISABLED);
      time = (CCP_1) * 0.0000004;
      distance = time * us_speed;
      distance = distance / 2;
      distance -= 0.04;
      echo = 1;
   }
}

void send()
{
   int i = 0;
   //set ccp and timer module
   setup_ccp1(CCP_CAPTURE_RE);
   setup_timer_1 (T1_INTERNAL);
   //all interrupts on
   enable_interrupts(GLOBAL);
   echo = 0;
   output_bit(send_us, 1);
   set_timer1(0);
   delay_us(200);
   output_bit(send_us, 0);
}

void analyze()
{
   int i = 0, cnt_max = 0, max = 0, min = 0, count = 0, dist;
   float cur_sum = 0, cur_dist = 0;
   for(i = 0; i < 10; i++)
   {
      if(temp[i] == 512.0) cnt_max++;
      if(temp[i] > temp[max]) max = i;
      if(temp[i] < temp[min]) min = i;
   }
   if(cnt_max > 5) avg_dist = 255;
   else
   {
      for(i = 0; i < 10; i++)
         if(i != max && i != min && temp[i] != 512.0)
         {
            cur_sum += temp[i];
            count++;
         }
         cur_dist = cur_sum / count;
         cur_dist = cur_dist * 100;
         dist = (int)cur_dist;
         if((cur_dist - dist) >= 0.5) dist++;
         avg_dist = dist;
   }
}
main()
{
   //define variables
   int i = 0, j = 0;
   //set IO ports
   set_tris_b(0x00);
   set_tris_c(0x00);
   set_tris_d(0x00);
   //enable interrupts
   enable_interrupts(INT_TIMER1);
   clear_interrupt(INT_TIMER1);
   enable_interrupts(INT_CCP1);
   clear_interrupt(INT_CCP1);
   //clear IO ports
   output_b(0x00);
   output_c(0x00);
   output_d(0x00);
   for(j = 0; j < 25; j++)
   {
       for(i = 0; i < 10; i++)
      {
         send();
         temp[i] = distance;
         delay_ms(20);
      }
      analyze();  
   }
}
--- Край на кода ---

Можете да го свалите от тук
Ще обясня на кратко как работи, а ако имате въпроси питайте. Значи първо инициализарме таймери и кепчър модула. По зададените параметри в сорса таймера ще инкрементира всеки 0,0000004 секунди и ще се напълва за 0,0262144 секунди, за което време звука ще премине приблизително 9м, което ни е напълно достатъчно тъй като ние имаме обхват от 2,5м => при оверфлоу казваме, че няма препядствие. След това викам функцията send(), която сетва таймера на 0, след това вдига пина , който контролира 555 за 200микросекунди, и така изпращаме сигнал с дължина 200микросекунд с честота 40кHz. След това имаме две функции, които са всъщност функци, ползващи интерупт. Първата е overflow(); Тя се активира ако таймера се напълни, тя дезактивира всички прекъсвания, чисти флаговете за такива и задава стойност на distance = 512, което означава оверфлоу. Другия варианt е да се активира receive(), тя пак спира всичките интерупти, чисти флаговете, после зима броя на инкрементиранията на таймера чрез кепчър модула, умножава по 0,0000004 - така намира времето, след това умножава по скоростта на звука и на края дели дистанцият на 2 и вади 0,04 което е корекция, тъй като до като се задейства кепчър модула минава време  :P И така за едно измерване, мери 10пъти, за по-голяма точност. После получената редица от 10 елемента се обработва- махат се най - малкия и най-големия елемент и ако има по-малко от 5 512 се пренебрегват. И след всичко това крайната стойност е в avr_dist
Това е в общи линии, на теория е лесно, но докато тръгне на практика ми беше много трудно. За малко да забравя ЛМ567 я има в комет, а за предавател и приемника от тук най-отдолу. Няколко пъти съм си поръчвал и по пощата идват максимум за седмица. Има се предлагат и затворени сензори, но не са достатъчно чувствителни, важно е да отворени.
Очаквам въпроси :)

Borislav:
Интересно... Дали да не сложа нещо подобно на сумиста, вместо TSOP.. :) Страхотна статия, браво! Добра работа!

sv_shady:
за сумиста не знам как ще реагира на движение :!:

kanadeca:
:o  Това звучи супер интересно. Прочетох статията и разбрах как действа, но съм сигурен, че със сегашните ми познания няма да успея да направя това... :oops:  Ще можеш ли да публикуваш и статия за инфраред сензорите, мисля че това ще бъде по-лесничко?

sv_shady:
Няма проблем :)

Навигация

[0] Списък на темите

[#] Следваща страница

Премини на пълна версия