PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Asuro mit Ultraschallsensor SRF04



G_UNIT00101
28.05.2007, 16:21
Hey Leute!!!!

Also ich hab mich jetzt bestimmt 45 min. durchs Forum gesucht und nix gefuden. Mein Problem ist folgendes. Ich will mit dem Asuro und dem angebrachten Ultraschallmodul (SRF04) die Entfernung zu Gegenständen messen können. Der Ultraschallsensor wurde so angebracht dass er durch den Port B.3 sein Triggerimpuls und durch den Port D.6 sein Echoimpuls bekommt. Port D.6 wurde auch schon auf In gestellt. Nun weis ich so viel dass ich ein Triggerimpuls an den Ultraschallsensor geben muss was auch funktioniert (leises knistern zu hören) und dieser Impuls sollte ja ungefähr 10 µs dauern. Danach muss ich ja das Echosignal irgendwie auffangen und je nach dem wie lang es ist auswerten und kann dann daraus die entfernung ermitteln.Nun hab ich das Problem dass ich nicht weiß wie ich den Timer bzw. Counter was ich auch immer benötige beim ATMega8 ansteuere und was ich sonst noch alles zu beachten habe.

Ich wäre euch sehr dankbar wenn ihr mir dabei helfen könnten

MFG G_UNIT00101

damaltor
28.05.2007, 18:10
dafür brauchst du keinen timer, es sollte auch ungefähr so gehen:



double entfernung=0 //entfernungsvariable, evtl richt auch ein long oder sogar ein int
//hier ist der normale programmablauf

//jetzt wird der triggerimpuls gegeben

while((PINB & 64)=0); //64=0b01000000, diese schleife bleibt so lange bis der entfernungsimpuls beginnt aktiv.
while((PINB & 64)=64){ //diese schleife bleibt aktiv während spannung anliegt, in dieser zeit wird eine variable hochgezählt)
entfernung++; //variable wird um eins erhöht
} //schleife ende

//weiterer programmablauf mit auswertung der variable, wert ist größer je weiter entfernt das objekt ist

G_UNIT00101
28.05.2007, 19:49
Danke für dien Antwort !!!

Ich habe es jetzt mal so ausprobiert wie du gesagt hast blos irgendwie funktioniert das noch nicht ganz. Ich hab das Gefühl dass er bei der ersten while schleife hängen bleibt und gar nicht mehr weiter geht. (höre kein knacken mehr vom Ultraschallsensor). Aber weis nicht wie ich das lösen soll.


void distanzmessen(){
int entfernung = 0;
triggerimpuls = 1;
wait();
triggerimpuls = 0;
while((echoimpuls & 64) == 0);
while((echoimpuls & 64) == 64){
entfernung++;
}
if(entfernung <= 10){
Motorvor();
}else if(entfernung > 10){
Motorstop();
}
}

damaltor
28.05.2007, 19:54
was macht die funktion wait()? warum setzt du "triggerimpuls" erst 1 und dann 0? wo ist die funktion, die den triggerimpuls startet?

G_UNIT00101
28.05.2007, 20:04
Die Funktion wait() startet einen Timer der eine kurze wartezeit verursacht, da es mir so bekannt ist, dass man kurz warten sollte nachdem man den triggerimpuls gegeben hat


void wait(){
unsigned int i;
for(i = 0;i < 65000;i++){
TCNT0 = 0;
TCNT1H = (0xffff - 16666)>>8;
TCNT1L = (0xffff - 16666)%256;
TIFR = 0;
TCNT0 = 1;
while(TIFR == 0);
TIFR = 1;
}
}

...ich dachte man muss den triggerimpuls nur kurz anmachen danach wieder aus und dann das echosignal abfangen.

...der triggerimpuls wird doch durch den befehl triggerimpuls = 1 gestartet

Danke für die schnelle antwort

damaltor
28.05.2007, 20:14
die funktion wait brauchst du nicht, da ja die erste shleife genausolange wartet wie noch kein entfernungsimpuls vorhanden ist.

wie soll das funktioniieren mit dem triggerimpuls? warum wird der gestartet bloss weil eine variable eins gesetzt wird?

