- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
Seite 3 von 3 ErsteErste 123
Ergebnis 21 bis 28 von 28

Thema: Asuro und Labyrinthe aus Linien - machbar?

  1. #21
    Benutzer Stammmitglied
    Registriert seit
    08.05.2005
    Ort
    München
    Alter
    52
    Beiträge
    59
    Anzeige

    Praxistest und DIY Projekte
    Hallo,

    Hier erst mal meine ADC Routine:
    Ist leicht abgeändert vom Original aber trotsdem danke an Rakke. Sein Code hat den Vorteil, das die Odometriesenoren im vergleich zu den anderen häufiger abgefragt werden und daher die Messung genauer wird.

    Code:
    /***************************************************************************
    SIGNAL (SIG_ADC)
    Interuptfunktion zum Auswerten mehrerer ADC-Kanäle nach einer vorgebbaren
    Konfigurationsliste. Zugriff auf global definierte Variablen für die ADC-Kanäle.
    
    last modification:
    Ver.     Date         Author           Comments
    -------  ----------   --------------   ---------------------------------
    beta1	 31.03.2005   Robotrixer	   counting odometrie tics
    sto1     29.07.2005   stochri		   Wheelspeed,hysteresis
    rakke	 20.12.2005	  Rakke			   Konfigliste, glob. Var für Line, Bat etc
    -------  ----------   --------------   ---------------------------------
    
    ***************************************************************************/
    #define	ADC_CTRL_MANYS		12	///>Zahl der Stützpunkte der configliste
    
    #define	ADC_CTRL_ODO_LEFT	1
    #define	ADC_CTRL_ODO_RIGHT	0
    #define	ADC_CTRL_LINE_LEFT	3
    #define	ADC_CTRL_LINE_RIGHT	2
    #define	ADC_CTRL_SWITCHES	4
    #define	ADC_CTRL_BATTERY	5
    
    // der folgende define erleichtert das berechnen des Wertes ADMUX.
    //		admux_pre_calc =  (0 <<REFS1)	// AVCC with external ...
    //						| (1 <<REFS0)	// ... capacitor at AREF pin;
    //						| (1 <<ADLAR);	// Ergebnis in ADCH, ADCL links ausrichten
    #define	ADMUX_PRE_CALC		0x60
    
    const unsigned char adc_mux_config_list[ADC_CTRL_MANYS] = {
    	WHEEL_RIGHT,
    	WHEEL_LEFT,
    	IR_RIGHT,
    	WHEEL_RIGHT,
    	WHEEL_LEFT,
    	IR_LEFT,
    	WHEEL_RIGHT,
    	WHEEL_LEFT,
    	SWITCH,
    	WHEEL_RIGHT,
    	WHEEL_LEFT,
    	BATTERIE
    	};
    
    
    SIGNAL (SIG_ADC)
    {
    	// für die Odometrie:
    	static unsigned char flag[2];	///> merkt sich für jede Seite, ob steigende oder fallende Flanke
    	static unsigned char adc_cnt=0;	///> Merker für die Auswertung
    	unsigned char adc_channel;		///> Kanal für die Auswertung
    	
    	unsigned char	side;			///> side = 0: linkes, side = 1: rechtes Rad
    	unsigned char	adc_lo;			///> zum Zwischenspeichern des ADC_lo_Wertes
    	unsigned char	adc_hi;			///> zum Zwischenspeichern des ADC_hi_Wertes
    	unsigned int	temp;			///> Hilfsvariable
    
    	const unsigned char grenzlow[2]={167,142}; // {LL,RL}
    	const unsigned char grenzhigh[2]={173,148}; // {LH,RH}
    
    	static unsigned int switcheshist[4]={0,0,0,0};
    	
    	// ADCL muss zuerst gelesen werden! Sonst können sich zwei Wandlungen überschneiden.
    	adc_lo= ADCL;		// Zwischenspeichern des ADC-Wertes in temp. Variable
    	adc_hi= ADCH;		// Zwischenspeichern des ADC-Wertes in temp. Variable
    	
    	if(autoencode==ADC_RUN)		// Aus Kompatibilitätsgründen und weil sehr praktisch für debugging wird autoencode weiter benutzt
    	{
    
    		adc_channel = adc_mux_config_list[adc_cnt];	// nachgucken: welcher Kanal wurde gerade gewandelt? Fürs bessere Verständnis als eigene Variable eingeführt. Wenns mal knapp wird, lässt sich hiereine sparen...
    
    		// Für die Auswertung je nach gewähltem Kanal unterschiedlich verfahren
    		switch(adc_channel)
    		{
    			// Odometriesensoren. Code von stochri weitgehend übernommen.
    			case ADC_CTRL_ODO_LEFT:
    			case ADC_CTRL_ODO_RIGHT:
    				/*
    				Unterscheidung nach steigender und fallender Flanke. Bei steigender Flanke wird 
    				nur der encoder_counter der jeweiligen Seite hochgesetzt und das Flag für "gestiegene
    				Flanke" gesetzt.
    				Die Seite bestimmt sich aus "adc_channel". Da encoder[0] aus AD-Eingang=1 und encoder[1] 
    				aus AD-Eingang=0 kommen, muss die Seite über XOR getauscht werden, um mit WEJA/stochri
    				kompatibel zu bleiben.
    				Wenn die Bytes mal ganz arg knapp werden, lässt sich hier eins sparen...
    				*/
    				side = adc_channel ^ 1;
    					// Hysteresis included 25.6.2005 stochri
    				if ( (adc_hi < grenzlow[side]) && (flag[side] == TRUE)) // falling edge
    				{
    					encoder[side] ++;
    					flag[side] = FALSE;
    				}
    				
    				if ( (adc_hi > grenzhigh[side]) && (flag[side] == FALSE)) // rising edge
    				{
    					encoder[side] ++;
    					flag[side] = TRUE; 
    				}
    				break;
    			
    			// Liniensensoren. Liefert die gleichen Werte wie "LineData"
    			case ADC_CTRL_LINE_LEFT:
    			case ADC_CTRL_LINE_RIGHT:
    				side = (adc_channel & 0x01)^ 1;	// nur das kleinste Bit vom adc_channel auswerten
    				temp = (((unsigned int)adc_hi)<<8) + ((unsigned int)adc_lo);
    				line[side] = temp>>6;	// Ergebnis ist links ausgerichtet
    				break;
    
    			// Kollisionstaster. Liefert die gleichen Werte wie "Pollswitch" und funktioniert genauso gut. Hm.
    			case ADC_CTRL_SWITCHES:
    				temp = ((((unsigned int)adc_hi)<<8) + ((unsigned int)adc_lo))>>6;  // align right
    				temp = (unsigned char)(((10240000L/(long)temp-10000L)*62L+5000L)/10000);
    				switcheshist[3] = switcheshist[2];  // shiftregister
    				switcheshist[2] = switcheshist[1];  // shiftregister
    				switcheshist[1] = switcheshist[0];  // shiftregister
    				switcheshist[0] = temp;
    				if (switcheshist[0] == switcheshist[1] && switcheshist[0] == switcheshist[2] && switcheshist[0] == switcheshist[3])	// nur wenn alle werte gelich sind, wird wert übernommen.
    					switches = temp;						// ansonsten bleibt switches beim alten wert. 
    				break;
    				
    			// Batteriespannung. Liefert die gleichen Werte wie "Batterie" und funktioniert genauso gut. Der Vollständigkeit halber aufgeführt.
    			case ADC_CTRL_BATTERY: 
    				u_Bat  = (((unsigned int)adc_hi)<<8) + ((unsigned int)adc_lo);
    				u_Bat  = u_Bat >>6;	
    				break;
    		}
    		
    		/*
    		ADC-MUX für die nächste AD-Wandlung auf den nächsten Kanal der Konfigliste umschalten.
    		*/
    		adc_cnt = adc_cnt + 1;			// nächstes Listenelement
    		if (adc_cnt >= ADC_CTRL_MANYS)	// Listenende erreicht?
    			adc_cnt = 0;				// Dann von vorne anfangen!
    		
    		ADMUX = ADMUX_PRE_CALC + adc_mux_config_list[adc_cnt];// aus der config-Liste den nächsten Kanal holen
    	}
    
    	/*
    	Schließlich noch die nächste Konversion starten: das ADSC-Bit wird nach Beendigung der Wandlung durch den 
    	ATmega auf null gesetzt. 	
    	Dies muss außerhalb der "if(autoencode)" erfolgen, sonst wird der Interrupt nicht mehr ausgelöst!
    	Soll also - z. B. wenn die Zeit mal knapp ist - der Code "gekürzt" werden, dann über autoencode = 0 ausschalten.
    	*/
    	ADCSRA = ADCSRA | (1<<ADSC);
    }// Ende der rakke'schen ADC-Interruptroutine
    Und hier Bilder von meiner Linienverfolgungseinheit:
    Damit bin ich eigentlich sehr zufrieden.
    Miniaturansichten angehängter Grafiken Miniaturansichten angehängter Grafiken asuro_von_unten.jpg   asuro_von_vorne.jpg  

  2. #22
    Neuer Benutzer Öfters hier
    Registriert seit
    29.12.2005
    Beiträge
    20
    *hmpf* gestaltet sich schwierig.
    Martin, ich glaube, du hast die drei Tage wirklich sehr gründlich programmiert, hm?

  3. #23
    Neuer Benutzer Öfters hier
    Registriert seit
    29.12.2005
    Beiträge
    20
    So... ich hab nach wie vor Probleme damit, die Kreuzungen korrekt abzuarbeiten. Vielleicht kann mir wer Tips geben, ich hab mit ganz naiven Annahmen gearbeitet, weil ich nicht soviel Zeit hab, mich tiefer einzuarbeiten.

    Ich beschreib mal, was ich gemacht habe: die erweiterte asuro.c verwendet, die die Methode Turn() von Stochri und Andun enthält. Diese Methode hab ich kopiert und einen Liniencheck eingebaut. Also
    - drehe links 30 Grad ohne Liniensuche
    - drehe weiter 65 Grad, mit Liniensuche
    - messe mit FrontLED on und off und rechne den absoluten Helligkeitswert heraus.
    - ist dieser Wert unter dem Threshold von Schwarz (den ich vorher ausgemessen hab; ist sehr unterschiedlich auf beiden Seiten der Linienfolgeeinheit), so stoppe die Motoren und beende den Turn
    - wenn nichts gefunden, drehe 275 Grad nach rechts mit Liniensuche.

    Soweit der abstrakte Ansatz.

    Ich drehe mit 90 Speed, damit der Roboter auch ja nicht zu schnell unterwegs ist und etwas übersieht.

    Konkrete Fragen zu Problemen kann ich erst heut ab 14 Uhr stellen, weil ich da programmieren kann.
    Falls es einstweilen Tips "Du, da gibts ein prinzipielles Problem..." gibt, bin ich sehr dankbar.
    Ansonsten meld ich mich später wieder mit konkreten Fragen.

    Danke für die Aufmerksamkeit
    Melitta

  4. #24
    Benutzer Stammmitglied
    Registriert seit
    08.05.2005
    Ort
    München
    Alter
    52
    Beiträge
    59
    Hi,

    prinzipiell habe ich an deinem Vorgehen nichts auszusetzen. Mache ich genau so.

    Allerdings erkenne ich auch den Unterschied zwischen 1 LED steht auf Linie und Linie ist unterhalb des Asuro und ich breche mein Drehen dann ab, wenn die Linie unterhalb des Asuros ist.

    Das geht deshalb, weil die Helligkeitsunterschiede jedes Fototransistors absolut und relativ zueinander immer unterschiedlich sind bei den Zuständen:
    1. Keine Linie
    2. Linie nur unter einem Fototransistor
    3. Linie zwischen beiden Fototransistoren.

    Martin

  5. #25
    Neuer Benutzer Öfters hier
    Registriert seit
    09.02.2006
    Beiträge
    5

    Helligkeiten?

    Hey MSSputnik, ich habe mit Begeisterung dein Programm ausprobiert. Als ich aber versucht habe, die Schwellenwerte für hell/dunkel anzugeben, habe ich die einzige Möglichkeit in der highlevel.c gesehen. Leider wird diese Datei meines Wissens in keinster Weise in den Quellcode des "eigentlichen" Programms mit einbezogen - und somit die Schwellenwerte nicht an den Roboter weitergegeben. Wie kann das sein? Bzw. wie bekommt man denn nun die richtigen Schwellenwerte "auf" den Roboter? ^^


    Greetz, Michi

  6. #26
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    29.04.2005
    Ort
    Weilburg
    Beiträge
    676
    Probier doch mal diese Moglichkeit.
    Die Ermittlung der Schwellenwerte ist damit recht gut.
    https://www.roboternetz.de/phpBB2/vi...=123226#123226
    Prostetnic Vogon Jeltz

    2B | ~2B, That is the Question?
    The Answer is FF!

  7. #27
    Neuer Benutzer Öfters hier
    Registriert seit
    09.02.2006
    Beiträge
    5
    Vielen Dank für die Antwort, Vogon!
    Leider hast du meine Frage etwas missverstanden. Die Schwellenwerte hab ich schon ermittelt, ich muss sie nur noch meinem Roboter "beibringen" und da steig ich nicht so wirklich durch, wenn ich ehrlich bin ^^

    EDIT:
    Ich habs geblickt... wer lesen kann, ist klar im Vorteil *g*
    Allerdings ne andere Frage. Wie geht denn aus dem Programm hervor, dass der Roboter sich um z.B. 40° dreht? Bei mir macht der nämlich nur wirres Zeug
    Ich bin jetzt nicht so der Überflieger was C-Programmierung angeht, von daher bitte ich um etwas Nachsicht

  8. #28
    Benutzer Stammmitglied
    Registriert seit
    08.05.2005
    Ort
    München
    Alter
    52
    Beiträge
    59
    Hallo,

    damit es alle mitbekommen. Die Schwellwerte für die Linienerkennung werden in der highlevel.h eingetragen.
    Code:
    /* Schwellwerte für die Linienerkennung
     */
    #define LIGHT_HIGH_MID 0x55
    #define LIGHT_MID_LOW  0x28
    Und das Drehen um 40° wird über die Funktion 'go' erledigt.
    Allerdings habe ich keine Umrechnung in einen Winkel eingebaut. Man kann hier nur 'ticks' also die Zahl der Farbwechsel auf der Odometriescheibe angeben. Bei mir sind ca. 30° 20 ticks oder so.
    Damit solltes du 'go(27,-27,GO_STOP,-20)' angeben. (GO_STOP -> nach dem Drehen Motoren ausschalten. -20 -> Von der Basisgeschwindigkeit 20 abziehen für die Drehgeschwindigkeit)

    Martin

Seite 3 von 3 ErsteErste 123

Berechtigungen

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

Solar Speicher und Akkus Tests