PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Artikel zu Sensorplatine mir GP2D02 von Sharp



Frank
05.12.2003, 20:53
Bereitgestellter Artikel von DCD-Robotik

Was wäre der beste ROBO ohne Sensoren ?

"NICHTS". Ohne Sensoren hätte der arme Kerl keine Chance sich in der rauen, eigentlich für Menschen (Haus, Hof, Wohnung) angepassten Umgebung, zurechtzufinden. Um dieser Tatsache gerecht zu werden bedient sich der Roboterentwickler der Sensorik, um seinem Schützling die Möglichkeit zu geben sich ein Bild von seiner Umwelt zu machen. Dieser Bericht beschreibt ein kleines Controller-Board mit dem ein Roboter das "Sehen" lernt. Eigentlich müsste es heißen das "Tasten" lernt. Denn die hier zum einen beschriebenen Sensoren tasten mittels Licht (Infrarot) die Umgebung ab und liefern einen Messwert der die Entfernung zu einem Hindernis repräsentiert. Man nennt diese Art der Sensoren auch Nährungssensoren. Für unser Controller-Board verwenden wir den Nährungssensor GP2D02 von Sharp. Dieser Sensor kann Hindernisse in einem Bereich von etwa 10 bis 80cm erfassen und liefert seine Messergebnisse in digitaler (serieller) Form. In Verbindung mit einem kleinen Mikrocontroller ergibt sich aus dieser Kombination ein schlagkräftiges Team gegen Hindernisse. Ein kleiner Wehrmutstropfen bleibt jedoch. Bei dieser Art der Abstandsmessung hängt die Güte des Messergebnisses sehr stark vom Messobjekt ab. Besser gesagt vom Reflexionsgrad des Messobjekts. Dies hat für die Praxis den Nachteil, dass je nach Material, Farbe, und Beschaffenheit des Hindernisses der ermittelte Messwert variiert. Um dieses Problem zu beseitigen oder zumindest zu kompensieren gibt es eine Reihe von Möglichkeiten. Zum einen wäre da die Kombination mit anderen Nährungssensoren wie z.B. Ultraschall oder man führt mehrere Messungen hintereinander durch und bildet den Mittelwert usw.. Für die meisten Anwendungen ist das gewonnene Messergebnis jedoch ausreichend, geht es doch darum überhaupt erst mal ein Hindernis zu erkennen. Grundsätzlich ist an dieser Stelle zu sagen, dass gerade größere Systeme wie der AMR-10 mit einem zusätzlichen Auffahrschutz ausgestattet sein sollten. Es kann immer vorkommen, dass der Nährungssensor z.B. in einem falschen Winkel zum Hindernis steht und sozusagen ins Leere abtastet. Um dieses Risiko so gering wie möglich zu halten, sollte man entweder mit mehreren Sensoren arbeiten, oder man verwendet einen Servo der den Sensor hin und her dreht und somit seine Umgebung über einen großen Bereich scannt. Der hier vorgestellte Sensor-Controller bietet vier Nährungssensoren und zwei PIR-Bewegungsmeldern Anschluss. Womit wir schon beim nächsten Thema wären. Im Gegensatz zu dem beschriebenen Nährungssensor macht es der PIR-Bewegungsmelder (Passiv InfraRot) genau umgekehrt. Diese Sensor-Art sendet kein Licht aus, sonder wertet die Wärmestrahlung der Messobjekte aus. Da die Bewegungssensoren ihren Sinn in der Erkennung von Menschen und Tieren haben, sind diese Sensoren auf die Wärmestrahlung lebender Körper optimiert. Der in diesem Bericht verwendete Sensor PIR-T1-M1-L0 stammt von der Firma HYGROTEC MESSTECHNIK und stellt beim AMR-10 die Augen im Kopf-Bausatz dar. Betrachtet man sich das Datenblatt dieses Sensors, so fällt einem auf, dass in der Anschlussleiste des Sensors auch das analoge Signal herausgeführt wird. Mit diesem Analogsignal ließe sich so einiges anstellen, über die Signalamplitude (Schwingungsweite) ließe sich auf den Abstand und die Größe eines Objekts schließen. Mit der Signalfrequenz (Schwingungen pro Sekunde) könnte man die Winkelgeschwindigkeit eines bewegten Objekts bestimmen.
Auf unserem Controller-Board machen wir hiervon jedoch keinen Gebrauch. Wir verwenden die interne Auswerteschaltung des Sensors, und können somit nur eine Aussage über Objekte, "da" oder "nicht da", machen. Das ist für den Zweck der Raumüberwachung durchaus ausreichend. Da der AMR-10 zwei dieser Sensoren sein Eigen nennt, kann man bei der gewählten Anordnung auch die Richtung aus der sich ein Objekt nähert erkennen. Soweit so gut. Wenden wir unser Augenmerk dem Controller-Board selbst zu und werfen einen Blick auf den unten abgebildeten Schaltplan. Leider wird das Bild des Schaltplans in dieser Größe nicht sonderlich gut dargestellt. Durch einen "KLICK" auf den Schaltplan gibt es das ganze auch in XXL lesbar oder Sie drucken den Plan einfach aus.

