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
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.
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.
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
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.
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.
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
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
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...
> 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.
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" ?
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
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.
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 ?
> 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)
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 ...
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 | }
|
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
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 | }
|
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.