- LiFePO4 Speicher Test         
Ergebnis 1 bis 10 von 28

Thema: Asuro und Labyrinthe aus Linien - machbar?

Baum-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #21
    Benutzer Stammmitglied
    Registriert seit
    08.05.2005
    Ort
    München
    Alter
    52
    Beiträge
    59
    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  

Berechtigungen

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

12V Akku bauen