Abbildung hier:
http://www.dcd-robotik.de/Startseiten/Bilder/ROBOCON-AS_sch.jpg

Für alte Controller-Hasen bietet die kleine Leiterkarte nichts aufregendes. Es ist alles dort wo man es auch vermutet hätte. Für die ausreichende Reset-Zeit sorgt eine altehrwürdige RC-Kombination (R1 und C5). Für den richtigen Takt sorgt ein 12Mhz Quarz (Q2) nebst zwei keramischen Kondensatoren (C4,C3) als Anschwinghilfe. Damit die Versorgungsspannung nicht total verunreinigt wird findet man an allen relevanten Stellen die typischen 100nF Blockkondensatoren. Dazu gibt es dann noch C6 mit 100µF (ELKO) der als Energiespeicher dient. Erwähnenswert wäre da noch R22 der dafür sorgt, dass der Controller nicht den RS485-Bus blockiert, wenn dieser nicht richtig arbeitet. Die zwei LED's werden direkt von den Controller-Pins angesteuert und zeigen zum einen den RUN-Status und die Datenübertragung an. Unbedingt notwendig sind diese beiden LED' s nicht, sie sind bei der Programmierung und/oder bei der Fehlersuche sehr hilfreich. Für die beiden PIR-Sensoren ist bei dieser Leiterkarte auch kein großer Aufwand nötig, da wie oben beschrieben die Auswerteelektronik schon integriert ist, begnügen sich die beiden PIR-Sensoren mit jeweils einem Pullup-Wiederstand gegen VCC (+5V). Etwas eigenartig fallen die vier Dioden an den Anschlüssen für die GP2D02 Sensoren auf. Die Dioden befinden sich in Sperrrichtung vor den VIN Eingängen der GP2D02 Sensoren. Ein Blick in das Datenblatt des Sensors gibt Aufschluss. Der Sensor verträgt an diesem Anschluss nur 3V !! Die Dioden sorgen dafür, dass die Spannung, wenn die Controller-Pins High-Pegel führen, nicht diesen Wert übersteigt. Wie funktioniert das ? Der Sensor hat intern einen "Pullup - Wiederstand" gegen 3V. Wenn das Controller-Pin High-Pegel führt, ist die Diode in Sperrrichtung, sodass nur der "Pullup" des Sensors den eigenen Eingang auf 3V hält und somit ist für den GP2D02 der VIN Eingang auf High und die Welt in Ordnung. Wenn der Controller seinen Eingang auf Low legt wird die Diode in Durchlassrichtung betrieben. Der VIN Eingang führt dann die gleiche Spannung wie der Controller-Pin 0V. Das bedeutet für den Sensor Low-Pegel. Somit ist die Schaltung in der Lage die benötigten Zustände High und Low für den Sensor darzustellen. Eine genaue Beschreibung des Protokolls für die GP2D02 Sensoren können Sie dem Datenblatt entnehmen. Als Schnittstelle zur Außenwelt besitzt diese kleine Schaltung eine RS458-Anbindung zur Kommunikation mit der Main-CPU. Es ist auch ohne weiteres möglich anstelle der RS485 eine RS232 Schnittstelle einzusetzen. Dann werden nur ein par kleine Änderungen in der Software notwendig. Diese Schaltung lässt sich auch ohne große Anstrengungen mit einem AVR90S2313 aufbauen. Diese Bausteine können mit Ihrem SPI-Interface besser programmiert werden. Bei diese Gelegenheit sei auf die AVR2313 Mini-Module von Embendit hingewiesen, mit diesen Modulen wird der ganze Aufbau einer eigenen Schaltung stark vereinfacht. Ohne Software läuft auch bei dieser Mikrocontroller-Schaltung nichts. Darum folgt hier die Software als Quelltext. Der Quelltext ist in BASCOM-8051 geschrieben und soll nur zur Anregung für eigene Entwicklungen dienen. Als Erläuterungen dienen die Kommentarzeilen im Quelltext.
Nach einem Telefonat mit der Firma Micromaus erfuhren wir, dass diese Sensortype nicht mehr lieferbar ist. Aus diesem gegebenen Anlass werden wir einen Artikel nachreichen, der auf verfügbare Sensoren eingeht.

Im nächsten Artikel beschäftigen wir uns mit der Implementierung des S.N.A.P. Protokolls, dass für diese Aufgabe hervorragend geeignet ist.

Nachtrag:
In der Schaltung hat sich ein kleiner Fehler eingeschlichen.
R22 muss natürlich gegen Masse und nicht gegen +5V. Sonst würde der RS485 Bus doch blockiert werden wenn der Kontroller im Rest steht oder ähnliches.




-------------------------------------------------------------------------------
' (c) 2001 DCD GmbH Computeretwicklung
'-------------------------------------------------------------------------------
' file: Robocon_as.BAS
' autor: Jürgen Lange
' stand: 07.05.2003
'Programm zur Abfrage der Sensoren von AMR10-WOLF.
'Das Programm erkennt Hindernisse bis zu 80cm von AMR10-Wolf
'-------------------------------------------------------------------------------
Dim X_adress As Byte , X_chksum As Byte , My_x_chksum As Byte , Wert As Byte
Dim Data1 As Byte , Data2 As Byte , Data3 As Byte , Data4 As Byte
Dim Data5 As Byte , Data6 As Byte , Sensor As Byte
Dim X_data1 As Byte , X_data2 As Byte , X_data3 As Byte , X_data4 As Byte
Dim X_data5 As Byte , X_data6 As Byte

Declare Sub Sub_checksum()
Declare Sub Sub_clear_rx_buf()
Declare Sub Sub_sensor_gp_1(wert As Byte)
Declare Sub Sub_sensor_pir_1(wert As Byte)
Declare Sub Sub_sensor_pir_2(wert As Byte)

Config Timer0 = Timer , Gate = Internal , Mode = 1

'we use conditional compilation for the optional spi int
Const Spi = 0
Const Stick_adress = 140 'Adresse des Moduls
Const _ack = 6
Const _nak = 21

'zuerst teilen wir dem Compiler mit welche Routinen er
'für die serielle Ein-/Aus-gabe verwendensoll
$serialoutput = Sendchar
$serialinput = Recchar

'jetzt benötigen wir einpaar Variablen um den Dateneingang und die Pointer zu speichern
'buf() ist ein array das die Eingangsdaten speichert
'wpos ist ein pointer der auf die lezte Position zeigt auf die gespeichert wurde
'rpos ist ein pointer der auf die letzte Position zeigt von der gelesen wurde
'rcount ist ein byte das die Anzahl der Byts die im Puffer warten speichert
Dim Buf(10) As Byte , Wpos As Byte , Rpos As Byte , Rcount As Byte

'Jetzt teilen wir dem Compiler mit wo er hinspringen soll wenn ein INT auf der seriellen
'Schnittstelle ausgelöst wird.
On Serial Isr_ser Nosave
'On Timer0 Timer_0_int
'Enable Timer0
'wir müssen den INT freigeben
Enable Serial
'die globale Interrupt Freigabe muss auch erteilt werden
Enable Interrupts
Rem Einstellung der Interrupt-Priorität
Priority Set Serial 'höchste Priorität

'Normalerweise stellt der Compiler die Schnittstelle so ein mov scon,#82 to enable TI,
'wir überschreiben diese Einstellung so ist TI nicht eingeschaltet
mov scon,#80

'Counter0 = 35535 'when the timer reaches 5ms an interrupt will occur
'Start Timer0 'start the timer
'************************************************* ******************************
'** Setze die Aliasnamen für die Ports
'************************************************* ******************************
Pir_1 Alias P3.2
Pir_2 Alias P3.3
Gp_clk_1 Alias P1.1
Gp_data_1 Alias P1.0
Led_run Alias P3.5
Led_data Alias P3.4
Tx_rx_rs485 Alias P3.7

'************************************************* ******************************
'** Selbsttest und Initialisierung
'************************************************* ******************************
Data1 = 0 'Variablen vorbelegen
Data2 = 0
Data3 = 0
Data4 = 0
Data5 = 0
Data6 = 0
Wert = 0

Reset Tx_rx_rs485 'RS485 auf Empfang schalten
Reset Led_run 'Run LED kurz einschalten
Reset Led_data 'Data LED kurz einschalten

Set Pir_1 'Setze Eingaenge PIR Sensoren
Set Pir_2

Set Gp_data_1 'Setze Sharp Sensor Eingaenge
Set Gp_clk_1


