Forum: Analoge Elektronik und Schaltungstechnik Pwm von RC Empfänger mit Arduino verarbeiten


von Faros (Gast)


Lesenswert?

Hallo,
ich habe mir mit einem Arduino Uno eine Art Roboter gebaut, und möchte 
ihn nun  mittels meiner RC Funke Graupner Mx12s Junior, Empfänger Rs16 
Scan 40/41 MhZ steuern (brauche das Analog Signal, welches dann 
ausgewertet und an die Antriebe/Servos etc. gegeben wird). Softwaremäßig 
funzt alles und mit einem Poti als "Gaspedal" geht's wunderbar.

Die Frequenz der Pwm vom Empfänger hab ich leider nicht in Erfahrung 
bringen können, lediglich den Kanalraster, der 14 kHz beträgt.
Ich habs als erstes mit einem RC Tiefpass versucht mit verschieden 
niedrigen Grenzfrequenzen (ca. 5- 1000 Hz), allerdings keinerlei 
Reaktion beim Roboter bei Bewegung des Steuernüppels.

Gerade habe ich den Duty Cycle des Pwm mit der PulseIn Funktion 
gemessen, genauergesagt bei minimaler und maximaler Knüppelstellung und 
diese Zeit dann auf 0-1023 gemappt. So funktioniert die Regelung per 
Knüppel, nur muss ich dies mehreremale im Programmcode machen, der sich 
alle paar ms wiederholt. Es läuft zwar, aber elendslangsam ^^.

Ich weiß nicht welchen Fehler ich beim RC Tiefpass mache, habe bis jetzt 
nur Kondensatoren mit 0.47 (Folien) bzw. 4700 uF (Elko) verwendet, sind 
die Kapazitäten zu groß ?

Bin für jede Hilfe sehr dankbar
LG

von hinz (Gast)


Lesenswert?

Faros schrieb:
> Die Frequenz der Pwm vom Empfänger hab ich leider nicht in Erfahrung
> bringen können,

ca. 50Hz, mit sehr kleinem Tastverhältnis (1-2ms).


> lediglich den Kanalraster, der 14 kHz beträgt.

Nö, 10kHz, aber das hat damit nichts zu tun.

von Martin (Gast)


Lesenswert?

Hallo,

Die Information steckt in der Impulslänge, nicht im Tastverhältnis.

Die Periodendauern sind teilweise deutlich unterschiedlich, an mancher 
Fernsteuerung sogar umstellbar. Oft liegt sie so zwischen 20..25ms

Das Signal per Analogfilter zu rekonstruieren ist heutzutage nicht mehr 
wirklich sinnvoll.

k.A. was PulsIn macht, aber Pulslänge messen wäre der richtige Weg.

von foo (Gast)


Lesenswert?


von Björn R. (sushi)


Lesenswert?

2 Interrupte einrichten, einen der bei steigender Flanke an einem Pin 
auslöst und einen bei fallender. Oder einen Pinchange Interrupt und als 
erstes gucken ob der Pin high oder low ist.
Bei steigender Flanke: Timer starten
Bei fallender Flanke: Timer stoppen, Zählregister auslesen, Timer 
zurücksetzen. So misst du die Pulslänge. Die Timerfrequenz so 
einstellen, dass er bei 2,5ms Pulslänge noch nicht überläuft. 
Normalerweise sollte sich die Pulslänge zwischen 1 und 2ms bewegen, bei 
1,5ms ist der Knüppel in der Mitte. Das kann jedoch von Anlage zu Anlage 
leicht verschieden sein.

LG, Björn

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Faros schrieb:
> Ich weiß nicht welchen Fehler ich beim RC Tiefpass mache, habe bis jetzt
> nur Kondensatoren mit 0.47 (Folien) bzw. 4700 uF (Elko) verwendet, sind
> die Kapazitäten zu groß ?
Egal, ob die Schaltung prinzipiell irgendwas sinnvolles tun müsste, 
aber 5 Zehnerpotenzen ohne Zwischenwerte hören sich nach "blindem 
Stochern" an.

> sind die Kapazitäten zu groß ?
Das kommt auf den zugehörigen unbekannten Widerstand an. Aber der Ansatz 
ist schon Murks, weil die Pause zwischen zwei 1..2ms Pulsen nicht 
eindeutig definiert ist.

Auf jeden Fall passt die Strategie "filtern mit RC-Glied" nicht zur 
Strategie "Pulsdauer messen". Du musst dich für eines entscheiden. Ich 
würde die Pulsdauer messen, dann ist keine weitere Hardware nötig, und 
in dem Puls selber steckt die gesuchte Information.

