Inhaltsverzeichnis
IR-bake für RP6 (Baustelle)
Verwendetes System:
RP6 V1, m32, multi-IO
Beweggründe, Ziele:
Im laufe des Projektes für die induktive Ladestation ergab sich die Frage, ob diese Ladestation auch zuverlässig mit Hilfe einer IR- bake gefunden werden kann.
Die Anleitung beschreibt den IST-Zustand des Projektes, ohne groß auf die Sackgassen und Irrwege aus der Entwicklungszeit einzugehen. Wenn aber irgendwo Bauteile oder Programmzeilen auftauchen, die ohne Hinweise auf diesen Prozess unverständlich wären, versuche ich detaillierter auf das Thema einzugehen. Wer den ganzen Weg nachverfolgen will (eigentlich empfehlenswert) kann es hier tun, Am Ende finden sich auch ein Paar Ideen was und wie man weitermachen könnte...
IR-bake http://www.roboternetz.de/community/threads/63467-IR-bake/page1
Mir ging es hier mehr oder weniger darum, nachzuweisen, dass es mit relativ geringem Aufwand möglich ist, mit Hilfe dieser IR-bake die Ladestation (oder was auch immer) über eine Entfernung von 5-6 Metern zu finden.
Last but not least – es soll eine Anleitung vom Anfänger für Anfänger sein, ich hoffe ich kann diesem Anspruch gerecht werden. Das Wort „einfach“ habe ich versucht zu vermeiden, für mich war es auch nicht einfach, trotz Hilfe aus dem Forum...
Eine reine Vorsichtsmaßnahme – jeglicher Nachbau geschieht auf eigenes Risiko...
hier sind die Ursprünge der Schaltungen:
IR-bake (Stromlaufplan und Beschreibung) http://www.robotroom.com/Infrared555.html
Blinker (astabile Kippstufe mit einstellbaren Zeiten) http://www.domnick-elektronik.de/elek555.htm
Und nun geht es zu der Anleitung...
IR-Empfänger
Als Empfänger soll der RP6 IR-Empfänger in unveränderter Form Verwendung finden
IR-Sender
Angefangen habe ich mit dem Aufbau des IR-Senders, experimentiert habe ich später – um die Leistung zu steigern - mit den Vorwiderständen der IR-LEDs und den Basiswiderständen des Q2. Die Werte im Stromlaufplan sind der letzte Stand.
Das Steckbrettmodell habe ich recht früh gegen eine gelötete Version getauscht, die Wackelkontakte beim Steckbrett haben mich gestört...
Die grüne LED (rote am Steckbrett) dient nur der grundsätzlichen Kontrolle ob die Schaltung läuft, ob die IR-LEDs leuchten kann man letztendlich nur mit einer digitalen Kamera sehen.
Die verwendeten IR-LEDs sind die gleichen, wie sie auch im RP6 verbaut sind (LD 271 L), 5 deshalb, weil man damit recht gut einen Halbkreis abdecken kann.
Die beiden USB-Stecker sind von der Funktion her nicht erforderlich, bei verschiedenen Testaufbauten haben sie sich aber auch als mechanische Halterungen für die bake und für den Test für den Abstand der IR-Strahlungsebene vom Boden bestens bewährt.
Im Verlauf der Tests habe ich verschiedene Bauteile nachträglich „gesockelt“, wenn jemand verschiedene Bauteilkombinationen testen will und sich spätere mühsame Lötarbeit ersparen will – der Steckbrettaufbau (zumindest meiner) eignet sich für solche Tests nicht - sollte es von vorne herein vorsehen (Widerstände in der Basisleitung des Q2, der Q2 selbst, Vorwiderstände der LEDs, der IC2, evtl. die IR-LEDs – wenn man leistungsfähigere einsetzen möchte.
Stromlaufplan des Senders:
Um die Funktion des Senders mit dem IR- Empfangssystem des RP6 auch testen zu können musste die Software für die Basis geändert werden:
in der "RP6Base_I2CSlave.c" wurde das Register 30 eingeführt:
(die Zeilennummern sind „meine“ Zeilennummern!)
Testaufbau IR- Sender
Die IR-bake wurde zunächst in diesem Testaufbau getestet:
Entfernung Sender - Empfänger ca. 30cm, mit geänderter Software für die Basis und der Bake – zunächst ohne die Blinkerplatine - wurde am Poti R6 die Sendefrequenz von 36kHz eingestellt:
das Foto links entspricht ca. 36kHz (7DIV und 5.95 Perioden), daneben die dazu notwendigen Einstellungen am Oszilloskop, rechts der Anschluss des OSZI an der Senderplatine (Masse und Kollektor von Q2).
hier noch eine Tabelle, mit der ich die Frequenz berechnet habe:
Ich kann mir auch vorstellen, dass man bei laufender Software am RP6 die Einstellung der 36kHz (mit der „readAllRegister“ Funktion und sendender bake) anhand des Empfangs oder eben keinen Empfangs am RP6 auch ohne Oszilloskops hin bekommt.
Die Versuche mit der IR-bake allein haben gezeigt, dass die Änderungen an den Vorwiderständen der IR-LEDs und den Basiswiderständen des Q2 bei den im Stromlaufplan angegebenen Werten Schluss ist, der Q2 wurde dann zu heiß ohne dass sich die Entfernung zwischen Sender und Empfänger nennenswert erhöhen ließ.
Um die Leistung des Senders zu erhöhen und die IR-LEDs vor Überhitzung und Ausfall zu schützen kommt jetzt der Blinker ins Spiel.
Blinkerschaltung:
Da die Senderplatine bereits fertig war, habe ich mich dazu entschlossen eine neue Schaltung quasi „huckepack“ auf die Lötseite der Senderplatine zu setzen, mit vier Stift- und Buchsenkontakten steckbar verbunden. Drei von ihnen verbindend, der vierte nur als mechanische Stabilisierung der oberen Leiterplatte. Die Kontakte haben „oben und unten“unterschiedliche Abstände, um falsches Stecken zu vermeiden. Durch die steckbare Blinkerplatine konnte ich die Blinkfrequenz unabhängig von der Senderplatine einstellen (Potis R1 und R2). Es ging aber auch mit Einzellitzen als Steckverbindungen zwischen der Sender- und Blinkerplatine (siehe Bilder im Abschnitt „Anpassung der Sende und Empfangsfrequenz zwischen RP6 und der bake“).
Vorsicht – die Senderschaltung funktioniert auch ohne die Blinkerplatine im „Dauerfeuer“, der Q2 auf der Senderplatine wird allerdings ziemlich heiß!
Stromlaufplan des Blinkers:
Testaufbau des Blinkers
Mit den Potentiometern R1 und R2 kann die Dauer der Ein- und Aus- Phasen des Blinkers eingestellt werden, siehe der Abschnitt „ Anpassung der Sende und Empfangsfrequenz zwischen RP6 und der bake“.
Man kann es sich beim Nachbau überlegen, ob man die beiden Leiterplatten zu einer zusammenfasst und eventuell statt zwei NE555 einen NE556 verwendet. Sicher möglich, aber das muss jeder für sich entscheiden. Wahrscheinlich vereinfacht es die Schaltung, evtl. aber wird die Einstellung der beiden Funktionen (Sender und und Blinker) erschwert.
IR-bake kpl.
Stromlaufplan kpl.
Der Stromlaufplan beider (hier zusammengesteckt und mit zwei NE555 versehen) Platinen zusammen:
Testaufbau IR-bake kpl.
Anpassung der Sende und Empfangsfrequenz zwischen RP6 und der bake
mit dieser Software wurden die Frequenzen aneinader angepasst:
/*********************ir_bake_test_anleitung.c**********************************/ #include "RP6ControlLib.h" #include "RP6I2CmasterTWI.h" #include "RP6Control_MultiIOLib.h" #include "RP6Control_I2CMasterLib.h" #include "RP6Control_LFSBumperLib.h" #include "RP6ControlServoLib.h" #include "standard.h" #include "navi_1.h" #define I2C_RP6_BASE_ADR 10 /******************variablen***************************/ uint8_t transmit_buffer[10]; uint8_t RP6data[32]; uint8_t i, j; uint8_t temp; uint8_t feld_IR[200]; uint8_t IR_wert[1]; /********************hauptprogramm*****************************/ int main(void) { initRP6Control(); multiio_init(); initLCD(); setLEDs(0b1111); mSleep(500); setLEDs(0b0000); I2CTWI_initMaster(100); I2CTWI_setTransmissionErrorHandler(I2C_transmissionError); //aktiviert I2C fehlermeldungen showScreenLCD(" RP6Control M32", " Ir_bake_test_anl", "", ""); mSleep(2500); clearLCD(); accuspannung(); mSleep(1500); while(true) { accuzustand(); /*****************anzeige gedrückter buttons****************/ clearLCD(); pressedMultiIOButtonNumber = getMultiIOPressedButtonNumber(); setCursorPosLCD(0, 0); writeStringLCD("1: einzelsignal"); setCursorPosLCD(1, 0); writeStringLCD("2: feldvariable_10ms"); setCursorPosLCD(2, 0); writeStringLCD("3: test_button_3"); setCursorPosLCD(3, 0); writeStringLCD("4: feldvariable_5ms"); mSleep(1500); uint8_t key = getMultiIOPressedButtonNumber(); /********************funktion der buttons*********************/ if(key) { switch(key) { case 1:// setLEDs(0b0001); writeString_P("\n\n messung einzelsignal\n"); initRP6Control(); initLCD(); // --------------------------------------- WDT_setRequestHandler(watchDogRequest); /*************************************************************/ while(true) { read_Register_30(); setMultiIOLED1(0); setMultiIOLED2(0); setMultiIOLED4(0); setMultiIOLED3(1); mSleep(100);//600, if (IR_wert[0] == 0) { setMultiIOLED1(1); setMultiIOLED3(0); mSleep(50);//500, 150 } // readAllRegisters(); // print_Register_30(); // mSleep(100); /**************************/ uint8_t key_1 = getMultiIOPressedButtonNumber(); key_1 = getMultiIOPressedButtonNumber(); if(key_1 != 0) break; /**************************/ } break; case 2:// setLEDs(0b0010); writeString_P("\n\n messung feldvariable step 10ms\n\n"); writeChar('\n'); initRP6Control(); initLCD(); while(true) { for(j = 0; j < 120; j+=10) { writeChar('\n'); writeInteger(j, DEC); writeChar('\n'); uint8_t i = 0; for(i = 0; i < 199; i++) { read_Register_30(); feld_IR[i] = IR_wert[0]; writeIntegerLength(feld_IR[i],DEC,4); if(i % 12 == 0) writeChar('\n'); else writeString_P(" | "); mSleep(20+j); } } /**************************/ uint8_t key_1 = getMultiIOPressedButtonNumber(); key_1 = getMultiIOPressedButtonNumber(); if(key_1 != 0) break; /**************************/ } break; case 3:// setLEDs(0b0100); while(true) { clearLCD(); setCursorPosLCD(0, 0); writeStringLCD("test button 3 "); mSleep(1500); clearLCD(); writeStringLCD("test break all "); mSleep(1500); /**************************/ uint8_t key_1 = getMultiIOPressedButtonNumber(); key_1 = getMultiIOPressedButtonNumber(); if(key_1 != 0) { break; } /**************************/ } break; case 4:// setLEDs(0b0010); writeString_P("\n\n messung feldvariable step 5ms\n\n"); writeChar('\n'); initRP6Control(); initLCD(); while(true) { for(j = 0; j < 120; j+=5) { writeChar('\n'); writeInteger(j, DEC); writeChar('\n'); uint8_t i = 0; for(i = 0; i < 199; i++) { read_Register_30(); feld_IR[i] = IR_wert[0]; writeIntegerLength(feld_IR[i],DEC,4); if(i % 12 == 0) writeChar('\n'); else writeString_P(" | "); mSleep(20+j); } } /**************************/ uint8_t key_1 = getMultiIOPressedButtonNumber(); key_1 = getMultiIOPressedButtonNumber(); if(key_1 != 0) break; /**************************/ } break; } } } return 0; } /***************************************************************************/
Man sollte vor dem Test die Werte der beiden Potis einstellen und die Werte festhalten. Ich habe zwei Blinkfrequenzen der Blinkschaltung getestet:
Frequenz R1 R2 2 / Sek. 1,1k 3,7k 1 / Sek. 2,7k 4,1k
Bessere Ergebnisse habe ich mit der Blinkfrequenz von 2 / Sek. erzielt. Die „Frequenz“ habe ich nur ganz grob mit einer Stoppuhr „eingestellt“
In der Datei „ir_bake_test_anleitung.c“ sind im wesentlichen zwei Wege enthalten mit denen man wahlweise oder als Kombination die Sende- und Empfangsfrequenz von RP6 und der bake anpassen kann.
Die grüne LED an der Senderplatine blinkt bei eingeschalteter bake in etwa 2x pro Sekunde, die rote LED auf der multi-IO Platine (bei einem Abstand der bake von ca. 30cm vom RP6) leuchtet dauernd wenn nichts empfangen wird, erlischt bei Empfang und die grüne LED geht an, dieser Wechsel wiederholt sich regelmäßig oder eben unregelmäßig, je nachdem wie die Sende- und Empfangsfrequenz zusammenpassen. Wenn jemand keine multi-IO platine hat, muss andere LEDs verwenden!
Mit case1: kann man durch verändern der Werte von R1 und R2 ein übereinstimmendes, gleichmäßiges Blinken der beiden grünen LEDs (Senderplatine der bake und die multi-IO) einzustellen versuchen. Oder den Wert des mSleep in dieser Schleife „if (IR_wert[0] == 0)“ versuchsweise verändern, neu compilieren, laden, starten. Das drehen an de Potis war einfacher :-).
Mit case2: kann man sich bei einigermaßen eingestelltem Blinken der bake und der LED am RP6 (es ist zunächst gleichgültig ob regelmäßig oder nicht, es müssen nur beide Seiten blinken) die empfangenen Daten (0000 oder 0004) am Terminal ausgeben lassen. In der Schleife wird der Wert für mSleep in steps von 10 von 0 bis 120 erhöht und mit den Werten des Register 30 mit ausgegeben. Terminal abspeichern, bearbeiten. Das sollte anschließend so aussehen:
Hier kann man sich dann ein Empfangsmuster, welches einem am regelmäßigsten erscheint aussuchen und die oberhalb dieses Musters stehende Zahl (Wert der mSleep-Pause) in die Schleife von case1 eintragen / aufteilen. Kompilieren, starten und schauen wie das gleichmäßige Blinken nun aussieht...
Case3: ist noch frei, wird hier nicht verwendet
Case4: ist nur eine Abwandlung von case2, die Erhöhung des mSleep Wertes geschieht hier mit 5.
Das ganze wiederholt man dann solange, bis man zufrieden ist. Und steigert dabei auch die Entfernung zwischen Sender und Empfänger. Die Ausrichtung des Sender und Empfänger für die Tests wird dann schwieriger, ich half mir bei geringeren Entfernungen mit einem Lineal, dann mit einem an beiden Enden festgeklebten Wollfaden. Hier noch ein paar Fotos zum Testaufbau:
Störungen durch Reflektionen der IR-Signale
Bei den Versuchen habe ich festgestellt, dass der RP6 manchmal in Richtung bake fuhr, öfters aber auch in andere Richtungen. Verursacht haben es Reflektionen der IR- Strahlen. Bei der bake habe ich durch Reflektoren an den IR-Dioden versucht die Probleme zu beseitigen:
es handelt sich um einen kleinen Reflektor für 5mm LED von CONRAD, zusammengeklebt mit einem 10mm langem Aluminiumrohr D12x1mm
Den Empfänger am RP6 habe ich mit einem ähnlichem, größerem Reflektor von CONRAD versehen, an die Verhältnisse an der Base-Platine angepasst, zusammengeklebt mit einem 25mm langem Aluminiumrohr D16x1mm
sodass es mit einem dickeren doppelseitigem Klebeband direkt vor den IR-Empfänger auf die BASE-Platine aufgeklebt werden konnte
In der Software (bake_suche) habe ich noch eines gemacht – es werden die empfangenen Signale pro bestimmten Zeitraum gezählt, bei 10 wird angenommen, dass es die bake ist.
Es ist schwer zu sagen welche von diesen Maßnahmen mehr Erfolg brachte - ich gehe davon aus, dass es die Kombination war – die Reflektionen spielen keine Rolle mehr...
Übrigens – bei Versuchen draußen habe ich festgestellt, dass offensichtlich durch die „gepulst“ sendenden IR- Dioden die IR- Signale vom Empfänger auch bei Sonnenschein empfangen wurden, offensichtlich werden diese durch die Sonnenstrahlung nicht gestört. Festgestellt habe ich es nicht auf die 5m Entfernung, es waren vielleicht 2 bis 3 Meter...
Software
Die bake soll bei einer bestimmten Akkuspannung automatisch aufgesucht werden. Das wird durch die Einbindung der Funktion Akkuzustand erreicht, diese wird in der Mainschleife einer beliebigen Software aufgerufen. Die Höhe der Spannung bei der der RP6 die Ladestation suchen soll ist ebenfalls in dieser Funktion einstellbar (if vbat...):
/*******************************accuzustand********************************/ void accuzustand(void) // accuspannung abfragen und signalisieren { LTC2990_measure(); if (vbat < 6.5) { buzzer(330); mSleep(200); buzzer(330); mSleep(200); //bake_suche(); } } /***************************************************************************/
in dieser Funktion erfolgt dann der Aufruf der Funktion „bake_suche“ (hier noch auskommentiert)
/*******************************bake_suche************************************/ void bake_suche(void) { setLEDs(0b0100); writeString_P("bake_suche_1 \n"); writeChar('\n'); initRP6Control(); initLCD(); startStopwatch3(); t=0; do { if(getStopwatch3() > 50) { read_Register_30(); if (IR_wert[0] !=0) { setMultiIOLED1(1); setMultiIOLED1(0); rotate(80, RIGHT, 5, false); read_Register_30(); if (IR_wert[0] == 0) stop(); } read_Register_30(); if (IR_wert[0] == 0) { x = getStopwatch3(); setMultiIOLED3(1); setMultiIOLED3(0); if (t<10) { t++; if (t == 10) { y = getStopwatch3(); z = y-x; writeInteger(x, DEC); writeChar('\n'); writeInteger(y, DEC); writeChar('\n'); writeInteger(z, DEC); writeChar('\n'); t=0; setStopwatch3(0); if (z< 600) { move(100, FWD, DIST_MM(100), false); setStopwatch3(0); t=0; mSleep(400); } } } } } } while(!bumper_left && !bumper_right); stop(); } /***************************************************************************/
die beiden libs:
/*****************************standard.c***********************************/ #include "RP6ControlLib.h" #include "RP6I2CmasterTWI.h" #include "RP6Control_MultiIOLib.h" #include "RP6Control_I2CMasterLib.h" #include "RP6Control_LFSBumperLib.h" #include "RP6ControlServoLib.h" #include "RP6Control_OrientationLib.h" #include "standard.h" /************************ Write a floating point number to the LCD or terminal. ******/ void writeDoubleLCD(double number, uint8_t width, uint8_t prec) {char buffer[width + 1]; dtostrf(number, width, prec, &buffer[0]); writeStringLCD(&buffer[0]); } void writeDouble(double number, uint8_t width, uint8_t prec) {char buffer[width + 1]; dtostrf(number, width, prec, &buffer[0]); writeString(&buffer[0]); } /**************************************accuspannungsanzeige*****************************/ void accuspannung(void) // accuspannung ausgeben { multiio_init(); LTC2990_measure(); setCursorPosLCD(0, 0); writeStringLCD(" accu: "); writeDoubleLCD(vbat, 4, 1); writeStringLCD( " V"); } /*********************************acculadungsanzeige**********************************/ void acculadung(void) { clearLCD(); setCursorPosLCD(0, 0); writeStringLCD(" ADC2: "); uint16_t adc2 = readADC(ADC_2); // Read ADC Channel 2 setCursorPosLCD(0, 9); writeIntegerLCD(adc2, DEC); if (adc2 > 650) { setCursorPosLCD(2, 0); writeStringLCD(" ladespannung ok "); setMultiIOLED1(1); } } /*********************************I2C Error handler***********************************/ void I2C_transmissionError(uint8_t errorState) { writeString_P("\nI2C ERROR --> TWI STATE IS: 0x"); writeInteger(errorState, HEX); writeChar('\n'); } /***************************variablen************************************************/ uint8_t RP6data[32]; uint8_t i, j, t; int16_t x, y, z; uint8_t temp; uint8_t IR_wert[1]; /***************************readAllRegister********************************************/ void readAllRegisters(void) { I2CTWI_transmitByte(I2C_RP6_BASE_ADR, 0); I2CTWI_readBytes(I2C_RP6_BASE_ADR,RP6data, 31); writeString_P("\nREADING ALL RP6 REGISTERS:"); uint8_t i = 0; for(i = 0; i < 31; i++) { if(i % 8 == 0) writeChar('\n'); else writeString_P(" | "); writeChar('#'); writeIntegerLength(i,DEC,2); writeChar(':'); writeIntegerLength(RP6data[i],DEC,3); } writeChar('\n'); } /**********************print_register_30*********************************************/ void print_Register_30(void) { writeString_P("\nPRINTING REGISTER 30:"); uint8_t i = 0; for(i = 0; i < 31; i++) { I2CTWI_transmitByte(I2C_RP6_BASE_ADR, 30); IR_wert[0] = I2CTWI_readByte(I2C_RP6_BASE_ADR); if(i % 8 == 0) writeChar('\n'); else writeString_P(" | "); writeChar('#'); writeIntegerLength(i,DEC,2); writeChar(':'); writeIntegerLength(IR_wert[0],DEC,3); } writeChar('\n'); } /********************************watchdog_request********************************/ void watchDogRequest(void) { static uint8_t heartbeat2 = false; if(heartbeat2) { clearPosLCD(1, 14, 1); heartbeat2 = false; } else { setCursorPosLCD(1, 14); writeStringLCD_P("#"); heartbeat2 = true; } } /********************** Heartbeat function************************************/ void task_LCDHeartbeat(void) { if(getStopwatch1() > 500) { static uint8_t heartbeat = false; if(heartbeat) { clearPosLCD(0, 15, 1); heartbeat = false; } else { setCursorPosLCD(0, 15); writeStringLCD_P("*"); heartbeat = true; } setStopwatch1(0); } }
/******************************standard.h************************************/ #ifndef STANDARD_H_ #define STANDARD_H_ void writeDoubleLCD(double number, uint8_t width, uint8_t prec); void writeDouble(double number, uint8_t width, uint8_t prec); void accuspannung(void); void acculadung(void); void readAllRegisters(void); void print_Register_30(void); void watchDogRequest(void); void task_LCDHeartbeat(void); #endif /*STANDARD_H_*/
/******************************navi_1.c**************************************/ #include "RP6ControlLib.h" #include "RP6I2CmasterTWI.h" #include "RP6Control_MultiIOLib.h" #include "RP6Control_I2CMasterLib.h" #include "RP6Control_LFSBumperLib.h" #include "RP6ControlServoLib.h" #include "RP6Control_OrientationLib.h" #include "standard.h" #include "navi_1.h" /***************************variablen************************************************/ uint8_t RP6data[32]; uint8_t i, j, t; int16_t x, y, z; uint8_t temp; uint8_t IR_wert[1]; /*****************************read_register_30**************************************/ void read_Register_30(void) { I2CTWI_transmitByte(I2C_RP6_BASE_ADR, 30); IR_wert[0] = I2CTWI_readByte(I2C_RP6_BASE_ADR); } /********************************bake_suche**************************************/ void bake_suche(void) { setLEDs(0b0100); writeString_P("bake_suche_1 \n"); writeChar('\n'); initRP6Control(); initLCD(); startStopwatch3(); t=0; do { if(getStopwatch3() > 50) { read_Register_30(); if (IR_wert[0] !=0) { setMultiIOLED1(1); setMultiIOLED1(0); rotate(80, RIGHT, 5, false); read_Register_30(); if (IR_wert[0] == 0) stop(); } read_Register_30(); if (IR_wert[0] == 0) { x = getStopwatch3(); setMultiIOLED3(1); setMultiIOLED3(0); if (t<10) { t++; if (t == 10) { y = getStopwatch3(); z = y-x; writeInteger(x, DEC); writeChar('\n'); writeInteger(y, DEC); writeChar('\n'); writeInteger(z, DEC); writeChar('\n'); t=0; setStopwatch3(0); if (z< 600) { move(100, FWD, DIST_MM(100), false); setStopwatch3(0); t=0; mSleep(400); } } } } } } while(!bumper_left && !bumper_right); stop(); } /*************************************accuzustand****************************************/ void accuzustand(void) // accuspannung abfragen und signalisieren { LTC2990_measure(); if (vbat < 6.5) { buzzer(330); mSleep(200); buzzer(330); mSleep(200); //bake_suche(); } } /************************calculateDetailDir*************************************/ void calculateDetailDir(char *dir, uint16_t heading) { dir[1] = ' '; dir[2] = '\0'; dir[3] = '\0'; if ((heading <= 11) || (heading >=349)) dir[0] = 'N'; if ((heading >= 12) && (heading <= 33)) {dir[0] = 'N'; dir[1] = 'N'; dir[2] = 'E';} if ((heading >= 34) && (heading <= 56)) {dir[0] = 'N'; dir[1] = 'E';} if ((heading >= 57) && (heading <= 78)) {dir[0] = 'E'; dir[1] = 'N'; dir[2] = 'E';} if ((heading >= 79) && (heading <= 101)) dir[0] = 'E'; if ((heading >= 102) && (heading <= 123)) {dir[0] = 'E'; dir[1] = 'S'; dir[2] = 'E';} if ((heading >= 124) && (heading <= 146)) {dir[0] = 'S'; dir[1] = 'E';} if ((heading >= 147) && (heading <= 168)) {dir[0] = 'S'; dir[1] = 'S'; dir[2] = 'E';} if ((heading >= 169) && (heading <= 191)) dir[0] = 'S'; if ((heading >= 192) && (heading <= 213)) {dir[0] = 'S'; dir[1] = 'S'; dir[2] = 'W';} if ((heading >= 214) && (heading <= 236)) {dir[0] = 'S'; dir[1] = 'W';} if ((heading >= 237) && (heading <= 258)) {dir[0] = 'W'; dir[1] = 'S'; dir[2] = 'W';} if ((heading >= 259) && (heading <= 281)) dir[0] = 'W'; if ((heading >= 282) && (heading <= 303)) {dir[0] = 'W'; dir[1] = 'N'; dir[2] = 'N';} if ((heading >= 304) && (heading <= 326)) {dir[0] = 'N'; dir[1] = 'W';} if ((heading >= 327) && (heading <= 348)) {dir[0] = 'N'; dir[1] = 'N'; dir[2] = 'W';} }
/*******************************navi_1.h*************************************/ #ifndef NAVI_1_H_ #define NAVI_1_H_ void read_Register_30(void); void bake_suche(void); void accuzustand(void); void calculateDetailDir(char *dir, uint16_t heading); #endif /*NAVI_1_H_*/
videos
2014_05_04_case_1_signaltest Testaufbau für case1, Frequenz 2 / Sek. Entfernung 85cm
2014_05_04_case_1_signaltest 5m Testaufbau für case1, Frequenz 1 / Sek. Entfernung 5m. Unregelmäßiger Empfang (Wechsel der multi-IO LEDs von rot auf grün)
2014_05_14_case_1_signaltest_6m Testaufbau für case1, Frequenz 2 / Sek. Entfernung 6m. Der Empfang ist besser
2014_05_04_case_2_signaltest Testaufbau für case2, Entfernung 85cm
bake_suche Suche der IR-bake
Wie geht’s weiter?
Die Funktion „suche_bake“ ist jetzt so ausgelegt, dass der RP6, nachdem er die bake gefunden hat per Bumper stehen bleibt. Das werde / würde ich so ändern, dass er
- zwar immer wieder überprüft ob er immer noch in Richtung bake fährt, aber auf die Funktion „fahre bis schwarze Linie“ umschaltet
- beim erreichen der Linie in der einfachen Version per Definition nach rechts (oder halt links) um 90° dreht und auf „followline“ umschaltet und folgt der Linie, bis er eine schwarze Querlinie findet. Sprechen vorher die Bumper an, war rechts die falsche Richtung, er ist gegen die Wand gefahren. Er setzt also einen Stück zurück, wendet um 180° und folgt der Linie solange zurück bis er die schwarze Querlinie gefunden hat
- in der komfortableren Version weiß der RP6 von seinem Gyro ob er vom Nordost oder Südsüdwest kommt und kann sich beim Finden der Linie entsprechend sofort für Links- oder Rechtsdrehung entscheiden, da er das ja anhand der gespeicherten Richtung in der er die bake vorher „gesehen hat“ erkennt
- in beiden Fällen hat er nun die senkrecht zur Wand führende Linie gefunden und weiß ob die Wand rechts oder links liegt, dreht auf die Linie und fährt den bekannten Abstand zu Ladestation
- lädt....
So, das war es, viel Spaß und Erfolg beim Nachbauen...
Autor
--inka 09:50, 12. Mai 2014 (CET)