Skocz do zawartości

Ultradźwiękowy czujnik odległości do robota


Pomocna odpowiedź

Z tego co ja widzę to masz 15*4=60cykli u góry i 58cykli na dole w WDR.

Razem z resztą wychodzi powiedzmy 125cykli zegara. Przy zegarze 16MHz generujesz fale pokroju 128KHz.

Nic dziwnego, że to nie działa. Powinieneś generować falę ok. 42KHz, czyli 3 razy wolniejszą.

Link do komentarza
Share on other sites

Mnie intrygują 2 rzeczy:

1. Dla czego wszyscy uparcie nazywają funkcję Sinus_40KHz jak tak naprawdę generuje ona przebieg prostokątny ? No bo zmieniając tylko stan Bitu z 0 na 1 i odwrotnie nie da się sinusa uzyskać.

2. Po co kombinujecie jak wysiorpać te 40KHz programowo jakimiś dziwacznymi funkcjami, jak można to zrobić sprzętowo Timerem ? I to z 100% dokładnością bo akurat 40KHz wychodzi bardzo dokładnie. Nawet wykorzystując tylko przerwania od Timera, programowo (w procedurze obsługi) można bardzo dokładnie to generować.

Link do komentarza
Share on other sites

Mnie intryguje jedna rzecz. W jaki sposób chcesz bezpośrednio wysiorbać sinusa 40kHz z uC nie posiadającego DAC - raczej kiepska sprawa, a co do użycia timreów - np ktoś wyżej pisał, że nie ma już wolnych, ale co do ich wyższośći w tym wypadku się zgodzę - po co blokować sobie uC, szczególnie, jeśli ma to być wykorzystane w robocie. Prawdę mówiąc, trzeba by zrobić ten sonar od nowa, bo to co jest jest powiedzmy... No nic nie mówmy, ważne że jest 😋

ED. Zwracam honor, przeczytałem "używają", zamiast "nazywają". Sorry.

Link do komentarza
Share on other sites

Jacek:

1. Procesor wygeneruje przebieg prostokątny, ale przetwornik już nie. On to przerobi na coś zdecydowanie bliższego sinusowi. Co innego, że nazwa funkcji nie ma żadnego znaczenia.

2. Użytkownik nie ma wolnych timerów, więc kombinuje jak może

Bobby:

Może on robi jakieś najważniejsze rzeczy w timerach i te 0,2ms które będzie trwać generowanie sinusa nie ma dla niego żadnego znaczenia? A jak funkcje timerów są krótkie to nie wpłyną poważnie na generowaniu fali 40KHz.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Zmieniłem funkcję w taki sposób:

void sinus_40_khz(void)			
{
register unsigned int i;

DDRA |= (1<<PA6);PORTA |= (1<<PA6);
DDRA |= (1<<PA7);PORTA &= ~(1<<PA7);

for(i=0;i<27;i++){     // 6 taktow
asm volatile("WDR"::); // 1 takt
};

PORTA &= ~(1<<PA6);
PORTA |= (1<<PA7);

for(i=0;i<26;i++){
asm volatile("WDR"::);
};

}

Sprawdziłem w AVR Studio 4 i wykonanie jej na 16MHz atmedze zajmuje 25us, czyli mam idealnie 40kHz.

Sonar oczywiście dalej nie działa. Po wgraniu do uC słychać dźwięk generowany przez nadajnik, a to dobrze nie świadczy, skoro ludzki próg słyszalności wynosi ok. 18-20kHz...

Jakieś pomysły?

Link do komentarza
Share on other sites

Bobby

Mnie intryguje jedna rzecz. W jaki sposób chcesz bezpośrednio wysiorbać sinusa 40kHz z uC nie posiadającego DAC

Ja pisałem tylko o nazwie procedury. Sinusa też się na upartego dałoby, robiąc z PWMa przetwornik C\A. Jak by użyć PICa to problem nie istnieje tam jest akurat na to prosty sposób, rozdzielczość co prawda tylko 4 bity, ale da się.

MirekCz

2. Użytkownik nie ma wolnych timerów, więc kombinuje jak może

A to nie można wykorzystać przerwania do robienia 2 rzeczy ? Tzn. nie wiem do czego dokładnie wykorzystuje te wszystkie Timery, ale pewnie się da kwestia pogłówkować.