G_UNIT00101
28.05.2007, 20:26
OK habe die wait funktion entfernt aber triggerimpuls is keine variable sondern eine konstanten des Ports B.3 an den die Leitung für den Impuls angeschlossen ist. Aber so funktioniert es immernoch nicht.


void distanzmessen(){
int entfernung = 0;
triggerimpuls = 1;
while((echoimpuls & 64) == 0);
while((echoimpuls & 64) == 64){
entfernung++;
}
if(entfernung <= 10){
Motorstop();
}else if(entfernung > 10){
Motorvor();
}
}

aber was mich jetzt wundert wenn ich in dem ersten teil der if-schleife Motorvor() aufrufe passiert genauso wenig als wenn ich Motorvor() im zweiten teil aufrufe.Aber in einem von den zwei fällen müsste doch logischerweise etwas passieren.

damaltor
28.05.2007, 20:48
hm. zeig mir mal die definition der portkonstanten. iegend was stimmt da noch ncih... ansonsten muss ich mal mein wissen über die timer raussuchen...

G_UNIT00101
28.05.2007, 20:54
Hier die Portkonstanten:


#define triggerimpuls PORTB.3
#define echoimpuls PORTD.6

ich denke aber dass es schon ohne Timer funktionieren sollte wobei es ja nicht vom Timer abhängt ob ich ein Echo bekomme oder nicht.

damaltor
28.05.2007, 21:07
hm. hast du ein multi zur hand? du könntest mal mit deinem original-programm laufen lassen und dann messen, wie lang (ungefähr) der echoimpuls ist. ich will wissen, ob es sich um millisekunden, oder sekunde oder was handelt. ich werde in der zeit mal ein datenblatt des sensors finden.

damaltor
28.05.2007, 21:17
habs schon gefunden, der impuls ist nur wenige millisekunden lang. schade... =)

hast du mal probiert nach einem beispielprogramm zu suchen? mir fällt grad nix mehr ein...

G_UNIT00101
28.05.2007, 21:20
Also wenn ich richtig gemessen habe, dann messe ich beim Startvorgang des Asuros eine Spannung von ca. 2V und dann bei laufendem Programm eine konstanten Spannung von 0,09V an der Leitung des Echoimpulses. Da wird wohl das Problem liegen dass die Spannung zu gering ist oder ???


Ein Datenblatt des ATMEGA8 habe ich bereits:

http://www.file-upload.net/download-287051/Mega8.pdf.html

G_UNIT00101
28.05.2007, 21:21
Hab schon nach Beispielprogrammen gesucht aber nichts gefunden...leider

Aber Danke für deine große Hilfe bereits

damaltor
28.05.2007, 21:35
nein die spannung ist fein, es sollten eigentlich 0V sein. der echoimpuls ist maximal 18 millisekunden lang, da sieht man nich viel auf dem multi. ich würde jetzt mein oszi rauskramen, aber leider bin ich grad am umziehen =)

warte mal auf morgen, etl hat noch jemand ne idee.

Leute: wer kann mit dem srf04 umgehen? =)

G_UNIT00101
28.05.2007, 21:57
Ok Danke dann werde ich nochmal abwarten.

G_UNIT00101
29.05.2007, 14:20
Hat denn keiner mehr eine Idee wie ich mein Problem lösen könnte?????

damaltor
29.05.2007, 15:32
Bitte nicht pushen. such mal bei google nach beispielprogrammen, wenn du was hast dann poste es hier, evtl können wir es für deine zwecke abwandeln.

G_UNIT00101
29.05.2007, 15:48
Sorry aber mir geht langsam die Zeit aus ich muss den Roboter in 3 Wochen fertig laufen haben und außer der Programmierung ist noch einiges zu tun.(Ist ein Schulprojekt)

Das einzigste was ich an Hilfe finde ist das hier:

"Um eine Messung zu starten, wird ein Impuls (TTL-Pegel, mind. 10us) an den Triggereingang gelegt. Der Wandler wird von der Ablaufsteuerung (PIC) fuer 200us (8 Zyklen, 40kHz) getaktet und der Echo-Ausgang des Moduls auf High gelegt. Das erste hereinkommende Echo schaltet den Echo-Ausgang wieder auf Low, so dass ein direkt zur Entfernung des Objektes proportionaler Impuls entsteht. Die Entfernung ergibt sich rechnerisch als Produkt aus Schallgeschwindigkeit (344m/s) und der Laenge des Echo-Impulses. Da die Strecke vom Schall doppelt zurueckgelegt wird, ist das Ergebnis durch 2 zu dividieren"