von Faros (Gast)


Lesenswert?

Ja, PulseIn misst die Pulsdauer (Hightime), so funktioniert mein Robo 
zwar, allerdings elendslangsam, somit scheidet es aus.

Ich werde heute erstmal die genaue Frequenz vom Pwm feststellen, und 
dann den passenden Tiefpass dranhängen.

Die Werte von den Kondis hab ich so gewählt, dass ich mit den 
entsprechenden Widerständen den genannten Bereich von etwa 5-1000 Hz 
abdecken kann.

von Wolfgang A. (Gast)


Lesenswert?

Faros schrieb:
> Ich werde heute erstmal die genaue Frequenz vom Pwm feststellen, und
> dann den passenden Tiefpass dranhängen.

Du hast noch nicht verstanden, wie bei Modellbau-Servo-Signalen die 
Positionsinformation übertragen wird. Das sind digitale, 
zeitkontinuierliche Impulse. Ein Tiefpass dahinter ist Unfug, weil du 
damit ein Mittelwertsignal von einem Signal erzeugst. Abgesehen davon, 
dass du damit unglaublich langsam wirst, wertest du die damit die 
falsche Information aus. Das Steuersignal wird als Pulsdauer 
übertrageb und nicht als Tastverhältnis.
http://www.electronicsplanet.ch/Roboter/Servo/intern/intern.htm

von Axel S. (a-za-z0-9)


Lesenswert?

Grundlagen, Kinder. Grundlagen!

Eine analoge Modell-Steuerungsanlage sendet ein Telegramm, bestehend aus 
einer etwas längeren Pause und dann so vielen Impulsen, wie die Anlage 
Kanäle hat. Impulslänge 1ms .. 2ms (nominal 1.4ms +/- 0.4ms).
Der Empfänger pfriemelt die Einzelimpulse wieder auseinander und gibt 
sie an seinen Servo-(etc)-Ausgänge. Mit PWM hat das nur sehr wenig zu 
tun. Im Prinzip ist es zwar eine, aber praktisch dann eher doch nicht.

Für die Auswertung mit einem µC würde man nun nicht jeden Serversteuer- 
impuls an einen einzelnen Controllereingang hängen, sondern sich im 
Empfänger den Punkt suchen, wo das komplette Telegramm anliegt. Und das 
an den µC hängen. Dann kann man mit einem einzigen Pin alle Kanäle auf 
einmal auswerten.


XL

von Beobachter (Gast)


Lesenswert?

Axel Schwenke schrieb:
> Für die Auswertung mit einem µC würde man nun nicht jeden Serversteuer-
> impuls an einen einzelnen Controllereingang hängen, sondern sich im
> Empfänger den Punkt suchen, wo das komplette Telegramm anliegt.

Solange es noch am Grundverständnis für Kodierung der Information fehlt, 
ist die direkte Auswertung des Summensignals doch erst recht zum 
Scheitern verurteilt...

von Martin (Gast)


Lesenswert?

> Ja, PulseIn misst die Pulsdauer (Hightime), so funktioniert
> mein Robo zwar, allerdings elendslangsam, somit scheidet es aus.

Ich kenne Arduino zwar nur vom Namen her, kann mir aber wirklich nicht 
vorstellen daß das so sein muß. Ein normaler AVR macht das Auswerten 
eines Fernsteuersignals nebenher ohne daß man es groß an der Rechenlast 
merkt.
Das Thema wurde sicher schon öfters mal gelöst.

Zur analogen Auswertung: wie gesagt, nicht mehr Zeitgemäß, vor 
vielleicht 25 Jahren hab' ich das aber auch so gemacht.
Es gibt da folgende Herausforderungen:
Erstens ist die Periodendauer unbekannt, die Schaltung wird optimal nur 
an einer bestimmten Fernsteuerung gehen. Früher, als das Timing von 
einem Elko mit bestimmt wurde hat das bedeutet daß ein Wechsel der 
Fernsteuerung immer gleich einen neuabgleich der Schaltung bedeutet hat.
Zweitens geben nicht alle Empfänger einen sauberen Pegel aus, es gibt 
z.B. auch welche die statt der Versorgungsspannung generell nur 3.3V 
ausgeben. Nächster Abgleich.
Drittens ist das Tastverhältnis sehr klein und ändert sich kaum.

Wenn ich mich recht erinnere hatte ich das damals so gelöst:
In einer ersten nichtlinearen Stufe war ein RC-Filter bei dem das 
Aufladen über eine Diode und einen zusätzlichen Widerstand schon einmal 
schneller ging als entladen. Damit kann man das Signal etwas zentrieren. 
Der Spannungsripple am Filter-C war so eingestellt daß er im Mittel gut 
2 Diodenspannungen groß war. Die 2. nichtlineare Stufe war relativ 
langsam, der Widerstand aber über 2 antiparallele Dioden gebrückt. Sinn 
und Zweck davon: eine schnelle Änderung kommt wegen der Dioden schnell 
durch und dannach hat man ein relativ ruhiges Signal. Die Fahrtenregler 
nach diesem Eingangsstufenprinzip haben durchaus schnell genug reagiert 
und liefen an einer Fernsteuerung zuverlässig.

Wenn man weiß daß die Periodendauer konstant ist und die Pegel passen, 
dann steckt im Tastverhältnis und im Mittelwert der Spannung die selbe 
Information wie in der Pulslänge. Allen Unkenrufen zum Trotz. Wo sollte 
die Information denn auch hin verschwinden?
Allerdings ist die Pulslänge wie schon vielfach genannt die einzig 
wirklich zuverlässige Informationsquelle.

von Faros (Gast)


Lesenswert?

Vielen Dank für die Erläuterungen ;-)

Ich benutze von der Fernsteuerung ja nur einen Kanal, das Ziel ist ja 
das Signal das normalerweise vom Empfänger an den Servo ausgeschickt 
wird in eine analoge Spannung zu verwandeln, sodass ich diese mit dem 
Arduino einlesen kann (ich brauche einen Wert von 0-1023) und das ist 
doch das "Mittelwertsignal" ?

von Sossil (Gast)


Lesenswert?

Das geht mit einem Tiefpassfilter, so wie Du es vorhast.
Aber es wird sehr ungenau sein. Und Dein Filter muss so groß sein, dass 
alles sehr sehr langsam geht.

Also mach es richtig:
http://www.cheapscience.com/2010/01/reading-servo-pwm-with-an-arduino.html

von hinz (Gast)


Lesenswert?

Faros schrieb:

> Ich benutze von der Fernsteuerung ja nur einen Kanal, das Ziel ist ja
> das Signal das normalerweise vom Empfänger an den Servo ausgeschickt
> wird in eine analoge Spannung zu verwandeln, sodass ich diese mit dem
> Arduino einlesen kann (ich brauche einen Wert von 0-1023) und das ist
> doch das "Mittelwertsignal" ?

Das kommt schon einigermaßen hin, aber der Tiefpass muss eine derart 
lange Zeitkonstante haben dass von Fernsteuern kaum mehr eine Rede ist.

Nimm wie schon mehrfach empfohlen die Pulsbreite über einen Zähler auf.

von Faros (Gast)


Lesenswert?

Vielen Dank für die Hilfe, so werde ich es machen.

von Faros (Gast)


Lesenswert?

Ich komme auf keinen grünen Zweig.
Kann es sein, wenn ich die Pulsdauer mehrmals in einem Code der sich 
alle paar ms wiederholt abfrage, es den Arduino überlastet und sich der 
Roboter deshalb so langsam bewegt ?

von Martin (Gast)


Lesenswert?

> Kann es sein, wenn ich die Pulsdauer mehrmals in einem Code der sich
> alle paar ms wiederholt abfrage, es den Arduino überlastet und sich
> der Roboter deshalb so langsam bewegt ?

Wenn sich Dein Programm immer wieder ausschließlich damit beschäftigt 
auf den nächsten Puls zu warten, dann schon.

Darum irgendwo oben der Hinweis daß man das über Interrupts macht (wobei 
ich dafür einen capture-Eingang bevorzuge)

von Beobachter (Gast)


Lesenswert?

Faros schrieb:
> Kann es sein, wenn ich die Pulsdauer mehrmals in einem Code der sich
> alle paar ms wiederholt abfrage, es den Arduino überlastet und sich der
> Roboter deshalb so langsam bewegt ?

Das kann sein, wenn die Pulsdauermessung ausreichend ungeschickt 
programmiert ist. But who knows ...

von Faros (Gast)


Lesenswert?

