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ą.

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ć.

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.

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.

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?

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.

  • 2 miesiące później...

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?

  • 3 miesiące później...

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?

  • 1 miesiąc później...

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

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...