...wobei ich das ja so versucht habe zu realisieren.

Blos irgendwie wird bei mir der Echoimpuls nie 1 obwohl ich relativ lang den Triggerimpuls gebe und alles mögliche schon probiert habe.

damaltor
29.05.2007, 22:29
vermutlich ist der triggerimpuls zu lang, so dass alles "voll" ist von ultraschallsignalen. dann kann kein eindeutiges echo empfangen werden.

ein solches programm sollte man in assembler programmieren, weil man dann taktgenaue zeitzyklen erreichen kann. so könnte man einen startimpuls geben der exakt 10 ms lang ist, und man könnte taktgenau die zeit messen. allerdings bin ich in assembler kein profi, das ist nicht ganz so einfach.

G_UNIT00101
30.05.2007, 15:05
Naja mit Assembler kenn ich mich auch nicht aus. Und da wird das ganze andere Zeugs wie Linienverfolgung und ähnliches bereits in C Programmiert haben muss nun der Ultraschallsensor auch in C Programmiert werden. Dann muss ich wohl noch dran arbeiten bis ich den Timer richtig zum laufen bringe. Vielleicht hat ja da einer ein Beispielprogramm für den ATEMEGA8 Timer.
Wäre sehr hilfreich.

Danke

m.a.r.v.i.n
31.05.2007, 08:58
Hi,

ein paar Dinge sind mir aufgefallen, warum dein Programm wahrscheinlich nicht funktionieren kann:

* Du schaltest in deinem Programm nicht den Triggerausgang PB.3 sondern PB.0. Zudem schreibst du den gesamten Port B und nicht nur den einzelnen Portausgang. Für den AVR in C funktioniert das so:


PORTB |= (1 << PB3); /* setzt Port B.3 auf HIGH */
PORTB &= (1 << PB3); /* setzt Port B.3 auf LOW */



* Wieso verwendest du überhaupt Port B.3? Dort wird nämlich beim Asuro die 36kHz Trägerfrequenz für die IR-LED ausgegeben. Besser wäre es, Port D.2 zu verwenden, dort hängt die rote Status LED dran.
* Die wait Funktion kommt mir sehr seltsam vor, dort werden sowohl die Register von Timer0 sowie Timer1 verwendet. Warum nimmst du nicht einfach die _delay_us Funktion aus der avrlibc.


#ifndef F_CPU
/* wenn F_CPU nicht bereits vorher definiert (z.B. durch
Übergabe als Parameter zum Compiler innerhalb des Makefiles) */
#define F_CPU 8000000UL /* Quarz mit 8 Mhz */
#endif
#include <util/delay.h> /* in älteren avr-libc Versionen <avr/delay.h> */

...

_delay_us(10); /* 10µs Delay */



* Das Einlesen des Ports D.6 für den Echo Impuls ist auch nicht ganz i.O. PORTx bezeichnet das Schreibregister eines Ports, PINx hingegen das Leseregister.


while ((PIND & (1<<PD6) ) == 0); /* solange warten, wie Port D.6 low ist */


Es geht auch mit den folgenden avrlibc Bibliotheksfunktion.



loop_until_bit_is_set (PIND,PD6); /* wartet bis Pin D.6 HIGH ist */
loop_until_bit_is_clear (PIND,PD6); /* wartet bis Pin D.6 LOW ist */


*Natürlich kannst du dir auch für deine Ports ein paar Defines überlegen, die aussagekräftiger sind.


#define TRIGGER_PORT PORTD
#define TRIGGER_PIN (1 << PD2)
#define ECHO_PORT PIND
#define ECHO_PIN PD6

...

TRIGGER_PORT |= TRIGGER_PIN; /* Trigger Port HIGH */
_delay_us(10); /* 10µs warten */
TRIGGER_PORT &= ~TRIGGER_PIN; /* Trigger Port LOW */


Viel Erfolg. Zum weiteren Studium empfehle ich dir das AVR-GCC Tutorial

Ronny10
02.06.2007, 09:12
Hallo m.a.r.v.i.n,

