Inhaltsverzeichnis
Kreuzmischer
Author: Dipl.-Ing. Wilfried Klaas
Board: Arduino Duemilanove
Was ist ein Kreuzmischer?
Ein Kreuzmischer mischt 2 Servosignale, also die Ruderausschläge, zweier Kanäle auf 2 Ausgangskanäle so zusammen, dass der eine Kanal beide Ausgangskanäle proportional steuert, während der 2 Kanal die beiden Ausgangskanäle gegengesetzt steuert. Beispiele für den Einsatz: Kettenfahrzeug mit 2 getrennten Kettenantrieben, Flugzeug mit einem V-Leitwerk, Boot mit 2 Schrauben zur Ruderunterstützung… Damit lässt sich über einen Kreuzküppel der Fernsteuerung das Gefährt einfach handhaben.
Und wie funktioniert das?
Beim Kreuzmischen kann man einfach für den 1. Ausgangskanal die beiden Eingangskanäle addieren, während man für den 2. Kanal den Steuerkanal abzieht. Also z.B. so:
A1 = ESC + STE; A2 = ESC - STE;
Nun sieht man hier ganz leicht, das wir das so einfach nicht machen können. Sagen wir mal, unsere Eingangs- und Ausgangssignale sind im Bereich -128 bis 128. Fahren wir nun voll Kraft voraus, dann hat Kanal A1 einen Wert von 128 und und Kanal A2 ebenfalls einen Wert von 128. Wenn wir jetzt etwas Seitenruder geben, sagen wir mal mit -60 dazu. Dann wird aus A1 = 128 + -60 = 68. OK und A2 = 128 - -60 = 128 + 60 = 188;
Upps, den Wert können wir jetzt nicht mehr darstellen. Denn wir können ja nur bs 128 steuern.
Um das zu umgehen, gibt es, je nach Einsatzzweck verschiedene Möglichkeiten:
* Wir lassen alles so wie beschrieben und ignorieren Werte > 128. Dann wäre im o. Fall A1 = 68 und A2= 128.
* Oder wir halbieren immer jeden Servoweg. Dann wäre A1 = 64 + -30 = 34 und A2= 64 - -30= 94.
Dazwischen sind natürlich noch viele andere Möglichkeiten drin.
Programm
Zuerst lesen wir die beiden Empfängerkanäle ein, dann wird gerechnet und zwar je nach Einstellung entweder nach Methode 1 oder 2. Was wir hier (wie bei meinen RC Projekten fast immer) machen, wir bestimmen beim Starten zunächst die Nullpunkte des Empfängers. Dann werden alle Werte durch einen Puffer geschleift. Der enthält 10 Werte und wenn man einen Wert abfragt, wird automatisch der Mittelwert über diese Werte gebildet. (Größter und kleinster fliegen dabei raus.) Dadurch ist man vor kruzen Empfangsstörungen sicher, aber das System reagiert nicht ganzt so schnell. Das kann evt. für Flugzeuge und Hubschrauber nicht gut sein. Da sollte man sich eine andere Strategie einfallen lassen, oder aber einfach den Puffer verkleinern. z.B. auf 4.
UPDATE: 18.10.2012: Ich habe auch diesen Kreuzmischer auf meine RCReceiver Bibliothek umgebaut. Und ich habe den Servoreverse pro Kanal eingebaut. Dazu werden 2 weitere Pins abgefragt.
UPDATE: 18.11.2013: Ich habe beide Programme auf den aktuellen Stand der RCReceiver Bibliothek umgebaut.
- Kreuzmischer.ino
#include <debug.h> #include <makros.h> #include <RCReceive.h> #include <Servo.h> /* Kreuzmischer. Kanal 1 ist Geschwindigkeit, Kanal 2 ist Steuerung. Der Empfänger wird vom Pin 2 und 3 gelesen, */ // Hardwareanbindung für Arduino Hardware // Empfängerkanäle const byte PIN_RC_THR = 2; // das ist INT 0 aber Pin 2!!!! const byte PIN_RC_STE = 3; // das ist INT 1 aber Pin 3!!!! // Modus Soft oder Hard const byte PIN_MODE = 4; const byte PIN_REVERS_1 = 7; const byte PIN_REVERS_2 = 8; // Ausgänge const byte SERVO_1 = 9; // PWM Kanal const byte SERVO_2 = 10; // PWM Kanal const byte LED = 13; // LED auf dem Board RCReceive escReceiver; RCReceive servoReceiver; Servo a1, a2; void setup() { // Kanäle auf Ausgang, und dann deaktivieren pinMode(SERVO_1, OUTPUT); pinMode(SERVO_2, OUTPUT); pinMode(LED, OUTPUT); digitalWrite(LED, LOW); // Eingang für RC pinMode(PIN_RC_THR, INPUT_PULLUP); pinMode(PIN_RC_STE, INPUT_PULLUP); escReceiver.attach(PIN_RC_THR); servoReceiver.attach(PIN_RC_STE); // Eingang Modus pinMode(PIN_MODE, INPUT_PULLUP); pinMode(PIN_REVERS_1, INPUT_PULLUP); pinMode(PIN_REVERS_2, INPUT_PULLUP); // Servos definieren a1.attach(SERVO_1); a2.attach(SERVO_2); a1.write(90); a2.write(90); #ifndef __AVR_ATtinyX4__ #ifdef debug Serial.begin(57600); Serial.flush(); Serial.println("RC V-mixer"); delay(100); #endif #endif } void loop() { // Aktuellen RC-Wert Gas lesen escReceiver.poll(); // und gleich auch für's Steuerservo servoReceiver.poll(); dbgOut("E:"); dbgOut(escReceiver.getLastRCValue()); dbgOut(",S:"); dbgOutLn(servoReceiver.getLastRCValue()); if (escReceiver.hasError() || servoReceiver.hasError()) { a1.write(90); a2.write(90); } else if (escReceiver.hasNP() && servoReceiver.hasNP()) { doWork(); } #ifdef debug // delay(100); #endif } /* Modus Soft berechnung, Werte werden jeweils halbiert und dann addiert. */ void doWork() { // Werte holen int escValue = escReceiver.getValue(); int servoValue = servoReceiver.getValue(); dbgOut("E:"); dbgOut(escValue); dbgOut(",S:"); dbgOutLn(servoValue); // Nullpunkte festlegen escValue = escValue - escReceiver.getNP(); servoValue = servoValue - servoReceiver.getNP(); // Hier wird zwischen hard und soft unterschieden. if (digitalRead(PIN_MODE) == 0) { // jetzt Wertebereich verkleinern escValue = escValue / 2; servoValue = servoValue / 2; } // die eigentliche Berechnung int servo1 = escValue + servoValue; int servo2 = escValue - servoValue; // Und damit das nicht aus dem Ruder läuft, etwas begrenzen servo1 = constrain(servo1, -128, 128); servo2 = constrain(servo2, -128, 128); if (digitalRead(PIN_REVERS_1) == 0) { // Servokanal 1 umkehren servo1 = servo1 * -1; } if (digitalRead(PIN_REVERS_2) == 0) { // Servokanal 1 umkehren servo2 = servo2 * -1; } // Nullpunkte wieder hinzu servo1 = servo1 + 128; servo2 = servo2 + 128; // Auf den Servo umsetzen servo1 = map(servo1,0, 255,0,180); servo2 = map(servo2,0, 255,0,180); // und einstellen a1.write(servo1); a2.write(servo2); }
Programm mit Interrupt
Vielleicht ist euch aufgefallen, daß gerade beim Kreuzmischer die Servos arg zittern. Das liegt weder am Arduino noch an der Programmierung, naja, vielleicht doch, aber nicht so offentsichtlich. Denn wie wir bereits bei der RC Bibliothek gesehen haben, stören sich die Servo Bibliothek und der pulseIn()
gegenseitig. Linderung, wenn auch keine Abhilfe, schafft da, das ganze Auswerten des Empfängers ebenfalls mit Intterupts zu machen. Hier das entsprechende Programm.
- Kreuzmischer_int.ino
#include <debug.h> #include <makros.h> #include <RCReceive.h> #include <Servo.h> /* Kreuzmischer. Kanal 1 ist Geschwindigkeit, Kanal 2 ist Steuerung. Der Empfänger wird vom Pin 2 und 3 gelesen, */ // Hardwareanbindung für Arduino Hardware // Empfängerkanäle const byte PIN_RC_THR = 2; // das ist INT 0 aber Pin 2!!!! const byte PIN_RC_STE = 3; // das ist INT 1 aber Pin 3!!!! // Modus Soft oder Hard const byte PIN_MODE = 4; const byte PIN_REVERS_1 = 7; const byte PIN_REVERS_2 = 8; // Ausgänge const byte SERVO_1 = 9; // PWM Kanal const byte SERVO_2 = 10; // PWM Kanal const byte LED = 13; // LED auf dem Board RCReceive escReceiver; RCReceive servoReceiver; Servo a1, a2; void setup() { // Kanäle auf Ausgang, und dann deaktivieren pinMode(SERVO_1, OUTPUT); pinMode(SERVO_2, OUTPUT); pinMode(LED, OUTPUT); digitalWrite(LED, LOW); // Eingang für RC pinMode(PIN_RC_THR, INPUT_PULLUP); pinMode(PIN_RC_STE, INPUT_PULLUP); escReceiver.attachInt(PIN_RC_THR); servoReceiver.attachInt(PIN_RC_STE); // Eingang Modus pinMode(PIN_MODE, INPUT_PULLUP); pinMode(PIN_REVERS_1, INPUT_PULLUP); pinMode(PIN_REVERS_2, INPUT_PULLUP); // Servos definieren a1.attach(SERVO_1); a2.attach(SERVO_2); a1.write(90); a2.write(90); #ifndef __AVR_ATtinyX4__ #ifdef debug Serial.begin(57600); Serial.flush(); Serial.println("RC V-mixer"); delay(100); #endif #endif } void loop() { dbgOut("E:"); dbgOut(escReciver.getLastRCValue()); dbgOut(",S:"); dbgOutLn(servoReciver.getLastRCValue()); if (escReceiver.hasError() || servoReceiver.hasError()) { a1.write(90); a2.write(90); } else if (escReceiver.hasNP() && servoReceiver.hasNP()) { doWork(); } else { int value = escReceiver.getValue(); dbgOut("E:"); dbgOut(value); value = servoReceiver.getValue(); dbgOut("S:"); dbgOut(value); dbgOutLn(", no NP"); } #ifdef debug delay(100); #endif } /* Modus Soft berechnung, Werte werden jeweils halbiert und dann addiert. */ void doWork() { // Werte holen int escValue = escReceiver.getValue(); int servoValue = servoReceiver.getValue(); dbgOut("E:"); dbgOut(escValue); dbgOut(",S:"); dbgOutLn(servoValue); // Nullpunkte festlegen escValue = escValue - escReceiver.getNP(); servoValue = servoValue - servoReceiver.getNP(); // Hier wird zwischen hard und soft unterschieden. if (digitalRead(PIN_MODE) == 0) { // jetzt Wertebereich verkleinern escValue = escValue / 2; servoValue = servoValue / 2; } // die eigentliche Berechnung int servo1 = escValue + servoValue; int servo2 = escValue - servoValue; // Und damit das nicht aus dem Ruder läuft, etwas begrenzen servo1 = constrain(servo1, -128, 128); servo2 = constrain(servo2, -128, 128); if (digitalRead(PIN_REVERS_1) == 0) { // Servokanal 1 umkehren servo1 = servo1 * -1; } if (digitalRead(PIN_REVERS_2) == 0) { // Servokanal 1 umkehren servo2 = servo2 * -1; } // Nullpunkte wieder hinzu servo1 = servo1 + 128; servo2 = servo2 + 128; // Auf den Servo umsetzen servo1 = map(servo1,0, 255,0,180); servo2 = map(servo2,0, 255,0,180); // und einstellen a1.write(servo1); a2.write(servo2); }
Diskussion
Ich habe mir das Franzis Paket gekauft und wollte den Kreuzmischer für mein Panzermodell realisieren. Dazu habe ich das obige Programm in die Arduino IDE kopiert und mir die RCReicer lib heruntergeladen und diese in das Library Dir c:\Users\KLA\Documents\Arduino\ in dieses verzeichnis kopiert. Leider bekomme ich immer diese Fehlermeldung:
Arduino: 1.6.2 (Windows 7), Platine: "Arduino Uno"
kreuzmischer.ino:5:24: fatal error: makros.h: No such file or directory
compilation terminated.
c:\Users\KLA\Documents\Arduino\kreuzmischer\ in diese Dir steht die *.ino Datei und hier
c:\Users\KLA\Documents\Arduino\libraries\RCReceiver\ befindet sich die RCReceiver lib
Wohin muss die Lib kopiert werden oder was muss ich tun, damit die IDE sie findet,
Danke schonmal im Vorraus und frohe Ostern natürlich
Gruss
Klaus
Wie oben bei ardufan habe ich das Problem bei allen Programmen die das Library RCReceive.h benötigen. Ich habe mir das neueste Library eingebunden, im Programm die Schreibweise kontrolliert aber ich become beim Überprüfen immer die Fehlermeldung: "error: 'RCRecive' does not name a type". Ich bin mit meinem Latein am Ende, bitte helft mir.
Danke Jörg
bei funktioniert dein Kreuzmischer irgendwie nicht. Da noch ziemlicher Anfänger bin, weiß ich aber nicht, woran genau es liegt. Es kommt eine ganze Reihe Fehlermeldungen, die meiner Meinung hauptsächlich auf die, auch in der RC Reciver library, fehlende Datei RCRecive.h, zurückzuführen sind (es wird dafür aber die Datei EEPROMStruct.h gelistet). Wenn ich bei anderen deiner Projekte den Aufruf im Programm in RCReceive.h umbenenne, wird das Programm kompiliert und geuploadet, funktioniert dann aber trotzdem nicht. Der Servo / ESC wird nicht angesteuert (lediglich die LED auf PIN13 blinkt). Ich verwende übrigens das Arduino ProMini mit 16 Mhz, 328 Prozessor und 5V. Die Fehlermeldungen lauten:
Kreuzmischer:26: error: 'RCRecive' does not name a type
Kreuzmischer:27: error: 'RCRecive' does not name a type
Kreuzmischer.ino: In function 'void setup()':
Kreuzmischer:43: error: 'escReciver' was not declared in this scope
Kreuzmischer:44: error: 'servoReciver' was not declared in this scope
Kreuzmischer.ino: In function 'void loop()':
Kreuzmischer:67: error: 'escReciver' was not declared in this scope
Kreuzmischer:70: error: 'servoReciver' was not declared in this scope
Kreuzmischer.ino: In function 'void doWork()':
Kreuzmischer:89: error: 'escReciver' was not declared in this scope
Kreuzmischer:91: error: 'servoReciver' was not declared in this scope
Vielleicht fehlt auch einfach die entsprechende Datei in der Library-Version, die ich installiert habe.
Ich hoffe du kannst mir helfen,
mfG