PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Hilfe!!! Asuro SnakeVision funktioniert nicht, wenn PollSwitch() ins Spiel kommt!



firescorpion
14.12.2012, 23:15
Hallo liebe Community,

ich bin neu hier und habe ein extrem dringendes Problem mit der SnakeVision von Asuro. Leider sind meine Programmier- geschweige denn Microcontrollerkenntnisse sehr beschränkt :(

Folgendes Problem: Wenn die ganz normalen Taster von Asuro in der Schleife des SnakeVision Programmes abgefragt werden, um Asuro dazu zu bringen, dass er nach Kollision mit Wänden etwas anderes tut, dann funktioniert plötzlich der linke Wärmesensor nicht mehr richtig.

Das Programm für die Verfolgung der Wärmequellen beruht auf dem Algorithmus aus dem Buch "Mehr Spaß mit Asuro Band2". Funktioniert soweit auch ziemlich gut. Sogar das Löschen von Teelichtern mit einem eingebauten Ventilator hat schon geklappt. Nur, wenn PollSwitch() ins Spiel kommt, geht halt der linke Sensor kaum noch :( Er erkennt bei Raumtemperatur meinen Finder dann nur noch auf wenige Millimeter Entfernung, während der rechte Sensor den Finger noch bei über 10cm Abstand erkennt (was der linke ja normalerweise auch tut)...

Habe dazu auch nirgends was passendes gefunden im Internet, deshalb seid ihr meine letzte Rettung. Kann es sein, dass da irgendwas gleichzeitig an einem Prozessorpin hängt oder dergleichen? Oder übersehe ich etwas bei der Programmierung? Habe leider echt nich das nötige KnowHow, um das selbst herauszufinden.

Hier mal der Code (ist jetzt erstmal einfach nur der Standard SnakeVision Code aus dem Buch, bloß mit Abbruch durch PollSwitch():


#include "asuro.h"
//Schwellen für die intensitätsabhängige Geschwindigkeit
#define THRESH1 20
#define THRESH2 80
#define THRESH3 200

//Funktion, um Tasterwert abzufragen
char switchwert(void){
char taste=0;
unsigned char t1,t2,t3;
t1=PollSwitch();
t2=PollSwitch();
t3=PollSwitch();

if((t1 == t2)&& (t2==t3))
{taste=t1;}
return taste;
}

//testet beim Fahren auf die Abbruchbedingungen
int abbruchtest(void){
int abbruch=0;

char tasten=switchwert();

if(tasten>0){
abbruch=1;
StatusLED(YELLOW);
}

return abbruch;
}

void ThermalData(unsigned int *data){

/* ThermalData() funktioniert genausi, wie LineData(), nur, dass dabei
die interne Spannungsreferenz als AD-Wandlerdifferenz verwendet wird.*/

//Prozessorinterne Referenz verwenden
//Multiplexer auf linken Sensor schalten
ADMUX = (1 << REFS0) | (1 << REFS1) | IR_LEFT;

//Wandlung starten
ADCSRA |= (1 << ADSC);

//Warten bis Wandlung beendet ist
while (!(ADCSRA & (1 << ADIF)));

//ADCIF zurücksetzen
ADCSRA |= (1 << ADIF);

//ADC-Wert auslesen
data[0] = ADCL + (ADCH << 8);

// Multiplexer auf rechten Sensor schalten
ADMUX = (1 << REFS0) | (1 << REFS1) | IR_RIGHT;

// Wandlung starten
ADCSRA |= (1 << ADSC);

// Warten, bis Wandlung beendet
while (!(ADCSRA & (1 << ADIF)));

// ADCIF zurücksetzen
ADCSRA |= (1 << ADIF);

// ADC-Wert auslesen
data[1] = ADCL + (ADCH << 8);

}

int main(void)
{
// Speicher für die Messwerte bereitstellen
unsigned int tdata[2],offset[2];
unsigned int speed;
signed int diff,sum;
Init();

//Port D, Pin 6 (die ehemalige FrontLED), auf Eingang schalten und den Pullup aktivieren.
DDRD&=~(1<<6);
PORTD|=(1<<6);

// Motoren immer auf vorwärts
MotorDir(FWD,FWD);

//Offset mit 0 initialisieren
offset[0]=0;
offset[1]=0;

int abbr=0;

while(abbr==0)
{
//Messwerte einlesen
ThermalData(tdata);

//Wenn Knopf gedrückt, den aktuellen Wert als Offset speichern
if ((PIND&(1<<6))==0){
offset[0]=tdata[0];
offset[1]=tdata[1];
}

//Offset abziehen, aber nur, wenn der Messwert groß genug ist, sonst gibt's nen Überlauf
if(tdata[0]>offset[0]) tdata[0]-=offset[0];
else tdata[0]=0;

if(tdata[1]>offset[1]) tdata[1]-=offset[1];
else tdata[1]=0;

/* Die Summe der Werte wird für die
Berechnung derGeschwindigkeit genutzt*/
sum=tdata[0]+tdata[1];

// Signal stark genug?
if (sum>THRESH1) {
StatusLED(GREEN);
speed=140;

// Ziemlich stark?
if (sum>THRESH2) {
StatusLED(YELLOW);
speed=200;
}
// Sehr stark?
if (sum>THRESH3) {
StatusLED(RED);
speed=255;
}
// Richtung bestimmen
diff=((signed)tdata[0]-(signed)tdata[1])*32/sum;
if (diff>4) {
// Links deutlich wärmer? Nach links fahren!

MotorSpeed(0,speed);
}
else if (diff<-4) {
// Rechts deutlich wärmer? Nach rechts fahren!

MotorSpeed(speed, 0);
}
else {
// Sonst geradeaus!

MotorSpeed(speed, speed);
}
}
else {
// Keine Wärmequelle in Sicht? Stehen bleiben!
StatusLED(OFF);

MotorSpeed(0,0);

}
abbr=abbruchtest();
}
MotorSpeed(0,0);
return 0;
}


Ich hoffe, dass mir jemand helfen kann, bin schon total verzweifelt :(

Danke schonmal an alle!
VG

radbruch
14.12.2012, 23:42
Hallo

Da kann ich ja mal nur raten:


//Messwerte einlesen
ThermalData(tdata);
ThermalData(tdata);
Messwerte zweimal einlesen. Hintergrund: Beim Einlesen der Snake-Werte wird die interne Referenz verwendet, PollSwitch() verwendet aber die externe Referenz. Möglicherweise geschied das Umschalten auf die interne Referenz nicht schnell genug.


abbr=abbruchtest();
}
MotorSpeed(0,0);
return 0;
}Das sollte man nicht tun, besser ist:

abbr=abbruchtest();
}
MotorSpeed(0,0);
while(1); // Programm sollte nie beendet werden!
return 0;
}