das funktioniert nicht:


PORTB |= (1 << PB3); /* setzt Port B.3 auf HIGH */
PORTB &= (1 << PB3); /* setzt Port B.3 auf LOW */


Das ist das Assemblerlisting dazu:


PORTB |= (1 << PB3); /* setzt Port B.3 auf HIGH */
9a: c3 9a sbi 0x18, 3 ; 24

PORTB &= (1 << PB3); /* setzt Port B.3 auf LOW */
9c: 88 b3 in r24, 0x18 ; 24
9e: 88 70 andi r24, 0x08 ; 8
a0: 88 bb out 0x18, r24 ; 24


So ist es richtig:


PORTB |= (1 << PB3); /* setzt Port B.3 auf HIGH */
PORTB = (PINB & (~(1 << PB3))); /* setzt Port B.3 auf LOW */


Das Assemblerlisting dazu:


PORTB |= (1 << PB3); /* setzt Port B.3 auf HIGH */
9a: c3 9a sbi 0x18, 3 ; 24

PORTB = (PINB & (~(1 << PB3))); /* setzt Port B.3 auf LOW */
9c: 86 b3 in r24, 0x16 ; 22
9e: 87 7f andi r24, 0xF7 ; 247
a0: 88 bb out 0x18, r24 ; 24


Du musst das Pinregister lesen und den geänderten Wert zum Portregister schreiben!

Oder du benutzt zum Setzen und Rücksetzen der Bits gleich die alten GCC-Macros:



#define sbi(p,b) p|=(1<<(b))
#define cbi(p,b) p&=(~(1<<(b)))

sbi( PORTB, PB3 ); // setze bit3 portb
cbi( PORTB, PB3 ); // rücksetze bit3 portb


Ronny10

m.a.r.v.i.n
02.06.2007, 21:06
Hy Ronny10,

danke für den Hinweis. Stimmt natürlich, beim Löschen von Bits müssen die zu löshenden Bits noch invertiert werden. :oops:

So sollte es auch gehen:


PORTB &= ~(1 << PB3); /* setzt Port B.3 auf LOW */

G_UNIT00101
03.06.2007, 16:36
MHM jetzt kapier ich gar nichts mehr.

Könntet ihr vielleicht wenn ihr Antworten schreibt nicht irgendwelche vorgefertigten Funktionen nutzen, da wir unser komplettes Asuro Projekt mit eigens Entwickelten Funktionen realisieren. Wäre echt nett.

Des weiteren muss ich jetzt nochmal was bezüglich des SRF04 Fragen.


Um eine Messung zu starten, wird ein Impuls (TTL-Pegel, mind. 10us) an den Triggereingang gelegt. Der Wandler wird von der Ablaufsteuerung (PIC) fuer 200us (8 Zyklen, 40kHz) getaktet und der Echo-Ausgang des Moduls auf High gelegt. Das erste hereinkommende Echo schaltet den Echo-Ausgang wieder auf Low, so dass ein direkt zur Entfernung des Objektes proportionaler Impuls entsteht. Die Entfernung ergibt sich rechnerisch als Produkt aus Schallgeschwindigkeit (344m/s) und der Laenge des Echo-Impulses. Da die Strecke vom Schall doppelt zurueckgelegt wird, ist das Ergebnis durch 2 zu dividieren:

hab diesen Text gefunden und jetzt wollte ich wissen ob der Echo-Ausgang automatisch auf High gesetzt wird oder ob man das bevor man den Triggerimpuls gibt selber machen muss??? Und dann hab ich noch die Frage wie ich denn genau das Echo Signal auswerten soll. Genügt es wenn ich einfach eine Schleife nehme und die solange hochzähle bis das Echo Signal 0 ist.

Des weitern wollte ich nochmal Fragen ob mir jemand ein Beispiel für einen Timer des ATMEGA8 hat. Das heißt den Befehl wie ich den Timer initialisieren muss, starte, Timer Flag abfrage usw.

Vielan Dank !!!!!!!!

