-         

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 13

Thema: NiboBiene und Sharp IR

  1. #1
    Erfahrener Benutzer Roboter Genie Avatar von Rabenauge
    Registriert seit
    13.10.2007
    Ort
    Osterzgebirge
    Alter
    49
    Beiträge
    1.242

    NiboBiene und Sharp IR

    Anzeige

    Hallöle.
    Wieder mal so ein Thread von mir...Bienenerweiterung für Dummys.
    Mein Sharp ist da.
    Im Bienen-Erweiterungen-Thread habe ich gelesen, wie "einfach" es ist, diesen Sensor (es ist der Sharp GP2Y0A21YK0F) an den XBee-Port 3 mitsamt nem Servo anzuschliessen.
    Servo habe ich schon ein paar Tage dran, das funktioniert bestens, im Moment kann ich es mit den Fühlern frei nach rechts und links schwenken.

    Nun soll der IR-Sensor mitarbeiten, angeschlossen (am gleichen Port, halt die vierte Leitung als Signalleitung) ist er, auch die IR-LED funktioniert prächtig.
    Jetzt die Preisfrage: UND NU?

    Ich habe den Artikel im RN-Wissen (über den ADC) zwar um Hilfe bemüht, aber vergebens, 2/3 des dort beschriebenen Codes kapiere ich wieder nich.


    Diese vielen ASDC, ASRaels und andere, meist mit A anfangenden Wörter sind einfach böhmische Dörfer für mich, trotz einiger Kommentare im Text.
    Alleine diese Zeile:

    // Den ADC aktivieren und Teilungsfaktor auf 64 stellen
    ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);

    sagt mir praktisch gar nix.
    Immerhin glaube ich, herausgefunden zu haben, dass ich den Teilungsfaktor so lassen kann, obwohl meine Biene ja doppelt so schnell tickt.
    Aber: wie kriege ich es beispielsweise hin, dass am Port PC3 gemessen wird?

    Das müsste, meinem lausigen Verständnis nach, ja hier drinnen dann passieren:

    // Kanal des Multiplexers waehlen
    // Interne Referenzspannung verwenden (also 2,56 V)
    ADMUX = channel | (1<<REFS1) | (1<<REFS0);
    ODER?

  2. #2
    Benutzer Stammmitglied
    Registriert seit
    04.05.2010
    Beiträge
    88
    Alleine diese Zeile:

    // Den ADC aktivieren und Teilungsfaktor auf 64 stellen
    ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);

    sagt mir praktisch gar nix.
    das ist schlecht, aber genau dafür gibt es datenblätter.

    ADCSRA = analog digital converter status register a.
    ADEN = analog digital enable
    usw.

    könnte man fast selbst drauf kommen.

    wie kriege ich es beispielsweise hin, dass am Port PC3 gemessen wird?
    ...
    // Kanal des Multiplexers waehlen
    // Interne Referenzspannung verwenden (also 2,56 V)
    ADMUX = channel | (1<<REFS1) | (1<<REFS0);
    ODER?
    dazu muss man den passenden adc kanal wählen.
    welcher das ist und was man dazu einstellen muss, kann man im Analog-to-Digital Converter abschitt im datenblatt nachlesen.

  3. #3
    Erfahrener Benutzer Roboter Genie Avatar von Rabenauge
    Registriert seit
    13.10.2007
    Ort
    Osterzgebirge
    Alter
    49
    Beiträge
    1.242
    das ist schlecht, aber genau dafür gibt es datenblätter.

    Danke, das hilft mir _nicht_ weiter, ich werd schlichtweg aus dem Kauderwelsch im Datenblatt _nicht_ schlau.
    Ein paar Dinge begreife ich zwar, aber (ich sitze nun mehr oder weniger zwei Stunden vor dem Ding) ich habe noch immer _keine_ Ahnung, wie zum Teufel ich einfach nur den Wert von PC3 einlesen soll.
    Mehr will ich doch erst mal gar nicht, vermutlich istd as das enzige, woran ich überhaupt hänge (wenn nicht, sag ichs dann schon).

    Aus dem ADC-Tutorial von RN-Wissen:

    Je nach Einsatzart muss das Beispielprogramm entsprechend abgeändert werden (also diese Zeile mit ADMUX |= (1<<REFS1) |

    Soso. Schön. Wenn mir einer erklärt, WAS und WIE ichs ändern muss, tu ich das sofort. [-(

    Ich lese überall, dass man einen bestimmten Kanal wählen muss (denk ich mir, das leuchtet irgendwie ein) aber WELCHEN und WIE erkläre ich das dem Prozessor?
    Wie finde ich heraus, welcher Kanal mein PC3 ist?

  4. #4
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.552
    Hi Rabenauge,

    ich gehe jetzt mal davon aus, dass Du einen mega16 im Bee drin hast. Leider habe ich für den grad nur ein altes Datenblatt hier von 2007: 2466P–AVR–08/07, das dürfte aber in anderen ähnlich drinstehen.

    Zitat Zitat von Rabenauge
    ... Beispielprogramm entsprechend abgeändert werden ... ADMUX |= (1<<REFS1)
    Wie finde ich heraus, welcher Kanal mein PC3 ist?
    Suche mal im Datenblatt nach "Input Channel and Gain Selections" - da müsste es eine Tabelle geben. Extra um Dich (und mich und andere) zu verwirren, hat Atmel nämlich die Ports mit den verschiedenen Namen versehen *ggg*). Der PC3 des m16 ist als ADC-Port GARNICHT zu benutzen . In den docs steht, meist auf Seite 2, eine Zeichnung mit den verschiedenen Portnamen. Bei meinem Doc steht da der ADC3 am PORT A - also als PA3 - nun würde ich gern wissen, wie Du auf PC3 kommst. Wie gesagt, der lässt sich NICHT als ADC-Eingang benutzen.
    Ciao sagt der JoeamBerg

  5. #5
    Erfahrener Benutzer Roboter Genie Avatar von Rabenauge
    Registriert seit
    13.10.2007
    Ort
    Osterzgebirge
    Alter
    49
    Beiträge
    1.242
    Aus dem Schaltplan der Biene: laut _dem_ liegen am Port X3 (das ist der rechte, vorne, neben der Nase) an:

    AN3
    PC3
    VCC
    GND

    Die letzten beiden sind eh klar, an AN3 habe ich das Servo liegen.
    Funktioniert auch wunderbar.
    Im Thread: Nibobee-Erweiterungen las ich, dass an den Port _ausserdem_ ein Sharp (eben zusätzlich zum Servo) angeschlossen werden kann, haben wohl einige auch erfolgreich gemacht.
    Daher denke ich mir, dass das geht. Ich vertrau da den Profis einfach.
    Sollte es wirklich nicht gehen, müsste ich den Sharp halt wo anders anschliessen, die Frage wäre nur, wo...

    Tante Edit ergänzt:
    Oook, die Blödheit (oder mein Kabelgewusele?) hat mich wieder voll erwischt: Die Signalleitung des Servos hängt natürlich an PC3!

    Ab und an hilft es doch, sich seine Programme mal wieder im Ganzen anzusehen....
    Damit ist nun (nein, eigentlich die ganze Zeit schon) AN3 der analoge Eingang, und es sollte funktionieren.

    Der Einfachheit halber würde ich gerne den gleichen Code, den ich für die Spannungsmessung benutze, wiederverwerten, von dem weiss ich, er funktioniert. Ok, ein paar Variablen müssen geändert werden, aber das ist nix.
    Genügt es dafür, die Zeile:

    while ((ADMUX & 0x07) != 0x04);
    umzustellen und wie?
    _So_ liefert mir der Code brav den ADC-Wert des Spannungsteilers vom Akku..

  6. #6
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    7.552
    Ahhhh - JETZT macht es Sinn. Gestern abends hatte ich nur gelesen, dass Du den Servo an AN3 hättest - und hatte spätabendsfastmitternacht gegrübelt, wie über den PC3 ein analoges Signal ausgewertet wird (schon klar, man könnte das Sharp-Ergebnis auch einfach dann auswerten, wenn es einen Pegel - low oder high - über-/unterschreitet). Und dazu bin ich dann "alles" durchgegangen. Deinen Kommentar von Tante Edit hatte ich erst heute morgen gelesen. Klar, AN3 ist der Controllereingang PA3/ADC3 (denn - warum sollte man diesen Eingang so benennen, wie es Atmel macht - etwas Abwechslung törnt ja die Gehirntätigkeit an) und damit kannst Du analoge Signale messen. Wenn Du das sowieso schon machst mit Deinem Spannungsteiler am AN3 dann muss der gleiche Code ja auch zur Spannungsmessung für den Sharp funktionieren.

    Ich hatte bei meiner Anwendung mit dem Sharp, da aber mit dem GP2D120, mir nach Hardware- und Softwareinstallation erstmal eine Eichkurve für den Sharp erstellt. Danach hatte ich aus dieser Messkurve >>in MEINEM System gemessen!!<< den Umrechnungsfaktor abgeleitet und eine entsprechende Softwareanpassung mit Angabe der Entfernung in üblichen Einheiten (ich rechne NICHT in russischen Werst oder althannoveraner Ellen!) geschrieben. Aufpassen: der Sharp, zumindest mein GP2D120, ist bei seinen Ergebnissen ziemlich abhängig von der Eingangsspannung - und der GP2D120 spuckt Störungen zurück. Die Eichkurve sieht so aus, der Thread dazu ist im Bild verlinkt.

    . . . . . . . .

    Viel Erfolg.
    Ciao sagt der JoeamBerg

  7. #7
    Erfahrener Benutzer Roboter Genie Avatar von Rabenauge
    Registriert seit
    13.10.2007
    Ort
    Osterzgebirge
    Alter
    49
    Beiträge
    1.242
    Sodele. Der Sharp läuft, und zeigt auch _brauchbare_ Werte an, aber:
    Es gibt ein neues Problem.
    Offenbar verträgt sich _diese_ ADC-Routine nicht mit der, die mir die Akkuspannung ermittelt.

    Konkret sieht es so aus, dass beim "hochfahren" so ziemlich als erstes mal die Akkuspannung ermittelt wird, wenn der einen bestimmten Wert unterschreitet, machts keinen Sinn, weiterzumachen.
    So weit klappt das auch, dann wird das Schwenkservo mal kurz getestet und dann der Sharp abgefragt.
    Keinerlei Probleme, bis dahin.
    Nun will ich aber, Timergesteuert, von Zeit zu Zeit den Akku immer wieder mal prüfen, und _dann_ hängt _diese_ Routine sich auf.

    Code:
    //----------------------------------------- Sharp-IR-Sensor ---------------------------------------
    
    int Sharp(void) 
    	{ 
    	 
      ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);// Frequenzvorteiler: setzen auf 128 (16 MHz / 128kHz = 125 kHz) und ADC aktivieren 
    	ADMUX = 0x03;											// Kanal waehlen (ADC3)
    	ADMUX |= (1<<REFS1); 									// interne Referenzspannung nutzen 
    	ADCSRA |= (1<<ADSC);              						// eine ADC-Wandlung 
    	while ( ADCSRA & (1<<ADSC) );     						// auf Abschluss der Konvertierung warten 
    	sharpResult = ADCW;										// Wert abholen
    	lcd_setCursor(0,1);										// Ausgabe ADC-Wert
    	printf("Sharp: %4d",sharpResult);						
    	
      return 0; 
    }
    //----------------------------------------- Spannungsüberwachung ----------------------------------
    int Batterie(void) 
    { 
      led_set(LED_L_RD,1);										// blitzt bei jeder Messung kurz auf
      unsigned char temp1,temp2; 
      while ((ADMUX & 0x07) != 0x04); 
      cli(); 
      while (!(ADCSRA & (1 << ADIF)));   						// wait for conversion complete 
      ADCSRA |= (1 << ADIF);              						// clear ADCIF 
      temp1 = ADCSRA; 											// Registerinhalte retten
      temp2 = ADMUX; 
    
      ADMUX = (1 << REFS0) | (1 << REFS1) | ANALOG_VOLT;  	 	//interne Referenzspannung m. externem Kondensator 
    
      															// ADCSRA löschen und neu setzen 
      ADCSRA = 0; 
      ADCSRA |= ((1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0));   // ADC clock = Clock/128 
      ADCSRA |= (1 << ADEN);         							// Enable ADC (das aktiviert die 2.56V Referenz) 
          
      															// Warten bis Kondensator an ARef = 2.56V hat 
      															// Messung an ARef ergab 1,2msec 
      delay(6);  												// = ca. 5*Tau 
          
      															// 1. ADC Wandlung starten und Ergebnis ignorieren 
      ADCSRA |= (1 << ADSC);         							// Start conversion 
      while (!(ADCSRA & (1 << ADIF)));  						// wait for conversion complete 
      ADCSRA |= (1 << ADIF);              						// clear ADCIF 
    
      															// 2. ADC Wandlung starten und Ergebnis übernehmen 
      ADCSRA |= (1 << ADSC);         							// Start conversion 
      while (!(ADCSRA & (1 << ADIF)));  						// wait for conversion complete 
      ADCSRA |= (1 << ADIF);              						// clear ADCIF 
    
      akkuResult = ADCL + (ADCH << 8); 
          
      															// Registerinhalte wiederherstellen 
      ADMUX = temp2; 
      ADCSRA = temp1 & ~(1 << ADSC); 
    
      															// Warten bis Kondensator an ARef = AVcc hat 
      															// Messung ergab sehr steile Flanke 
      delay(2);  												// nicht notwendig, nur zur Sicherheit 
    
      ADCSRA |= (1 << ADSC);         							// Start conversion 
    
      sei();
    .....hier kommt noch ein bisschen Rechnerei und die Displayausgabe
    Lasse ich den periodischen Aufruf von Batterie() weg, klappt alles hervorragend.
    Die Routine Sharp() wird im Hauptprogramm in einer Endlosschleife praktisch ununterbrochen aufgerufen, nebenbei zählt ein Timer hoch und löst, bei einem bestimmten Wert (so alle 15s) die Routine Batterie() auf.
    Die LED (sie wird später, während der Umrechnung des ADC-Wertes in brauchbares wieder ausgeschalten) bleibt an, daher _muss_ der Punkt, an dem sich das Programm aufhängt, irgendwo in Batterie() liegen.
    Alleine (wenn ich Sharp() _nicht_ aufrufe) funktioniert Batterie() einwandfrei.

    Weiss jemand Rat?

  8. #8
    Neuer Benutzer Öfters hier
    Registriert seit
    05.03.2009
    Beiträge
    20
    Hallo Rabenauge,

    um klarzustellen was da passiert, muss man etwas in den Eingeweiden der Nibobee wühlen.
    Wird mit analog_init() der ADWandler gestartet, so arbeitet er "interrupt getrieben" vor sich hin. D.h. sobald die Wandlung abgeschlossen ist, löst er einen Interrupt aus. In der ADC-Interruptroutine (siehe unten den Teil des listing von analog.c) wird das Resultat abgeholt (analog_storeResult(analog_pos)), ein neuer Kanal eingestellt (++analog_pos...) und die nächste Wandlung gestartet (analog_setupNext(analog_pos)).

    ISR(ADC_vect) {
    analog_storeResult(analog_pos);
    if (++analog_pos>10) {
    analog_pos=0;
    }
    analog_setupNext(analog_pos);
    }

    Das macht er für 11 analoge Kanäle (Warum 11 kommt später).

    Mit deiner neu Konfiguration von ADCSRA in deiner Sharp(void) bringst du diesen Automatismus zum Stehen. Dadurch funktioniert nun die Abfrage der Liniensensoren nicht mehr und "meine" Batteriespannungsmessung hängt sich auf, denn sie setzt auf die laufenden Interrupts.
    Eigentlich brauchst du deine Sharp(void) nicht, denn das Resultat von ADC3 findest du auch im Array analog_samples[..] (siehe analog.c) als 3. Eintrag, denn ANALOG_EXT3 = 3 (siehe analog.h).

    Also mit

    sharpResult = analog_samples[3];

    erhälst du den Wert von ADC3 ganz automatisch.
    Das funktioniert für alle AD-Werte bis auf die Batteriespannung, für die ich dieses "workaround" geschrieben habe (detaillierte Erklärung siehe nibobee: Akkuspannung mit ADC messen).

    Nun noch ein Wort zu den 11 analogen Kanälen. Eigentlich hat der ATMega16 nur 8 Kanäle. Die Liniensensoren (3 analoge Werte) werden jedoch 2 mal gelesen. Nämlich einmal mit eingeschalteten IR-LED und einmal mit ausgeschalteten IR-LED.
    Die Werte bei abgeschalteten IR-LED sind hier zu finden
    case 4: analog_samples[ANALOG_L0]=value; break;
    case 5: analog_samples[ANALOG_C0]=value; break;
    case 6: analog_samples[ANALOG_R0]=value; clear_output_bit(IO_LINE_EN); break;

    Die Werte bei eingeschalteten IR-LED sind hier zu finden
    case 8: analog_samples[ANALOG_L1]=value; break;
    case 9: analog_samples[ANALOG_C1]=value; break;
    case 10: analog_samples[ANALOG_R1]=value; set_output_bit(IO_LINE_EN); break;

    Es gibt nun 2 Möglichkeiten.
    1. Du benutzt sharpResult = analog_samples[3]; und lässt das ADCSRA in der Sharp(void) in Ruhe.
    2. Du schreibst ebenfalls ein "workaround" das ungefähr so aussieht (nicht getestet, nur ein Beipiel)

    int Sharp(void)
    {
    unsigned char temp1,temp2;
    uint16_t sharpResult;

    while ((ADMUX & 0x07) != 0x03); //warten bis ADC3 dran ist

    cli();

    while (!(ADCSRA & (1 << ADIF))); // wait for conversion complete
    ADCSRA |= (1 << ADIF); // clear ADCIF

    //Registerinhalte retten
    temp1 = ADCSRA;
    temp2 = ADMUX;

    //hier müssen die Teile deiner Sharp(void) rein

    sharpResult = ADCL + (ADCH << 0x0;

    //Registerinhalte wiederherstellen
    ADMUX = temp2;
    ADCSRA = temp1 & ~(1 << ADSC);


    ADCSRA |= (1 << ADSC); // Start conversion

    sei();

    return sharpResult;
    }


    Viel Erfolg
    Skroete

  9. #9
    Erfahrener Benutzer Roboter Genie Avatar von Rabenauge
    Registriert seit
    13.10.2007
    Ort
    Osterzgebirge
    Alter
    49
    Beiträge
    1.242
    Also mit

    sharpResult = analog_samples[3];

    erhälst du den Wert von ADC3 ganz automatisch.
    Nee, oder? Ich sitze vier Tage an dem Problem, und da kommst du daher, grienst dir einen und sagst dass es mit zwei Zeilen abgeht?
    Erstmal ein grosses Danke, das löst gleich ein halbes dutzend Probleme, die später noch gekommen wären.

    Ja, ich habs probiert, und es funktioniert auch, aber...nicht ganz richtig.
    Von weitem klappt das gut, ab ca. nem Meter misst der Sharp brauchbar (ich glaub, ab 80cm _sollte_ er erst), aber im Nahbereich....mit meiner Methode war ich bei ca. 10cm Entfernung dann bei 1023, jetzt bin ich, wenn das Hindernis 10cm weg ist, gerade mal bei ungefähr 600, und wenn ich näher als 5cm rangehe, sinkt der Wert wieder.
    Oook, man _könnte_ damit durchaus leben, das messen an sich funktioniert ja, aber der volle Wertebereich hätte auch was- dann nämlich kann man im Nahbereich superfein messen, wie ich festgestellt habe.
    Geht das noch besser?
    Oder hab ich wiedermal Mist gebaut?

    Da der Compiler mit mir schimpfte, als ich _nur_ :

    sharpResult = analog_samples[3];

    schrieb, habe ich im Kopf des Programmes noch hinzugefügt:

    int analog_samples[10];

    Schon gibts keine Fehler-oder Warnmeldungen mehr.
    Hab ich da auch was vertrottelt oder...

    [/i]

  10. #10
    Neuer Benutzer Öfters hier
    Registriert seit
    05.03.2009
    Beiträge
    20
    Hallo Rabenauge,

    du hast Recht. So
    sharpResult = analog_samples[3];
    funktioniert es nicht. Ich habe leider versäumt es zu testen.

    Richtig müsste es heissen
    sharpResult=analog_getValue(ANALOG_EXT3);

    Im Kopf deines Programms muss natürlich
    #include <nibobee/analog.h>
    rein und zu Beginn des Hauptprogramm die Zeile
    analog_init();

    Damit gibt es keine Fehlermeldungen mehr und deine Zeile
    int analog_samples[10];
    kann raus.
    Ob damit das Problem mit der Auflösung des Abstands ebenso erledigt ist,
    musst du ausprobieren.
    Es gibt nämlich ein Problem bei dieser Methode. Wie ich schon schrieb wurschtelt der AD-Wandler fröhlich in seinem Interrupt vor sich hin. Wenn deine Abstandsroutine nun eine gewisse Synchronität erwartet (z.B. die LED wird eingeschaltet und dann soll gemessen werden), dann musst du dem AD-Wandler genügend Zeit geben, denn er könnte ja gerade dabei sein, alle anderen Kanäle abzuklappern.
    Wenn es nicht funktioniert, dann hilft nur, die AD-Wandlung von ADC3 zu Fuss zu machen und deine Routine so einzubinden, wie ich es in der letzten Antwort beschrieben habe.

    Eine weitere Möglichkeit wäre dann auch ganz auf die Nibobee AD-Wandlung zu verzichten.
    Denn dann hast du die Batteriemessung und die ADC3-Messung schon zu Fuss gemacht und die Nibobee AD-Wandlung macht eigentlich nur noch die Wandlung der Liniensensoren. Die kann man dann auch noch zu Fuss machen.
    Also kein
    analog_init();
    mehr und alles zu Fuss.


    Viel Erfolg
    Skroete

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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