Archiv verlassen und diese Seite im Standarddesign anzeigen : Verständnisproblem beim IRCollisionTest-Testprogramm
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 & 0x08)
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 }
radbruch
01.12.2009, 18:21
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:
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:
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:
/************************************************** *****************************
*
* 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;
}
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 :-k 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
radbruch
06.02.2010, 01:19
Hallo
Aus dieser Grundfunktion ist bei mir dann das entstanden:
http://i2.ytimg.com/vi/5exIBE11L04/2.jpg (http://www.youtube.com/watch?v=5exIBE11L04)
(Aus: ProBot mit asuro-Mega8 (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=459661#459661))
Das Programm verwendet diese ACS(AntiCollisionSystem)-Funktion:
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:
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:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=480524#480524
Gruß
mic
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 ? #-o
Hendrik
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.