ehenkes
03.06.2007, 18:45
Meinst Du so etwas? outp ((1<<CS01) | (1<<CS00), TCCR0); (8-Bit Timer/Counter starten, zählt nun ständig mit 1/64 des CPU-Takts von 0 bis 255. Bei jedem Überlauf von 255 auf 0 wird das Timer Overflow Flag TOV0 im Timer Interrupt Flag TIFR Register gesetzt. Damit kann ein entsprechender Interrupt ausgelöst werden (Beispiel: AT90S2313).

http://ulrichradig.de/site/infos/pdf/AtmelCprogramming.pdf

siehe Datenblatt ATmega8(L)_doc2486.pdf ab Seite 106.

und vor allem hier: https://www.roboternetz.de/wissen/index.php/Timer/Counter_%28Avr%29

G_UNIT00101
03.06.2007, 20:19
Ja so etwas habe ich schon gemeint, nur wundert es mich dass ich den Timer allein durch den einen Befehl starte und sonst nichts einstellen muss.

Dass heißt dann ich kann so eine Timerfunktion schreiben:



void timer(){
TCCR0 = 0x05;
TIFR = 0;
while(TIFR == 0);
TIFR = 0;
}


Ich bin es in der Schule gewöhnt wo wir ein Trainigsboard haben allerdings mit einem anderen µController dass man ebenfalls einen wert einstellen muss sodass der Timer z.b. anstatt von 0 bei 100 anfängt um so genau zu sagen wie lang der timer für einen durchlauf benötigt.

In der Schule haben wir das immer so gemacht:



void wait(){
TR0 = 0; // Timer wird gestoppt
TL0 = (0xffff-16666)%256; // Einstellung für
TH0 = (0xffff-16666)>>8; // 10ms Timer
TF0 = 0; // Timer Flag wird auf 0 gesetzt
TR0 = 1; // Timer wird gestartet
while(TF0 == 0); // warten solange Timer läuft
TF0 = 0; // Timer wird wieder gestoppt
}

Um den Wert der von 0xffff abgezogen wird zu berechen haben wir diese Formel verwendet:

Anzahl der Takte = Zeit(z.B. 10ms) / 0,6µs = 16666

Ist sowas hier bei dem Timer des ATMEGA8 nicht nötig oder möglich?????

Danke

damaltor
06.06.2007, 08:24
der echo eingang des prozessors ist normalerweise auf low. wenn der echo impuls ankommt, wird er high gemacht, und die zeit in der er high ist bevor er wieder low wird, die muss gemessen werden.

G_UNIT00101
06.06.2007, 21:52
Ja das hab ich jetzt mittlerweile auch alles herausbekommen, danke aber trotzdem. Bei mir funktioniert jetzt glücklicherweise die Distanzmessung via Ultraschall und ich brauche daher keine Hilfe mehr von euch. Danke nochmal dass ihr alle geholfen habt.

damaltor
08.06.2007, 10:16
zeig mal deinen programmcode!

G_UNIT00101
11.06.2007, 20:01
Also hier man Quellcode:

Die nötigen Konstanten:


// Konstanten
#define TRIGGER_IMPULS PORTB.3
#define ECHO_PIN PIND.6


Diese Funktio ist zunächst mal für den Triggerimpuls:


// Funktion um Triggerimpuls zu erzeugen
void trigger(){
unsigned int i;
TRIGGER_IMPULS = 1;
for(i = 0;i<1000;i++);
TRIGGER_IMPULS = 0;
}

Diese Funktion dient dann zum eigentlich Messen des Abstandes:


// Funktion zum messen der Distanz zwischen Roboter und Gegenstand
unsigned int distanzmessen(){
unsigned int entfernung;
entfernung = 0;
trigger();
while(ECHO_PIN == 0);
while(ECHO_PIN == 1){
entfernung++;
}
return entfernung;
}


Und zum Schluss noch eine Funktion mit dem man dass ganze Auswertet und dementsprechende Dinge ausführt wie anhalten und fahren:


// Funktion zum anhalten wenn ein Gegenstand im Weg ist
void vorgegenstandhalten(){
unsigned int l, entfernung2;
entfernung2 = distanzmessen();
for(l = 0;l<0xffff;l++);
if(entfernung2 <= 2000){
Motorstop();
}else if(entfernung2 > 2000){
Motorvor();
}
}

Vielleicht hilf es ja noch jemandem weiter

Danke nochmal an euch alle!!!!!