-         

Ergebnis 1 bis 5 von 5

Thema: Verständnisproblem beim IRCollisionTest-Testprogramm

  1. #1

    Verständnisproblem beim IRCollisionTest-Testprogramm

    Anzeige

    Hey Leute,

    habe ein Verständnisproblem zum IRCollisiontestprogramm,
    ich hab den IRSensor umgelötet, das Programm aufgespielt,
    es klappt auch. Nur leider verstehe ich aufgrund der Microcontroller programmierung kein Wort von der Source.
    Kann mir jemand die einzelnen Abläufe erklären, bzw. hat jemand das Programm ausdokumentiert?

    Das wäre mir wirklich eine große Hilfe

    Hier ist das Programm nochmal (quelle: AsuroWiki)

    00001 /************************************************** *****************************
    00002 *
    00003 * Description: Asuro IR-Detektor Testprogramm
    00004 *
    00005 ************************************************** ***************************/
    00006 /************************************************** *************************
    00007 * *
    00008 * This program is free software; you can redistribute it and/or modify *
    00009 * it under the terms of the GNU General Public License as published by *
    00010 * the Free Software Foundation; either version 2 of the License, or *
    00011 * any later version. *
    00012 ************************************************** *************************/
    00013 #include "asuro.h"
    00014 #include <stdlib.h>
    00015
    00016 static unsigned char ocr2 = 0x91;
    00017
    00018 void InitIRDetect(void)
    00019 {
    00020 UCSRB = 0;
    00021 DDRD |= (1 << DDD1); // Port D1 als Ausgang
    00022 PORTD &= ~(1 << PD1); // PD1 auf LOW
    00023 OCR2 = ocr2;
    00024 }
    00025
    00026 void InitUart(void)
    00027 {
    00028 OCR2 = 0x91; // duty cycle fuer 36kHz
    00029 }
    00030
    00031 int main(void)
    00032 {
    00033
    00034 unsigned char sw;
    00035
    00036 Init();
    00037
    00038 DDRD |= (1 << DDD1); // Port D1 als Ausgang
    00039 PORTD &= ~(1 << PD1); // PD1 auf LOW
    00040
    00041 // InitIRDetect();
    00042 while (1)
    00043 {
    00044 UCSRB = 0;
    00045 OCR2 = 0xFE;
    00046
    00047 if (PIND & (1 << PD0))
    00048 StatusLED(GREEN);
    00049 else
    00050 StatusLED(RED);
    00051
    00052 sw = PollSwitch();
    00053 if (sw & 0x01)
    00054 ocr2 = 0xFE; //Pulsbreite 1
    00055 if (sw & 0x02)
    00056 ocr2 = 0xFD; //Pulsbreite 2
    00057 if (sw & 0x04)
    00058 ocr2 = 0xFB; //Pulsbreite 4
    00059 if (sw & 0x0
    00060 ocr2 = 0xF7; //Pulsbreite 8
    00061 if (sw & 0x10)
    00062 ocr2 = 0xEF; //Pulsbreite 16
    00063 if (sw & 0x20)
    00064 ocr2 = 0x90; //Pulsbreite 110
    00065
    00066 if (sw)
    00067 {
    00068 OCR2 = 0x91;
    00069 PrintInt(sw);
    00070 SerPrint(" ");
    00071 PrintInt(ocr2);
    00072 SerPrint("\r\n");
    00073 }
    00074 // Msleep(100);
    00075 }
    00076 return 0;
    00077 }

  2. #2
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    54
    Beiträge
    5.785
    Blog-Einträge
    8
    Hallo

    Dann testen wir mal ob ich die Funktion kapiert habe:

    Der TSOP IC2 (=IR-Empfänger) des asuro reagiert auf IR-Signale die mit 36kHz moduliert sind (es gibt auch welche für andere Frequenzen) und ist an Port PD0 des Mega8 angeschlossen. Die IR-LED D10 liegt mit der Anode an PB3 und mit der Kathode an PD1. Sie leuchtet, wenn PD1 ein auf low geschalteter Ausgang ist und an PB3 gleichzeitig ein high ausgegeben wird. (Senden mit dem USART muss mit "UCSRB = 0;" ausgeschaltet sein, sonst hat man keine Kontrolle über PD1!)

    "Zufällig" ist PB3 auch der Ausgangspin OC2 des Timer2. Deshalb wird der Timer so parametriert, dass er 36000 mal pro Sekunde den Ausgang auf high schaltet und ebensooft wieder auf low. Das ergibt dann eine Trägerfrequenz von 36kHz mit der die LED blinkt, wenn gleichzeitig PD1 ein low ausgibt.

    Dieser Absatz erklärt, wie das Timersetup funktioniert, das ist für das Verständniss der IR-Abstandsmessung nicht so wichtig: Beim Start des Counters wird der OC2-Pin auf low gesetzt, beim Erreichen des Wertes im OCR2-Register wird der OC2-Pin nach high umgeschaltet. Der Counter zählt dann weiter bis zum Überlauf, dann wird das Zählregister wieder auf null gesetzt und die Overflow-ISR angesprungen. Bei 8MHz dauert eine 36Khz-Periode ca. 222 Zähltakte, wenn man für den Counter keinen Prescaler verwendet. Beim Berechen des Counterstartwertes und des Umschaltpunktes setzt man nun am Besten am Ende einer Periode beim Überlauf des Zählregisters an. Für 111 Takte vor dem Überlauf muss man den Wert im OCR2-Register auf 256-111=145 oder 0x91 setzen, 222 Takte davor muss das Zählregister starten. Für das Laden des Zählregisters braucht man noch zusätzliche drei Takte: 256-222+3=37 oder 0x25. Die betreffenden Zeilen im Timersetup in asuro.c:
    Code:
    Im Init():
    
    	OCR2  = 0x91; // duty cycle for 36kHz
    
    In der ISR:
    
    SIGNAL (SIG_OVERFLOW2)
    {
    	TCNT2 += 0x25;
    ...
    Das += bewirkt, dass inzwischen schon erfolgte Zähltakte nicht ignoriert werden.

    Der TSOP erkennt nach maximal 12 Pegelwechseln der IR-LED, dass er angeblinkt wird und schaltet dann seinen Ausgang auf low. Dabei unterscheidet er weder zwischen direkter oder indirekter Einstrahlung, noch erkennt er den Abstand zu einem reflektierenden Gegenstand. Allerdings wird ein sich weiter entfernender Gegenstand irgendwann mal nicht mehr erkannt, weil die Menge an nutzbarem reflektiertem Signal für den TSOP zuwenig wird. Und genau hier setzt waste mit seinem Setup des Timers an: Man verkleinert den Signalanteil der Trägerfrequenz durch Veränderung des Impuls-Pauseverhältnisses. Das erreicht man durch Änderung des OCR2-Wertes. Je näher dieser Wert an 256 liegt, umso kürzer ist die Leuchtzeit der LED und umso näher muss sich ein Gegenstand befinden, wenn man ihn erkennen möchte.

    Beim eigentlichen Scanvorgang ändert man den Wert in OCR2, wartet kurz (12 Flanken sind 6 Perioden oder Sleep(6) ;) und prüft dann den Eingangspin PD0:

    OCR2 = 0xFE;
    if (PIND & (1 << PD0)) ....



    Bei der IR-Kommunikation muss das OCR2-Register wieder auf den normalen Wert gesetzt werden:
    Code:
    if (sw)
     {
     OCR2 = 0x91;
     PrintInt(sw);
     SerPrint(" ");
     PrintInt(ocr2);
     SerPrint("\r\n");
    }
    Achtung! Dabei wird der USART wieder eingeschaltet und kontrolliert PD1!

    Uff. Willkommen im RN-Forum.

    Gruß

    mic

    [Edit]Ungetestet:
    Code:
    /*******************************************************************************
    *
    * Description: Asuro IR-Detektor Testprogramm
    *
    *****************************************************************************/
    /***************************************************************************
    * *
    * This program is free software; you can redistribute it and/or modify *
    * it under the terms of the GNU General Public License as published by *
    * the Free Software Foundation; either version 2 of the License, or *
    * any later version. *
    ***************************************************************************/
    #include "asuro.h"
    #include <stdlib.h>
    
    static unsigned char ocr2 = 0x91; // Wert für 50:50 Pulsweite laden
    
    void InitIRDetect(void)
    {
    	UCSRB = 0;                    // USART ausschalten
    	DDRD |= (1 << DDD1); 			// Port D1 als Ausgang
    	PORTD &= ~(1 << PD1); 			// PD1 auf LOW
    }
    
    void InitUart(void)
    {
    	OCR2 = 0x91; 						// duty cycle fuer 36kHz
    }
    
    int main(void)
    {
    
    	unsigned char sw;
    
    	Init();                       // Library initialisieren
    	InitIRDetect();               // IR-Funktion initialisieren
    
    	while (1)
    	{
    		OCR2 = ocr2;               // Puls-Pause-Verhältniss setzen
    		Sleep(10);                 // kurz warten bis TSOP genügend Flanken erkennt
    
    		if (PIND & (1 << PD0))     // TSOP-Eingang auf IR Echo überprüfen
    		StatusLED(GREEN);          // kein Echo
    		else
    		StatusLED(RED);            // Echo!
    
    		sw = PollSwitch();
    		if (sw & 0x01)  				// K6 neben Schalter
    			ocr2 = 0xFE; 				//Pulsbreite 1
    		if (sw & 0x02)
    			ocr2 = 0xFD; 				//Pulsbreite 2
    		if (sw & 0x04)
    			ocr2 = 0xFB; 				//Pulsbreite 4
    		if (sw & 0x08)
    			ocr2 = 0xF7; 				//Pulsbreite 8
    		if (sw & 0x10)
    			ocr2 = 0xEF; 				//Pulsbreite 16
    		if (sw & 0x20)
    			ocr2 = 0x90; 				//Pulsbreite 110
    
    		if (sw)                    // bei Tastendruck Wert zum Terminal senden
    		{
    			InitUart();             // Pulsbreite für IR-Kommunikation setzen
    			PrintInt(sw);
    			SerWrite(" ",1);
    			PrintInt(ocr2);
    			SerWrite("\r\n",2);
    			InitIRDetect();         // Abstandsmessung aktivieren
    			Msleep(100);
    		}
    	}
    	return 0;
    }

    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  3. #3
    Hallo mic @radbruch,

    jetzt will ich mal das nachholen, was der mutige Fragensteller Mr. Osemann bis dato versäumt hat und mich für Deinen tollen Beitrag bedanken!!! Ich als Anfänger mit verstaubten BASIC Kenntnissen als Handwerkszeug (damals mit Papas Commodore plus 4) habe bei dem Code nämich auch "wie ein Schwein ins Uhrwerk" geschaut aber mit Hilfe Deiner Erklärung hab ich jetzt zumindest mal prinzipiell und ansatzweise verstanden was hier abläuft. (Respekt!)

    Übrigens hab ich auch mal Dein Beispielprogramm getestet, welches ich (zusammen mit Deiner Erklärung) viel verständlicher und besser finde, als das Original aus der Library. Obendrein funktioniert sogar besser, denn beim Originalcode haben die Tasten nicht angesprochen (zumindest bei mir nicht) Ich konnte sogar feststellen, dass sich beim Variieren des ocr2-Wertes die Sache sogar bedingt zur Abstandsmessung eignet: (je kleiner der ocr2 Wert, desto größer wird die Empfindlichkeit)

    Ich will hier mal ansetzen und versuchen eine IR-Wandverfolgung auf die Beine zu stellen ...mal sehen, ob's klappt.

    Grüße Hendrik

  4. #4
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    54
    Beiträge
    5.785
    Blog-Einträge
    8
    Hallo

    Aus dieser Grundfunktion ist bei mir dann das entstanden:


    (Aus: ProBot mit asuro-Mega8)

    Das Programm verwendet diese ACS(AntiCollisionSystem)-Funktion:
    Code:
    void ACSData(unsigned int *data)
    {
       UCSRB &= ~(1<<TXEN); // USART TX disable
    
       OCR2=0xff;
       DDRD |= (1<<PD1);
       PORTD &= ~(1<<PD1); // ACS LED left on
       while(PIND & 1)
       {
            acs=15;
          while(acs);
          OCR2--;
       }
       PORTD |= (1<<PD1); // ACS LED left  off
       data[0]=OCR2;
       while(!(PIND &1));
    
       OCR2=0xff;
       PORTB &= ~(1<<PB0); // ACS LED right on
       while(PIND & 1)
       {
            acs=15;
          while(acs);
          OCR2--;
       }
       PORTB |= (1<<PB0); // ACS LED right  off                            6
       data[1]=OCR2;
       while(!(PIND &1));
    
       OCR2=0x91; //36kHz
    }
    
    Die Variable acs wird dabei in der 36kHz-ISR nach jeder Periode des Signals verkleinert:
    
    volatile unsigned char count36kHz=0;
    volatile unsigned char acs=0;
    volatile unsigned long timebase=0;
    
    /* uses timer2 (36kHz for IR communication */
    SIGNAL (SIG_OVERFLOW2)
    {
       TCNT2 += 0x25;
       count36kHz ++;
       if (!count36kHz) timebase ++;
       if(acs) acs--;
    }
    Der Probot hat auf jeder Seite drei IR-LEDs mit denen man die Abstände auf jeder Seite messen kann. Die rechten IR-LEDs hängen an PB0. Die eigentliche Messung findet hier statt:
    Code:
       OCR2=0xff;
    ...
       while(PIND & 1)
       {
            acs=15;
          while(acs);
          OCR2--;
       }
    Beginnend mit OCR=255 (geringste Impulslänge) werden jeweils 15 Impulse im 36kHz-Takt gesendet und anschliesend der OCR2-Wert verringert. Das wird solange fortgesetzt wie der IR-Empfänger kein Trägersignal erkennt (sein Ausgang also high ist). Nach verlassen dieser Schleife ist der Wert in OCR2 ein Mass für den Abstand des reflektierenden Gegenstands. Das funktioniert hier ohne Timeout, weil ab einer gewissen Impulslänge immer irgendetwas im Raum erkannt wird.

    Wichtig ist nun noch, dass man abwartet, bis der IR-Empfänger nach dem Abschalten der IR-LED keine "verirrten" IR-Signale mehr empfängt bevor man eine neue Messung startet:

    while(!(PIND &1));

    Mit der bee sieht das dann übrigends so aus:
    http://www.roboternetz.de/phpBB2/zei...=480524#480524

    Gruß

    mic

    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  5. #5
    Hallo Mic,
    Danke nochmal für die Antwort. Das Programm, welches Du am 1.12. gepostet hast funktioniert zwar ansich super. ABER: Wenn parallel die Motoren laufen (hab das o.g. Programm einfach mal in den "Kollisionstest" eingepflanzt), dann scheinen da irgendwie zu viele Störungen reinzukommen, so dass zumindest bei der Empfindlichkeit (Taste 1-6) keine Unterschiede mehr zu erkennen sind. Evtl. werd ich während der IR-Abfrage die Motoren stoppen müssen, was dann aber vermutlich zu einem ekligen Summton beim Fahren führen wird...

    Egal - momentan konzentrier ich mich mehr auf die Hardware-Arbeiten für meinen Saug-Robi ...das mit der Wandverfolgung mach ich dann später, vielleicht sogar über Taster/Fühler oder sowas.

    Noch ne Frage:
    Hat hier eigentlich schon mal jemand ein ASURO-Board zerschnitten? [-X Das ist mir nämlich zu lang und passt nicht in das von mir vorgesehende Gehäuse/Design [-o< Ich dachte mir, die Leiterplatte direkt dort zu zersägen, wo die Motoren beginnen und die paar Verbindungen mit Kabeln wieder herzustellen. Any comments ?
    Hendrik

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •