- fchao-Sinus-Wechselrichter AliExpress         
Seite 2 von 4 ErsteErste 1234 LetzteLetzte
Ergebnis 11 bis 20 von 31

Thema: Minimallösung: Servo-Sensor

  1. #11
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Anzeige

    Praxistest und DIY Projekte
    Hallo

    Ich habe den Code etwas umgestrickt. Der Impuls wird nun über einen 8bit-Timer per Interrupt erzeugt. In der Servo-ISR wird zum richtigen Zeitpunkt (der ist extrem wichtig!) das einmalige Wandeln des ADC angestoßen. Wenn die Wandlung beendet ist, wird in einer ADC-ISR das Ergebniss in adc_servo gespeichert. In der Hauptschleife wird dieser Wert mit LEDs ausgegeben (für den RP6):
    Code:
    // Servo-Lastmessung am Steuerpin                                 9.2.2008  mic
    
    // In der 20ms-Signalpause wird die Spannung am Steuerpin des Servos gemessen
    // und ausgewertet.
    
    #include "rblib.h"
    #include "rblib.c"
    
    uint8_t adc_pos; 				// Position des Servos
    uint16_t adc_servo;        // Messwert der Signalleitung
    
    void servo_ON(void)        // Servo-ISR starten
    {
    	cli();
    	TCCR0 =  (0 << WGM00) | (1 << WGM01);					// CTC-Mode
    	TCCR0 |= (0 << COM00) | (0 << COM01);					// ohne OCR-Pin
    	TCCR0 |=	(0 << CS02)  | (0 << CS01) | (1 << CS00);	// prescaler /1
    	TIMSK =  (1 << OCIE0); 										// Interrupt ein
    	OCR0  = 105;
    
    // 5V-Referenz, Kanal 0
    	ADMUX = (0<<REFS1) | (1<<REFS0) | 0;
    // Interrupt ein, ADC enable, prescal /16, altes Flag löschen
    	ADCSRA = (1<<ADIE) | (1<<ADEN) | (1<<ADPS2) | (1<<ADIF);
    
    	sei();
    }
    
    int main(void)
    {
    	rblib_init();
    	adc_pos=100;			// Position der Servos
    	adc_servo=0;         // Startwerte setzen
    	servo_ON();          // Servo-ISR starten
    
    	while(1)
    	{
    		setLEDs(adc_servo);
      	}
    	return 0;
    }
    
    ISR(ADC_vect)
    {
    	adc_servo=ADC;                		// jetzt messen wir die Spannung!
    }
    
    ISR(TIMER0_COMP_vect)
    {
    	static uint16_t count=0; 				// Zykluszähler
    	if (count>adc_pos)                  // Servoimpuls senden?
    	{
    		DDRA &= ~1;                      // nein: auf Eingang ohne PullUp
    		PORTA &= ~1;
    		if (count == adc_pos+100)        // seit 100 Takten auf Eingang gesetzt,
    		{
    		   	ADCSRA |= (1<<ADSC);      // ADC starten
    		}
    	}
    	else
    	{
    		DDRA |= 1;                      // Impuls senden, Pin auf Ausgang
    		PORTA |= 1;                     // und high
    	}
    	if(count<2000) count++; else count=0; // Zyklus fertig?
    }
    Hier noch eine Anwendung für einen 8MHz-Mega32 ohne RP6-Funktionen:

    Code:
    // Servo-Lastmessung am Steuerpin mit einem 8MHz-ATMega32         10.2.2008 mic
    
    // In der 20ms-Signalpause wird die Spannung am Steuerpin des Servos gemessen
    // und ausgewertet. Servoimpuls wird mit einem 8bit-Timer im CTC-Mode per ISR
    // erzeugt. Kurz nach Ende des Impulses wird der ADC gestartet und der Messwert
    // in einer ADC-ISR eingelesen.
    
    #include <avr/io.h>			// I/O Port definitions
    #include <avr/interrupt.h>	// Interrupt macros
    
    // Position des Servos, Belastungszähler
    uint8_t servo_pos;
    // Messwert der Signalleitung, Verzögerung
    volatile uint16_t servo_adc, servo_count, pause;
    
    void init_servo(void)         // Servo-ISR starten
    {
    	cli();
    	TCCR0 =  (0 << WGM00) | (1 << WGM01);					// CTC-Mode
    	TCCR0 |= (0 << COM00) | (0 << COM01);					// ohne OCR-Pin
    	TCCR0 |=	(0 << CS02)  | (0 << CS01) | (1 << CS00);	// prescaler /1
    	TIMSK =  (1 << OCIE0); 										// Interrupt ein
    	OCR0  = 105;                                       // Servomitte=100?
    
    // 5V-Referenz, Kanal 0
    	ADMUX = (0<<REFS1) | (1<<REFS0) | 0;
    // Interrupt ein, ADC enable, prescaler /16, altes Flag löschen
    	ADCSRA = (1<<ADIE) | (1<<ADEN) | (1<<ADPS2) | (1<<ADIF);
    	sei();
    }
    void wait(uint8_t p)
    {
    	pause=p;
    	while(pause);
    }
    int main(void)
    {
    	servo_pos=100;			// Position des Servos
    	servo_adc=-1;         // Startwerte setzen
    	init_servo();        // Servo-ISR starten
    	wait(20);
    
    	while(1)
    	{
    weiter2:
    	   servo_pos+=2;
    		servo_count=0;
        	while((servo_pos++ < 200))
    		{
    	   	wait(1);
    	   	while(servo_count > 8)
    	   	{
    	   	   if (servo_count > 15) goto weiter1;
    	   	}
    		}
    weiter1:
    	   	servo_pos-=2;
    		servo_count=0;
        	while((servo_pos-- > 30))
    		{
    	   	wait(1);
    	   	while(servo_count > 8)
    	   	{
    	   	   if (servo_count > 15) goto weiter2;
    	   	}
    		}
    	}
    	return 0;
    }
    
    ISR(ADC_vect)
    {
    	servo_adc=ADC;                		// ADC-Messung beendet, Wert speichern
    	if (servo_adc) servo_count++; else servo_count /=2;
    	
    }
    
    ISR(TIMER0_COMP_vect)
    {
    	static uint16_t count=0; 				// Zykluszähler
    	if (count>servo_pos)                  // Servoimpuls senden?
    	{
    		DDRA &= ~1;                      // nein: auf Eingang ohne PullUp
    		PORTA &= ~1;
    		if (count == servo_pos+100)        // seit 100 Takten auf Eingang gesetzt,
    		{
    		   ADCSRA |= (1<<ADSC);      		// ADC starten
    		}
    	}
    	else
    	{
    		DDRA |= 1;                      // Impuls senden, Pin auf Ausgang
    		PORTA |= 1;                     // und high
    	}
    	if(count<2000) count++; else {     // Zyklus fertig?
    		count=0;
    		if (pause) pause--;
    	}
    }
    und das Video dazu:
    Bild hier  
    http://www.youtube.com/watch?v=39tOx0IxQ40

    Der Steuerpin hängt dabei ohne weitere Beschaltung direkt am ADC-Pin. Gemessen habe ich Werte bis über 30. Direkt nach dem Impuls messe ich noch für einige Zyklen das High des Impulses, gegen Ende des Zyklus bleibt der Wert immer bei 0. Gut funktioniert's um 100, sogar mit diesem Müll-Code...

    Gruß

    mic
    Bild hier  
    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  2. #12
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.01.2009
    Ort
    NRW
    Beiträge
    562
    Hallo

    Sehr interessantes Projekt!
    Ich steuer meinen Servo über die M32 Erweiterung
    mit folgender Methode an:

    void ServoG(uint8_t pos)
    {
    DDRC |= IO_PC7;
    PORTC |= IO_PC7;
    sleep(pos);
    PORTC &= ~IO_PC7;
    sleep(185);
    }

    Ich habe mir deine Programme angeguckt aber leider nicht verstanden wann genau die ADC-Messung wie erfolgen muss.
    Ich wollte über die M32 ADC-Kanäle messen.
    Kannst du mir dies nochmal für mein Beispiel erklären?

    Gruß Thund3r

  3. #13
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Hallo

    Bei deiner Ansteuerung musst du während sleep(185); messen. Mein Messpunkt war 100 Einheiten nach dem Impulsende. Weil deine Sleep()-Ansteuerung um den Faktor 10 langsamer ist, würde ich etwa folgenden Messpunkt vorschlagen:

    sleep(10);
    readADC(kanal); // Nicht zusammen mit task_ADC() verwenden!
    sleep(175);

    Zusätzlich (noch vor demSleep(10);) musst du die Datenrichtung des Pins auf Eingang setzen!

    In der RP6-Library wird der ADC mit externer Spannungsreferenz und Prescaler /64 verwendet, beim M32 weiß ich das nicht auswendig. Ich verwende die internen 5V und Prescaler /16. Vor allem das vielmal schnellere Wandeln der Spannung könnte wichtig für diese Servo-Sensor-Funktion sein. Vielleicht solltest du für die ersten Versuche dieses Setup übernehmen, bzw. Prescaler /32 bei 16MHz des M32.

    Gruß

    mic
    Bild hier  
    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  4. #14
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.01.2009
    Ort
    NRW
    Beiträge
    562
    Hallo

    Ich hab die ADC-Messung zwischen die sleep gebaut.
    Leider funktioniert es nicht. Er misst permanent 0.

    Den Teil:


    In der RP6-Library wird der ADC mit externer Spannungsreferenz und Prescaler /64 verwendet, beim M32 weiß ich das nicht auswendig. Ich verwende die internen 5V und Prescaler /16. Vor allem das vielmal schnellere Wandeln der Spannung könnte wichtig für diese Servo-Sensor-Funktion sein. Vielleicht solltest du für die ersten Versuche dieses Setup übernehmen, bzw. Prescaler /32 bei 16MHz des M32.
    Hab ich nicht verstanden.

    Könntest du mir das etwas genauer erläutern und mir erklärn wie ich weiter vorgehn kann?

    Gruß Thund3r

  5. #15
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Hallo

    Hab ich nicht verstanden.
    Ist eigentlich auch nicht wichtig. Da wir hier ja nur eine einzelne Messung machen, spielt das keine Rolle. Beim Start der Messung wird die Spannung in das Sample&Hold-Register kopiert und dann ist es unwichtig, wie schnell wir den Wert wandeln. Und da die Dauer der Wandlung (sie ist bei readADC() blockierend) auch mit Prescaler /64 das Timeing der Impulspause des Servos wohl nicht stört, kann man sicher auch das orginale ADC-Setup der M32-Lib verwenden. Sorry, war mein Fehler.

    Ich hab die ADC-Messung zwischen die sleep gebaut.
    Leider funktioniert es nicht. Er misst permanent 0.
    Vielleicht solltest du mal dein aufs nötigste reduzierte Programm zeigen. Aber nicht nur ein paar Fetzen sondern schon eine kompilierbare und lauffähige Version. Wie oben geschrieben funktioniert es auch nicht mit allen Servos.

    Gruß

    mic
    Bild hier  
    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  6. #16
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.01.2009
    Ort
    NRW
    Beiträge
    562
    Hallo

    Also ich benutze den TOP-LINE MINI SERVO ES-05 JR von Conrad.

    Meine Methoden sehen so aus:

    Code:
    void ServoG(uint8_t pos)
        {
    	 DDRC |= IO_PC7;
         PORTC |= IO_PC7;   
         sleep(pos);          
         PORTC &= ~IO_PC7; 
    	 sleep(10);
    	 messG();
    	 sleep(175);
    	}
    
    ...
    
    void messG()
    	{
    	 uint16_t adc5 = readADC(ADC_5);
    	 clearLCD();
    		setCursorPosLCD(0, 0);
    		writeStringLCD("Belastung: ");
    		writeIntegerLCD(adc5, DEC);
    		if(adc5>0)
    		{  setLEDs(0b1111);}
    		}
    ...
    
    void gtest(void) // im Hauptprogramm aufgerufene Methode
    	{
    		  int c;
            setLEDs(0b0000);
    	for(c=0;c<=50;c++)
    	{
    	ServoG(12);
    	mSleep(20);
    	}
    	
    	 mSleep(1000);
    	 for(c=0;c<=50;c++)
    	{
    	ServoG(21);
    	mSleep(20);
    	}
    	
    	mSleep(1000);
    	setLEDs(0b0000);
    	}
    Gruß Thund3r

  7. #17
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Hallo

    Ich wollte über die M32 ADC-Kanäle messen.
    Und der ATMega32 im M32 hat seine ADC-Eingänge an Port C7? Was ist damit: "Zusätzlich (noch vor demSleep(10);) musst du die Datenrichtung des Pins auf Eingang setzen!"

    Vergleiche doch mal was ich zwischen Sleep(10); und Sleep(175); vorgeschlagen habe und was du eingebaut hast. Die vom LCD vertrödelte Zeit kannst du am folgenden Sleep(175); möglicherweise wieder reinholen. Bewegt sich das Servo eigentlich?

    Gruß

    mic
    Bild hier  
    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  8. #18
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.01.2009
    Ort
    NRW
    Beiträge
    562
    Hallo

    Der Port C7 ist ein IO Port (IO_PC7; )

    ADC_5 ist mein ADC-kanal den ich benutze.

    Ah "...musst du die Datenrichtung des Pins auf Eingang setzen!"

    Nun funktioniert es.
    Vielen Dank für deine Unterstützung!

    Nun möchte ich meinen Greifer mit dem Programm aufpeppn so dass der Greifer wenn er Widerstand spürt nich weiter drückt sondenr nur einen stabilen Griff hält.

    Gruß Thund3r

  9. #19
    Erfahrener Benutzer Begeisterter Techniker Avatar von RobbyMartin
    Registriert seit
    31.12.2009
    Ort
    Leverkusen
    Alter
    30
    Beiträge
    206
    Mir ist gerade so ne Idee gekommen koennte man nicht ueber ein adc Eingang den Strom über ein spannungsteiler messen, da soweit ich weiß wenn der servo blockiert der Strom steigt.

    Das waere im Prinzip doch viel einfacher oder irre ich mich??

    LG
    Martin

  10. #20
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Nochmals hallo

    Nun funktioniert es.
    Das ist verblüffend. Wenn das Servo mit seiner Signalleitung an PC7 "hängt", wie kannst du dann die Spannung an dieser Signalleitung an ADC_5 (PA5) messen? Aber wenn es funktioniert ist es ja gut...

    ...koennte man nicht ... den Strom über einen Spannungsteiler messen...?
    Das könnte man schon, aber die Idee ist nicht wirklich neu und wurde weiter oben schon angesprochen. Und das wäre dann doch keine Minimalösung (=keine weiteren Bauteile) mehr, oder?

    Gruß

    mic
    Bild hier  
    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

Seite 2 von 4 ErsteErste 1234 LetzteLetzte

Berechtigungen

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

LiFePO4 Speicher Test