Set Led_data 'Data LED kurz ausschalten
'The end of the test - sequence
'This is our actual program
'************************************************* ******************************
'** Main Loop
'************************************************* ******************************

Do

Reset Led_run
Set Led_data

If Rcount >= 6 Then 'Check serial of input data
Reset Led_data
X_adress = Inkey() 'read adress from buffer
X_data1 = Inkey() 'read data from buffer
X_data2 = Inkey() 'read data from buffer
X_data3 = Inkey() 'read data from buffer
X_data4 = Inkey() 'read data from buffer
X_data5 = Inkey() 'read data from buffer
X_chksum = Inkey() 'read data from buffer
'<---------------- calculate and check the checksum
Call Sub_checksum()
If My_x_chksum = X_chksum Then 'is checksum ok?
If X_adress = Stick_adress Then 'is adress my adress?
Select Case X_data1
Case 0 To 5:
Data1 = X_data1 'Werte zur Verarbeitung in Data sichern
Data3 = X_data3
Data4 = X_data4
Data5 = X_data5
Data6 = X_data6
X_data1 = _ack ' alles ok
X_data2 = 0
X_data3 = 0
X_data4 = 0
X_data5 = 0
X_data6 = 0
Case 7: '<--- sende Ergebnis der Messung von X
X_data1 = Sensor ' Nummer des Sensors
X_data2 = Wert ' Wert der Messung
X_data3 = 0
X_data4 = 0
X_data5 = 0
X_data6 = 0
Case Else: 'Fehler unbekanntes Kommando
X_data1 = _nak 'nichts ok
X_data2 = 0
X_data3 = 0 'aktuelle Werte für Counter rechts
X_data4 = 0
X_data5 = 0 'aktuelle Werte für Counter links
X_data6 = 0
Data1 = 0 'Alle Werte in Data loeschen
Data3 = 0
Data4 = 0
Data5 = 0
Data6 = 0
End Select
X_adress = 255 'set master adress
X_chksum = 0
My_x_chksum = 0
Call Sub_checksum() 'berechne Pruefsumme
X_chksum = My_x_chksum 'Prüfsumme zum Senden umkopieren
Call Sub_clear_rx_buf() 'clear receive buffer
Set Tx_rx_rs485 'Set Rs485 to sending
Waitms 50
Printbin X_adress ; X_data1 ; X_data2 ; X_data3 ; X_data4 ; X_data5 ; X_chksum;
Waitms 10
Reset Tx_rx_rs485 'Set Rs485 to receiving
End If
Else
X_adress = 0 'set all bytes to 0 on error
X_data1 = 0
X_data2 = 0
X_data3 = 0
X_data4 = 0
X_data5 = 0
X_chksum = 0
Data1 = 0 'Alle Werte in Data loeschen
Data2 = 0
Data3 = 0
Data4 = 0
Data5 = 0
Data6 = 0
Call Sub_clear_rx_buf() 'clear receive buffer on error
End If
End If

Select Case Data1
Case 0:
Call Sub_sensor_gp_1(wert) 'Starte Messung Sensor
Sensor = 0 'Rueckgabewert von Sensor Nr
Case 1:
Call Sub_sensor_gp_1(wert) 'Starte Messung Sensor
Sensor = 1 'Rueckgabewert von Sensor Nr
Case 2:
Call Sub_sensor_gp_1(wert) 'Starte Messung Sensor
Sensor = 2 'Rueckgabewert von Sensor Nr
Case 3:
Call Sub_sensor_gp_1(wert) 'Starte Messung Sensor
Sensor = 3 'Rueckgabewert von Sensor Nr
Case 4:
Call Sub_sensor_pir_2(wert) 'Starte Messung PIR Sensor
Sensor = 4 'Rueckgabewert von PIR Sensor Nr
Case 5:
Call Sub_sensor_pir_1(wert) 'Starte Messung PIR Sensor
Sensor = 5 'Rueckgabewert von PIR Sensor Nr
Case Else
Sensor = Data1
Wert = 0
End Select
Loop
End

'************************************************* ******************************
'** Messe Entfernung Sensor 1
'************************************************* ******************************
Sub Sub_sensor_gp_1(wert As Byte)

Set Gp_data_1
Reset Gp_clk_1
Waitms 70
Set Gp_clk_1
'SHIFTIN pin , pclock , var , option [PRE]
Shiftin Gp_data_1 , Gp_clk_1 , Wert , 0
Set Gp_clk_1
Waitms 2
End Sub
'************************************************* ******************************
Messe Bewegung Sensor 1
Diese Sub muss bei 4 Sensoren 4x vorhanden sein. Nur der SUB
Name und die Pins ändern sich sonst bleibt alles gleich.
'************************************************* ******************************
Sub Sub_sensor_pir_1(wert As Byte)

