-
        

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

Thema: RP6 Fernsteuerung über RC-Empfänger

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    01.05.2008
    Beiträge
    52

    RP6 Fernsteuerung über RC-Empfänger

    Anzeige

    Hallo auch,
    ich hab vor für meinen RP6 eine Art Fernsteuerung zu bauen.
    Dazu habe ich von meinem damaligen Fluzeug noch Fernsteuerung und Empfänger sowie Servos übrig die alle noch funktionieren. (Bis auf die Akkus *g*)

    Ich hatte mir überlegt, dass ich über Funk den RP6 am Anfang nur sage entweder vorwärts fahren, rückwärts fahren, links drehen oder rechts drehen. Alles einzeln also erstmal nicht manches gleichzeitig. Das kommt später evtl dazu.

    Nun hab ich mir gedacht ich könnte ja das Signal des Empfängers irgendwie zur Fernsteuerung des RP6 nutzen. Da fängt aber auch schon mein Problem an. Der Empfänger gibt das empfangene Signal ja über eine Pulsweitenmodulation an die Servos weiter. Zumindest habe ich das so rausgefunden. Wie darf ich das denn aber verstehen. Pulst der zwischen 0V und +Vcc (Vcc nenn ich mal die Spannung die der über die Akkus bekommt) oder zw. -Vcc und +Vcc.
    Und wenn er dann da die Pulsweite ändert, hat der dann ohne ein Signal nen Taktverhältnis von 1:1 und verschiebt das dann nur in Richtung von z.B. 2:1 bzw 1:2?
    Falls der nämlich nur zw. 0 und +Vcc rumtaktet un da das Tastverhältnis ändert könnte ich ja einfach hingehen, das über ne Diode "gleichrichten" un dann an nen AD-wandler schicken. Wenn dann das Signal über dem wert von eben 1:1 ist soll er vorwärts fahren sonst rückwärts und für rechts und links eben analog dazu.

  2. #2
    Erfahrener Benutzer Robotik Visionär Avatar von Hubert.G
    Registriert seit
    14.10.2006
    Ort
    Pasching OÖ
    Beiträge
    6.183
    Sieh mal hier wie ein Servo angesteuert wird: www.roboternetz.de/wissen/index.php/Servo
    Grüsse Hubert
    ____________

    Meine Projekte findet ihr auf schorsch.at

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

    Wenn man zur Ansteuerung der Servos die Variante aus dem RN-Wissen verwendet, ist die Auswertung eines RC-Empfängers unglaublich einfach:

    Code:
    ISR(TIMER0_COMP_vect) 
    { 
       //static uint16_t count=0; 
       static uint16_t rc_temp_pwr=0; 
       static uint16_t rc_temp_dir=0; 
       //if(count>x) PORTA &= ~16; else PORTA |= 16;   // E_INT1 (Pin8) 
       //if(count>y) PORTC &= ~1;  else PORTC |= 1;   // SCL (Pin10) 
       //if(count>z) PORTC &= ~2;  else PORTC |= 2;   // SDA (Pin12) 
       //if(count<1000)count++; else count=0; 
       if (PINC & 1) rc_temp_dir++; else 
          if (rc_temp_dir) { rc_input_dir=rc_temp_dir-1; rc_temp_dir=0; } 
       if (PINC & 2) rc_temp_pwr++; else 
          if (rc_temp_pwr) { rc_input_pwr=rc_temp_pwr-1; rc_temp_pwr=0; } 
    }
    (Codeschnippsel aus meinem Dominoday-Thread)

    Das ist die Timer-ISR die normalerweise die Impulslängen der Servosignale generiert. Mit ihr kann man auch sehr bequem die Impulslängen des Empfängers messen. Die lokalen Variablen rc_temp_pwr und rc_temp_dir sind die Hilfsvariablen für die Impulsmessung, rc_input_pwr und rc_input_dir die globalen Variablen für die Werte der Kanäle die man dann im Programm auswerten kann.

    Das funktioniert dann so:

    Code:
    if (PINC & 1) rc_temp_dir++;  // solange der Impuls anliegt wird der Zähler erhöht
     else if (rc_temp_dir) // Es liegt kein Impuls an und der Zähler ist !=0
    rc_input_dir=rc_temp_dir-1; // dann ist der gezählte Wert die Impulsdauer
     rc_temp_dir=0; // Zähler wieder rücksetzen, Ergebniss steht jetzt in rc_input_dir
    Gruß

    mic

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

  4. #4
    Benutzer Stammmitglied
    Registriert seit
    01.05.2008
    Beiträge
    52
    Ich danke euch schonmal.
    Hab aber gleich noch ein paar weitere Fragen an radbruch.
    Zum einen, ich hab meinen RP6 noch nicht sehr lange. Ich nehme mal an das
    PINC & 1 so viel bedeutet wie PortC Pin 1 oder?

    Und andererseits, wenn er solange den Zähler erhöhen soll wie der Impuls anliegt, dann kann ich ja erst darauf durch fahren reagieren wenn der komplette Impuls anliegt. Dann kann der ja nur Stück für Stück fahren oder hab ich da grad einen Denkfehler.

    Und wirklich genau wird das doch auch erst wenn ein Schleifendurchlauf des kompletten Programmes dann möglichst kurz ist.

    Mein RP6 soll eben ein automatisches Programm erledigen bis ich anfangen ihn zu steuern. Wenn ich aufhöre zu steuern soll er auch nach kurzer Wartezeit wieder mit dem automatischen Programm anfangen.

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

    Ich nehme mal an das PINC & 1 so viel bedeutet wie PortC Pin 1 oder?
    Das sind die SDA/SCL-Anschlüsse des XBUS-Steckers. (Es ist aber PortC.0 mit der Wertigkeit 1, ATMega32-Pin 22(SCL)) Ich hatte mir mal für den XBUS einen kleinen Adapter gebastelt:

    http://www.roboternetz.de/phpBB2/zei...=322579#322579

    ...dann kann ich ja erst darauf durch fahren reagieren wenn der komplette Impuls anliegt. ...hab ich da grad einen Denkfehler?
    Mach dir mal bewusst, dass die ISR 100000 mal pro Sekunde aufgerufen wird! Das ergibt 50 Impulse pro Sekunde (=alle 20ms), also 50 Messwerte pro Sekunde.

    Und wirklich genau wird das doch auch erst wenn ein Schleifendurchlauf des kompletten Programmes dann möglichst kurz ist.
    Wir verwenden einen Timerinterrupt, deshalb sind wir unabhängig vom Hauptprogramm das nur die rc_input_x-Werte auswerten muss. Übrigens, was bedeutet in diesem Zusammenhang "wirklich genau"? Wirklich entschiedend ist doch nur, dass die selbe Stellung des RC-Steuerknüppels immer mit dem selben Wert gemessen wird. Je nach gewünschter Auflösung kann man den Timertakt variieren um die Anzahl der ISR-Aufrufe zu optimieren.

    Mein RP6 soll eben ein automatisches Programm erledigen bis ich anfange ihn zu steuern.
    Dazu muss das automatische Programm prüfen ob ein RC-Input anliegt(rc_input_x != 0) Wenn ein Signal erkannt wird, folgt der RP6 der Fernsteuerung, wenn kein Signal erkannt wird (rc_inputx == 0) geht er wieder in den Automatik-Modus.

    Obwohl sich das alles recht einfach anhört, der Hacken ist die orginale Library des RP6. Sie verwendet alle Timer und somit funktioniert meine (und die im RN-Wissen) Lösung nicht ohne Tricks auf dem RP6. Mein hier gezeigter Weg ist eine minimale Lib mit den nötigsten Funktionen. Eine Alternative wäre z.b. den ADC-Interrupt zu nutzen.

    Gruß

    mic

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

  6. #6
    Benutzer Stammmitglied
    Registriert seit
    01.05.2008
    Beiträge
    52
    Ach mensch bin ich blöd. Hab nicht gesehen das des von der Interrupt Service Routine erledigt wird. Ok dann ist es ja klar
    Programm laufen lassen, ISR misst den Impuls un speichert dessen länge in ner Variablen, das Programm ruft die variable ab und handelt entsprechend oder eben nicht un läuft weiter, dann das ganze wieder von vorn.
    danke dir

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

    Ohne Interrupts, dafür aber blockierend könnte es so funktionieren (noch nicht getestet):
    Code:
    uint16_t get_RC(uint8_t kanal)
    {
    	uint16_t count=0;
    	if(kanal==1)                  // Erster RC-Kanal
    	{
    	   while(PINC & 1); 				// warten bis Ende des aktuellen Impuls
    	   while(!(PINC & 1));			// warten auf Ende Pause
    	   while(PINC & 1) count++; 	// Impulslänge messen
    	}
    	if(kanal==2)                  // Zweiter RC-Kanal
    	{
    	   while(PINC & 2);
    	   while(!(PINC & 2));
    	   while(PINC & 2) count++;
    	}
    	return(count);             	// Zählwert übergeben
    }
    Kleiner Überschlag: Bei 8MHz und 2ms Impulslänge und Erhöhung des Zählers bei jedem Takt: 0,002s/(1/8000000)=0,002/0,000000125=16000

    Weil "while(PINC & 1) count++;" aber sicher mehr als einen Takt benötigt wird dieser Wert nie erreicht und eine 16-Bit-Variable reicht als Zähler.

    Gruß

    mic

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

  8. #8
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    54
    Beiträge
    5.781
    Blog-Einträge
    8
    Nochmal hallo

    Nun habe ich die Funktion getestet, wie erwartet funktioniert das wunderbar:
    Code:
    // RC-Signal messen und auswerten                                  2.5.2008 mic
    
    #include "rblib.h"
    #include "rblib.c"
    
    uint8_t servopos;
    volatile uint16_t p=0;
    
    void pause(uint16_t p_dauer)
    {
    	p=p_dauer;
    	while(p);
    }
    
    uint16_t get_RC(uint8_t kanal)
    {
    	uint16_t count=0;
    	if(kanal==1)                  // Erster RC-Kanal
    	{
    	   while(PINA & 1); 				// warten bis Ende des aktuellen Impuls
    	   while(!(PINA & 1));			// warten auf Ende Pause
    		while(PINA & 1) count++; 	// Impulslänge messen
    	}
    	return(count);             	// Zählwert übergeben
    }
    
    int main(void)
    {
    	rblib_init();
    	DDRA |= 1;
    	servopos=0;
    
    	TCCR0 =  (0 << WGM00) | (1 << WGM01);					// CTC-Mode
    	TCCR0 |= (0 << COM00) | (0 << COM01);					// ohne OCR-Pin
    	TCCR0 |=	(0 << CS02)  | (1 << CS01) | (0 << CS00);	// prescaler /8
    	TIMSK =  (1 << OCIE0); 										// Interrupt ein
    	OCR0  = 13;
    
    	sei();
    	servopos=40;
    	while(1)
    	{
    		writeInteger(servopos, 10);
    		writeString(" - ");
    		writeInteger(get_RC(1), 10);
    		writeString("\n\r");
    		servopos+=10;
    		if(servopos>170)
    		{
    		   servopos=40;
    			writeString("\n\r");
    		   pause(50);
    		}
    		pause(10);
    	}
    	return 0;
    }
    
    ISR(TIMER0_COMP_vect)
    {
    	static uint16_t count=1;
    	if(count>servopos) PORTA&=~1; else PORTA|=1;
    	if(count<2000)count++; else { count=1; if(p) p--; }
    }
    Das Progamm steuert per ISR ein Servo an Pin ADC0 an. Gleichzeitig werden im Hauptprogramm am selben Pin die Impulslängen gemessen und angezeigt. (Ein auf Ausgang geschalteter Pin kann auch eingelesen werden: IR-Kommunikation mit dem RP6) Mit Prescaler /8 und OCR0=13 ist der Wert für Servomitte ungefähr 100 (Basis des Programms ist der Testcode meines aktuellen "Projekts"). Die Ausgabe am Terminal sieht so aus:
    Code:
    Terminal cleared!
    
    [RP6BOOT]
    
    [READY]
    40 - 368
    50 - 460
    60 - 552
    70 - 644
    80 - 736
    90 - 828
    100 - 920
    110 - 1012
    120 - 1104
    130 - 1196
    140 - 1288
    150 - 1380
    160 - 1472
    170 - 1564
    
    40 - 368
    50 - 460
    60 - 552
    Im Anhang nochmals meine minimale Lib auf Basis der RP6-Lib.

    Gruß

    mic
    Angehängte Dateien Angehängte Dateien

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

  9. #9
    Benutzer Stammmitglied
    Registriert seit
    01.05.2008
    Beiträge
    52
    Vielen Dank. Ich werde das dann gleich mal probieren wenn ich endlich dazu gekommen bin das mal einzubauen.

  10. #10
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    24.01.2008
    Ort
    Schrobenhausen, München
    Alter
    24
    Beiträge
    583
    Hi radbruch,

    meintest du bei

    void pause(uint16_t p_dauer)
    {
    p=p_dauer;
    while(p);
    }

    nicht doch eher ein

    Code:
    void pause(uint16_t p_dauer) 
    { 
       p=p_dauer; 
       while(p) p--;
    }
    ohne ein p--; kann das irgendwie keine andere Möglichkeit als eine dauerschleife geben, beispiel bei pause(10); :

    p=10
    while(p);//10 halt


    irgendwie sieht das für mich sehr nach dauerschleife aus


    MfG Pr0gm4n

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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