Ich habe eine Art Interrupt Timer gefunden, wenn ich mit diesem die 
Pulsdauer des Signals messe, bekomme ich je nach Knüppelstellung Werte 
von 2147 bis 3735, soweit so gut. Wenn ich allerdings diesen Timercode 
in meinen Robotercode einbaue geht er nicht mal in die void setup ().
Wann, also zu welcher Bedingung ist dieses ISR(TIMER1_CAPT_vect) 
abgearbeitet, sodass er in die setup geht ?
Tut mir leid, wenn es für euch total lachhafte Fragen sind, aber ich bin 
noch Anfänger...




•
1
volatile unsigned int Ticks;         // holds the pulse count as .5 us ticks 
2
int icpPin = 8;                       // this interrupt handler must use pin 8
3
4
5
ISR(TIMER1_CAPT_vect){ 
6
   if( bit_is_set(TCCR1B ,ICES1)){       // was rising edge detected ?   
7
       TCNT1 = 0;                        // reset the counter      
8
   }
9
   else {                                // falling edge was detected   
10
        Ticks = ICR1;
11
   }     
12
   TCCR1B ^= _BV(ICES1);                 // toggle bit value to trigger on the other edge    
13
}
14
15
16
void setup()                    // run once, when the sketch starts
17
{
18
  Serial.begin(9600);   
19
  pinMode(icpPin,INPUT);
20
  TCCR1A = 0x00;         // COM1A1=0, COM1A0=0 => Disconnect Pin OC1 from Timer/Counter 1 -- PWM11=0,PWM10=0 => PWM Operation disabled 
21
  TCCR1B = 0x02;         // 16MHz clock with prescaler means TCNT1 increments every .5 uS (cs11 bit set
22
  Ticks = 0;             // default value indicating no pulse detected 
23
  TIMSK1 = _BV(ICIE1);   // enable input capture interrupt for timer 1
24
}
25
26
int getTick() {
27
  int akaTick;       // holds a copy of the tick count so we can return it after re-enabling interrupts 
28
  cli();             //disable interrupts
29
  akaTick = Ticks;
30
  sei();             // enable interrupts
31
  return akaTick;  
32
}
33
34
void loop()                     // run over and over again
35
{
36
  static int prevTick = 0;
37
 
38
  if( getTick()  != prevTick) {
39
     prevTick = getTick(); 
40
     Serial.println( prevTick);     // print the tick value only when it changes  
41
  }
42
   
43
/*
44
static int tick=0; 
45
tick=getTick(); // so würde ich die Hightime vom Signal abfragen (für meinen code) 
46
*/
47
48
49
  
50
}

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Faros schrieb:
> Kann es sein, wenn ich die Pulsdauer mehrmals in einem Code der sich
> alle paar ms wiederholt abfrage, es den Arduino überlastet und sich der
> Roboter deshalb so langsam bewegt ?
Wie sieht denn die Hardware zur Software aus?

Faros schrieb:
> Wenn ich allerdings diesen Timercode in meinen Robotercode einbaue geht
> er nicht mal in die void setup ().
Und wie sieht DEIN Code aus? Rufst du die Funktion setup() überhaupt 
auf? Oder meinst du, das geht vom bloßen Drandenken?

Dir ist schon klar, das das hier ein blindes Herumgegurke ist? Woher 
hast du diesen geposteten Code? Passt der überhaupt zum Arduino?

: Bearbeitet durch Moderator
von Faros (Gast)


Lesenswert?

Benutzt wird ein Arduino Uno R3. Habe mit dem obig geposteten Code (vom 
Arduino Froum) ja schon das Signal gemessen.
Mein Code ist noch nicht fertig (kommen noch ein paar Sachen dazu), ist 
noch sehr provisorisch geschrieben.
Gesteuert werden die 4 Beine (4 Servos) eines vierbeinigen Roboters.

•
1
#include <Servo.h>
2
 
3
Servo servo1, servo2, servo3, servo4,  servolenkung;
4
int sensorvalue=0, pos1, pos2, pos3, pos4, val, pos, pin=7;
5
float delaytime;
6
volatile unsigned int Ticks;         // holds the pulse count as .5 us ticks 
7
int icpPin = 8;                       // this interrupt handler must use pin 8
8
9
10
ISR(TIMER1_CAPT_vect){ 
11
   if( bit_is_set(TCCR1B ,ICES1)){       // was rising edge detected ?   
12
       TCNT1 = 0;                        // reset the counter      
13
   }
14
   else {                                // falling edge was detected   
15
        Ticks = ICR1;
16
   }     
17
   TCCR1B ^= _BV(ICES1);                 // toggle bit value to trigger on the other edge    
18
}
19
20
21
 