Wert = 0 'Wert auf 0
If Pir_1 = 0 Then 'PIR 1 noch mal abfragen ein Spike auf der Leitung war
Waitms 10 'Entprellzeit
If Pir_1 = 0 Then Wert = 1 'PIR 1 nochmal abfragen
Else
Wert = 0 'PIR nicht gesetzt Wert = 0
End If

End Sub
'************************************************* ******************************
'** Messe Bewegung Sensor 2
'************************************************* ******************************
Sub Sub_sensor_pir_2(wert As Byte)

Wert = 0 'Wert auf 0 falls ein Spike auf der Leitung war
If Pir_2 = 0 Then 'PIR 2 abfragen
Waitms 10 'Entprellzeit
If Pir_2 = 0 Then Wert = 1 'PIR 2 nochmal abfragen
Else
Wert = 0 'PIR nicht gesetzt Wert = 0
End If

End Sub
'************************************************* ******************************
'** Loesche den Empfangspuffer
'************************************************* ******************************
Sub Sub_clear_rx_buf()
Wpos = 0
Rpos = 0
Rcount = 0
End Sub
'************************************************* ******************************
'** Berechne Prüfsumme
'************************************************* ******************************
Sub Sub_checksum()
My_x_chksum = X_adress Xor X_data1
My_x_chksum = My_x_chksum Xor X_data2
My_x_chksum = My_x_chksum Xor X_data3
My_x_chksum = My_x_chksum Xor X_data4
My_x_chksum = My_x_chksum Xor X_data5
End Sub
'************************************************* ******************************
'** Timer 0 Interrupt
'************************************************* ******************************
Rem The Interrupt Handler For The Timer0 Interrupt
Timer_0_int:

Stop Timer0 'Timer nur zur Sicherheit stoppen


'Timer neu laden und starten
Counter0 = 35535 'when the timer reaches 50ms an interrupt will occur
Start Timer0 'start the timer

Return
'************************************************* ******************************
'** Serielle Schnittstelle
'************************************************* ******************************
Dieser Code ist bei BASCOM-8051 schon mit dabei.
'we use some asm
$asm
Sendchar:
Mov sbuf, a ; write the data
Jnb scon.1, *+0 ; wait until it is ready
Clr scon.1 ; disable TI
ret

' That Was Easy


Recchar:
mov a,{rcount} ; get the number of bytes waiting in the buffer
jz recchar ; when zero try again
push h'00 ; now we must save the used registers
push psw

mov r0,#{buf} ; load the address of the buffer
mov a,{rpos} ; load the last read position
add a,r0 ; add it
mov r0,a ; put back in r0
mov a,@r0 ; get it out of the buffer
inc {rpos} ; increase the read pointer
dec {rcount} ; 1 char less waiting
push acc ; save the byte we retrieved from the buffer
mov a,{rpos} ; get the read pos
cjne a,#10, recchar_exit ; is it past the size of the buffer
mov {rpos},#0 ; reset it to the begin
Recchar_exit:
pop acc ; restore byte
pop psw ; restore registers
pop h'00
ret ; return

$end Asm


'this is the ISR that gets fired when TI or RI gets set
Isr_ser:
push acc
push h'00 ; save used registers
push psw
jnb scon.0, .isr_tx ; was RI causing the interrupt?
mov a,{wpos} ; get write position
mov r0,#{buf} ; load address of buffer
add a,r0 ; add it
mov r0,a ; back to r0
mov @r0,sbuf ; store the char in the buffer
inc {wpos} ; increase write pointer
inc {rcount} ; and we have one char more waiting
clr scon.0 ; clear RI
mov a ,{wpos} ;get the write pointer
cjne a,#10,.isr_exit ;is it past the size?
Mov {wpos},#0 ; reset it
sjmp .isr_exit ;exit
Isr_tx:
' TI Caused The Int But It Gets Reset In The Sendchar Routine

'optional for the 8252 that has a shared SPI interrupt you can add the following code
#if Spi
mov a,spsr ; get status register
jnb acc.7, .isr_exit ; it was not the SPI that caused the int
mov spsr,#255 ; to clear the int flag spif and wcol must be set
mov a,spdr ; by reading the data register the int gets cleared
'now we can store the data this is not implemented
'note that acc gets popped so acc will be destroyed

#endif


Isr_exit:
pop psw ; restore regs
pop h'00
pop acc
Return


Dieser Artikel wurde bereitgestellt von http://www.dcd-robotik.de/