Jak Zmusić jeden timer do generowania przerwań co 25uS, zmieniać w nim stan potrzebnej końcówki, a jednocześnie zwiększać dodatkowy programowy licznik i porównywać go z wartościa która określa drugi odmierzany czas i jak jest równa to ustawiać znacznik, który będzie sprawdzany w pętli głównej i wyzerować licznik.

W 51 tak się robiło jak brakowało Timerów i działało.

Link do komentarza
Share on other sites

Witam, czy któryś z szanownych forumowiczów ma może zbędną parę przetworników? Niestety na znanym portalu aukcyjnym nie znalazłem, są co prawda w TME ale wysyłka itp.

Mam jeszcze pytanie. Czy ktoś z was myślał może nad wykorzystaniem czujników parkowania? Są dość tanie bo za 20zł kupi. Czy byłaby znacząca różnica w ich zastosowaniu w porównaniu z przetwornikami o których mowa w temacie?

Link do komentarza
Share on other sites

Cześć panowie,

ja mam pytanie odnośnie możliwej do uzyskania precyzji pomiaru odległości - testował ktoś, np. na analogach Sharpa czy da się uzyskać niepewność pomiaru na poziomie 1mm?

Link do komentarza
Share on other sites

Cóż, kupiłem tanie czujniki T4010A1 i R4010A1 i są spore problemy - oczywiście oryginał nie działa w ogóle - cały czas daje odległość minimalną. Potem zabrałem się za pisanie własnego programu i dokonywałem czegoś co można nazwać debugowaniem za pomocą analizatora stanów logicznych (scanlogic1 - zrobiony w 10 min z Arduino). I co się okazało - nadawanie przebiega bez problemu, oparłem to na timerze, więc przy F_CPU=16MHz ładnie generuje idealne 40kHz, odbiornik też odbiera sygnał przy nadawaniu ciągłym i widoczności czujników/odbiciu fal.

Potem zabrałem się za implementację zasady działania dalmierza więc program działa tak:

1. Nadajemy przez 10 okresów falę o częstotliwości 40kHz

2. Blokujemy nadajnik zwierając oba wyprowadzenia do masy

3. czekamy 50us

4. Blokujemy odbiornik zwierając oba piny do masy

5. czekamy 50us

6. ***czekamy aby pominąć pierwotną falę docierającą do nadajnika***

7. czekamy aż komparator analogowy zmieni swój stan, czyli aż fala odbita dotrze do odbiornika

8. w "międzyczasie" mierzymy czas od początku nadawania fali aż do początku odbioru fali odbitej i na tej podstawie wyliczamy odległość

No i niestety nie jest różowo. Impuls pierwotny zachowuje się dosyć dziwnie, mianowicie trwa dosyć długo (mimo osłonięcia nadajnika i odbiornika osobnymi kartonowymi tulejami o długości ~5cm każda). Po drugie bardzo często odczyt jest wysoce niestabilny - układ często łapie jakieś wyimaginowane obiekty w odległości <20cm pomimo iż teren jest na 100% czysty (dalmierz wycelowany w sufit na środku pokoju odległy o jakieś 1,5m) Dalsze obiekty po odpowiednim zwiększeniu czasu z punktu 6. algorytmu (tak że wtedy chcąc nie chcąc minimalna odległość wykrywana przez dalmierz to 20-25cm) są wykrywane poprawnie i odległość podawana przez urządzenie jest zgodna z oczekiwaniami.

Zastanawiam się więc nad tym jak ten problem rozwiązać i czy ew:

a) nie dać mniejszego rezystora między zaciski odbiornika (np. 60 lub 30k)

b) nie zmniejszyć mocy nadajnika wpinając w jego obwód szeregowo rezystor

c) zastosować lepsze czujniki (te "z metalowymi obudowami")

Macie ew. jakieś inne rady?

Dalej pytanie do Autora - czy testowałeś (lub czy ktoś inny testował) działanie tego układu z zastosowaniem TL082?

PS. załączam swoje wypociny tworzone na kolanie.

Połączenia:

PD6-7 - nadajnik

PB2-3 - odbiornik z wpiętym równolegle rezystorem 100k

PB0 - wyjście do debugowania, jak widać programowo "podpinałem" tam wyjście z komparatora

dodatkowo wyświetlacz LCD do prezentacji wyników.

[ Dodano: 28-09-2011, 13:30 ]