22
void setup()
23
{
24
 pinMode(icpPin,INPUT);
25
  TCCR1A = 0x00;         // COM1A1=0, COM1A0=0 => Disconnect Pin OC1 from Timer/Counter 1 -- PWM11=0,PWM10=0 => PWM Operation disabled 
26
  TCCR1B = 0x02;         // 16MHz clock with prescaler means TCNT1 increments every .5 uS (cs11 bit set
27
  Ticks = 0;             // default value indicating no pulse detected 
28
  TIMSK1 = _BV(ICIE1);   // enable input capture interrupt for timer 1
29
 
30
 
31
 
32
 
33
  servo1.attach(9); // 4 beine
34
  servo2.attach(10);
35
  servo3.attach(5);
36
  servo4.attach(6);
37
  servolenkung.attach(3);
38
  pinMode(pin, INPUT);
39
  
40
  
41
   
42
  
43
  
44
  
45
46
  
47
  
48
  for(pos = 180; pos >= 0; pos--) // servos gehen in die anfangsposition
49
    {
50
      servo1.write(pos);
51
      
52
      delay(10);
53
    }
54
     servo1.write(65); 
55
     
56
     for(pos = 180; pos >= 0; pos--)
57
    {
58
      servo3.write(pos);
59
      
60
      delay(10);
61
    }
62
     servo3.write(65); 
63
     
64
     
65
     for(pos = 180; pos >= 0; pos--)
66
    {
67
      servo2.write(pos);
68
      
69
      delay(10);
70
    }
71
     servo2.write(65); 
72
     
73
     
74
     for(pos = 180; pos >= 0; pos--)
75
    {
76
      servo4.write(pos);
77
      
78
      delay(10);
79
    }
80
     servo4.write(65); 
81
    
82
    
83
    
84
    
85
    
86
     delay (500);
87
}
88
89
int getTick() {
90
  int akaTick;       // holds a copy of the tick count so we can return it after re-enabling interrupts 
91
  cli();             //disable interrupts
92
  akaTick = Ticks;
93
  sei();             // enable interrupts
94
  return akaTick;  
95
}
96
 
97
void loop() 
98
{
99
 
100
   
101
  
102
   
103
   for(pos1=65, pos3=65, pos2=65, pos4=65; pos1 <=105, pos2<=25, pos3 >=25, pos4 >=25; pos1++, pos3--, pos2++, pos4--) //vorwaertsbewegung   {
104
     sensorvalue=getTick();
105
      
106
      while (sensorvalue<2180)
107
      { delay (10);
108
       sensorvalue=getTick();
109
      }
110
      
111
      
112
      
113
      servo1.write(pos1);
114
      servo2.write(pos2);
115
      servo3.write(pos3);
116
      servo4.write(pos4);
117
      
118
      
119
      
120
      delaytime=sensorvalue/1000;
121
      if (delaytime<1.5)
122
      {delaytime=1.5;}
123
      
124
      val = analogRead(A1);  //Lenkung          
125
      val = map(val, 0, 1023, 0, 179);     
126
      servolenkung.write(val);
127
      
128
      
129
      
130
      delay(delaytime);
131
    }
132
    
133
    for(pos1=105, pos3=25, pos4=25, pos2=105; pos1 >=25, pos3<=105, pos4<=105, pos2 >=25; pos1--, pos3++, pos4++, pos2--) //rueckwaertsbewegung
134
   {
135
     sensorvalue=getTick();
136
      while (sensorvalue<2180)
137
      { delay (10);
138
        
139
        sensorvalue=getTick();
140
      }
141
      
142
      
143
      
144
      
145
 
146
      servo1.write(pos1);
147
      servo2.write(pos2);
148
      servo3.write(pos3);
149
      servo4.write(pos4);
150
     
151
      delaytime=sensorvalue/1000;
152
      if (delaytime<1.5)
153
      {delaytime=1.5;}
154
      
155
      val = analogRead(A1);            
156
      val = map(val, 0, 1023, 0, 179);     
157
      servolenkung.write(val);
158
      delay(delaytime);
159
    }
160
    
161
    
162
163
164
}

von Faros (Gast)


Lesenswert?

Tut mir leid für den Doppelpost und für die Länge des Codes, habe nicht 
erwartet das er so lang wird.
Mittlerweile habe ich einen ersten Fehler entdeckt, einmal PinMode 
zuviel..
Das war noch vom vorigen Versuch mit einem Timer, der allerdings nur auf 
dem Due funktioniert.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.