Gruß

mic

firescorpion
15.12.2012, 13:45
Hallo radbruch,

vielen Dank für deine superschnelle Antwort :)

Hat prima funktioniert. Witzigerweise hat es in dem geposteten Code mit zweimaligem Aufruf dazu geführt, dass dann der rechte Sensor plötzlich das Problem hatte. Bei 300maligem Aufruf hat es dann sehr gut funktioniert.

Im kompletten Programm hat es dann allerdings mit zweimaligem Aufruf schon perfekt funktioniert :) Könnte das daran liegen, dass er da insgesamt mehr rechnen muss und somit mehr Zeit hat, um wieder auf interne Referenz zu schalten? Könnte man ihm das eigentlich auch aktiv sagen, dass er umschalten soll?

Wie auch immer, auf jeden Fall funktioniert das nun soweit schonmal und es kann weitergehen :D

Vielen lieben Dank für die schnelle Hilfe!

Viele Grüße

radbruch
15.12.2012, 20:34
Hallo

Schön, dass es funktioniert. Der Grundgedanke war, dass nach dem ersten Umschalten vor der ADC0-Lesung die Referenz noch nicht komplett umgeschaltet ist, bei der ADC1-Lesung dies dann aber abgeschlossen ist.

Ja, man könnte die Referenz auch selbst aktiv umschalten. Die Referenz wird mit REFS0 und REFS1 im ADMUX-Register festgelegt. Nur REFS0 gesetzt bedeutet externe Referenz, beide gesetzt bedeutet interene Referenz. Spannenderweise wird in PollSwitch() nach dem Setzen der Referenz kurz gewartet und erst dann die Wandlung gestartet:

/* function to read out switches */
unsigned char PollSwitch (void)
{
... ADMUX = (1 << REFS0) | SWITCH; // AVCC reference with external capacitor
Sleep(10);

ADCSRA |= (1 << ADSC); // Start conversion
...
}(Auschnitt aus asuro.c v3.2)

Möglicherweise würde eine entsprechende Wartezeit in ThermalData() das Problem der Referenzumschaltung lösen.

Warum werden bei den Funktionen unterschiedliche Referenzen verwendet? Bei PollSwitch() wird ein Spannungsteiler verwendet der mit der Batteriespannung gespeist wird. Auch wenn sich die Akkuspannung ändert bleiben die Verhältnisse zwischen den Tastenwiderständen gleich, die Messung wird nicht beeinflußt. Anders das Snake-Vision. Um mit den Wärmesensoren gute Ergebnisse zu erzielen wurde auf der Platine ein 5V-Spannungsregler (getrieben über die Ladungspumpe um OCR2 (https://www.roboternetz.de/community/threads/47843-Projekt-RP6-mit-Snake-Vision?p=525640&viewfull=1#post525640)) zur Versorgung eingebaut. Deshalb schwanken die Ausgangsspannungen des Moduls nicht mit der Akkusspannung und deshalb muss man diese Spannungen mit der internen 2,56V-Referenz des ADC messen.

Über die Umschaltprobleme der Referenz bin ich kürzlich schon mal gestolpert, dabei ging es um die Akkuspannungsmessung bei der bee:
http://www.roboter.cc/index.php?option=com_kunena&func=view&catid=3&id=1707&limit=6&limitstart=18&Itemid=20#1784

Gruß

mic