Pomogło umieszczenie nadajnika i odbiornika w większej odległości od siebie. Dokładność jaką osiągnąłem to ±2cm, więc jak na potrzeby planowanego robocika bardzo przyzwoicie. Minimalna odległość od czujników to 14cm (10cm + 4 cm tulejek), gdyż taki czas trzeba aby wyeliminować wszystkie fale pierwotne odbite od otoczenia czujników lub dochodzące bezpośrednio z jednego do drugiego pomimo tulejek.

Program z niewielkimi zmianami umieszczam poniżej. Oczywiście w przyszłości zamierzam całość zamontować na płytce i obsługiwać procesorem klasy attiny85 z wyprowadzonymi odpowiednimi sygnałami cyfrowymi (może I2C slave albo uart tx + int przy wykryciu znacznej zmiany odległości).

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "lcd44780.h"

volatile uint8_t pulse=0;

void generate_40k(uint8_t p){
PORTD|=(1<<PD7);//PB7 - wstan wyskoi, PB6 - stan niski
pulse=p;
}

void generate_stop(){
pulse=0;
PORTD&=~((1<<PD6)|(1<<PD7));
}

int main(void){
lcd_init();
lcd_cls();
uint8_t aco_old, aco_cur;	
uint16_t echo_time=0;
uint64_t distance;
uint8_t inf=0;
/*Konfiguracja pinów I/O do nadajnika*/
DDRD|=((1<<PD7)|(1<<PD6));//PB6-7 - wyjścia
PORTD|=(1<<PD7);//PB7 - wstan wyskoi, PB6 - stan niski

/*Konfiguracja Timera0 - nadawanie 40kHz*/
TCCR0B|=(1<<CS00);//Timer 1, preskaler 1 (16000000)
TCCR0A|=(1<<WGM01);//Tryb CTC
TIMSK0|=(1<<OCIE0A);//aktywacja przerwania CTC0A
OCR0A=199;//16000000Hz / 200 =~ 80,000kHz (f*2)
       //timer1 - pomiar czasu
TCCR1B|=(1<<CS11);

sei();//system przerwań

DDRB|=(1<<PB0);//PB0 - wyjście


while(1){
	TCNT0=190;
	TCNT1=0;
	generate_40k(20);
	while(pulse>0);
	generate_stop();
               //wytłumianie odbiornika pogarszało parametry układu i powodowało paradoksalnie jego wzbudzenie zaraz po "rozwarciu" pinów od masy
	/*_delay_us(50);
	PORTB&=~((1<<PB2)|(1<<PB3));
	DDRB|=((1<<PB2)|(1<<PB3));
	_delay_us(50);
	DDRB&=~((1<<PB2)|(1<<PB3));//*/
	_delay_us(500);
	aco_old=ACSR&(1<<ACO);
	inf=1;
	for(unsigned long int i=0;i<5000;i++){
		aco_cur=ACSR&(1<<ACO);
		if(aco_cur!=aco_old){
			if(inf==1)echo_time=TCNT1;
			aco_old=aco_cur;
			inf=0;
			PORTB^=(1<<PB0);
			//break;
		}
                       //do debbugowania - wyjście ACO przepisujemy na PB0
		if(aco_cur){
			PORTB|=(1<<PB0);
		}else{
			PORTB&=~(1<<PB0);
		}
	}
	if(inf){
	lcd_locate(0,0);
	lcd_str("-----us");
	lcd_locate(1,0);
	lcd_str("-----cm");
	}else{
	lcd_locate(0,0);
	echo_time/=4;
	if(echo_time<10000)lcd_char('0');
	if(echo_time<1000)lcd_char('0');
	if(echo_time<100)lcd_char('0');
	if(echo_time<10)lcd_char('0');
	lcd_int(echo_time);
	lcd_str("us");
	distance=(uint64_t)echo_time*340;
	distance/=10000;
	echo_time=distance;
	lcd_locate(1,0);
	if(echo_time<10000)lcd_char('0');
	if(echo_time<1000)lcd_char('0');
	if(echo_time<100)lcd_char('0');
	if(echo_time<10)lcd_char('0');
	lcd_int(echo_time);
	lcd_str("cm");
	}
	_delay_ms(500);

}
}

ISR(TIMER0_COMPA_vect){
if(pulse>0){
	PORTD^=((1<<PD7)|(1<<PD6));
	pulse--;
}
}

main.c

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.