- Registriert
- 22.07.2007
- Beiträge
- 72
Bei meinem Bruder Claas Xerion 5000 möchte ich über die Fernbedienung einige unterschiedliche Lenkprogramme (Standard-, Allrad- und Hundeganglenkung) auswählen können. Das ganze sollte über einen Arduino im Modell realisiert werden, damit ich bei einem eventuellen Wechsel der Fernsteuerung nicht auf die Mischprogramme der Fernsteuerung angewiesen bin.
Hier mal ein kleines (ausbaufähiges) Programm für einen Arduino.
Leider erlaubt mir die Foren-Software keine genauen Referenz-Links zu den Sketch-Vorlagen, daher habe ich hier im Sketch-Text die allgemeinen Links verlinkt.
Über Tipps, Kritiken usw. würde ich mich sehr freuen.
Hier mal ein kleines (ausbaufähiges) Programm für einen Arduino.
Code:
/* Programm zur Ansteuerung von mehreren Lenkungsarten für einen Claas Xerion 5000 - Version 1 - April 2019
*
* - Programm verwendet die beiden Interrupts zur Signalabfrage anstelle der Funktion pulseIn
* - Kanal 1 der Fernsteuerung dient zur Lenkung
* - Kanal 3 der Fernsteuerung dient zum Einstellen von eines der drei Lenkprogramme (hoch- bzw- runterschalten mittels Senderhebel Kanal 3, ggf. Kanal 3 an
* an der Fernsteuerung invertieren)
*
* - Lenkprogrammarten:
* 1 - normale Lenkung
* 2 - Allrad-Lenkung, vordere und hintere Lenkachse werden entgegengesetzt angelenkt
* 3 - Hundegang, vordere und hintere Lenkachse werden angelenkt
* - interne LED dient zur Anzeiger des gewählten Lenkprogrammes (dauerhaftes Leuchten = Lenkprogramm 1, Blinken der Led im 250ms-Takt = Lenkprogramm 2,
* Blinken der Led im 750ms-Takt = Lenkprogramm 2
*
* Vorlagen:
* - Grundgerüst der Lenkarten : [URL="https://www.rockcrawler.de/thread/22643-mehrachser-lenkung-von-2-achsen-%C3%BCber-einen-fernsteuerkanal/"][COLOR="#0000FF"]dqb312[/COLOR][/URL] - [url]https://www.rockcrawler.de/thread/22643-mehrachser-lenkung-von-2-achsen-%C3%BCber-einen-fernsteuerkanal/[/url]
* - Modul Neutralstellung : [URL="https://www.rockcrawler.de/thread/39320-programme-und-tips-zu-arduino/?postID=1092340#post1092340"][COLOR="#0000FF"]Joerg1972[/COLOR][/URL] - [url]https://www.rockcrawler.de/thread/39320-programme-und-tips-zu-arduino/[/url]
* - Modul Interruptabfrage : [URL="https://www.modelltruck.net/showthread.php?55990-Auslesen-von-Servosignalen-per-Interrupt&p=688628&viewfull=1#post688628"][COLOR="#0000FF"]gismow[/COLOR][/URL] - [url]https://www.modelltruck.net/showthread.php?55990-Auslesen-von-Servosignalen-per-Interrupt[/url]
* - Modul Blinken : [URL="https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay"][COLOR="#0000FF"]Arduino[/COLOR][/URL] - Beispielsketch Arduino IDE - Kapitel 2 Digitial - BlinkWithoutDelay
*
*
* Den Code kann und darf jeder für sich ändern, solange es eine private Nutzung ist. Der Code wurde nur zum Einsatz in privaten Modellfahrzeugen erstellt.
* Jede andere Nutzung ist widerrechtlich. Gewerbliche Nutzung des Codes ist untersagt und wird rechtlich verfolgt.
* Eine gewerbliche Nutzung ist nur gegen Lizenzgebühr möglich. Es wird keine Haftung für Folgeschäden welche sich aus der Nutzung des Codes ergeben könnten übernommen.
* Der Einsatz erfolgt auf eigene Gefahr und eigenes Risiko.
* Mit der Nutzung diese Codes erklärt sich der Nutzer hiermit einverstanden.
*
* Im Moment bekannte Fehlfunktionen:
* - manchmal kann nach einer gewissen Zeit nicht mehr in das Lenkprogramm 1 geschaltet werden, Anwahl Lenkprogramm 2 und 3 geht ohne Probleme
* - manchmal unruhige Lenkservos (Zittern) wenn der Lenkungsauschlag den rechten Endbereich erreicht
*/
// #include <Servo.h> //Library für Servoausgabe einbinden
#include <MobaTools.h> //Library für Servoausgabe einbinden
#define debug // bedingte Compilierung
// Variablen fuer die Lenkung
volatile uint16_t Empfaenger_Kanal1_Wert[8] = {1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500}; // Die letzten 8 Werte werden gespeichert um einen Mittelwert zu bilden
volatile uint16_t Empfaenger_Kanal1_Wert_Summe = 12000; // Die Summe der letzten 4 Werte
volatile uint8_t Empfaenger_Kanal1_Wert_Index = 0; // Der Index des naechsten auszutauschenden Wwets
// Variablen fuer die Schaltung
volatile uint16_t Empfaenger_Kanal3_Wert[8] = {1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500}; // Die letzten 8 Werte werden gespeichert um einen Mittelwert zu bilden
volatile uint16_t Empfaenger_Kanal3_Wert_Summe = 12000; // Die Summe der letzten 8 Werte
volatile uint8_t Empfaenger_Kanal3_Wert_Index = 0; // Der Index des naechsten auszutauschenden Wwets
volatile uint32_t LetzteLenkungAenderung = micros(); // Letzter Zeitpunkt des Signalwechsels Lenkung
volatile uint32_t LetzteSchalterAenderung = micros(); // Letzter Zeitpunkt des Signalwechsels Schalter
volatile uint16_t AktuellerEmpfaengerWertLenkung = 1500; // Der aktuell als letztes ermittelte Wert
volatile uint16_t AktuellerEmpfaengerWertSchaltung = 1500; // Der aktuell als letztes ermittelte Wert
byte Lenkprogramm = 1; // Wert Lenkprogramm
int WertInSchalter; // Wert des Eingangssignal Schaltung
int wertin; //Wert des Eingangssignale Lenkung
int wertaus1 = 90; //Wert des Ausgangssignales Achse 1 (auf Mitte stellen)
int wertaus2 = 90; //Wert des Ausgangssignales Achse 2 (auf Mitte stellen)
int mixer = 75; //Mixer in % von Servo 1 auf Servo 2
int mitte1 = 0; //Mittelstellung Servo 1 anpassen
int mitte2 = 0; //Mittelstellung Servo 2 anpassen
const unsigned long neutral = 1500; // neutral pulse lenght in µS
const unsigned long deadzone = 125; // pulse lenght difference in µS between neutral and point to switch on
const unsigned long hysteresis = 50; // pulse lenght hysteresis (between on and off)
boolean antitoggle = true; // flag to prevent from auto toggling
Servo8 s1, s2; //Servoobjekte definieren
// constants won't change. Used here to set a pin number:
const int ledPin = LED_BUILTIN;// the number of the LED pin
// Variables will change:
int ledState = LOW; // ledState used to set the LED
// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0; // will store last time LED was updated
long interval = 1000; // interval at which to blink (milliseconds)
void setup()
{
#ifdef debug
Serial.begin( 57600 ); // Serielle Datenübertragung zur Kontrolle aktivieren
#endif
attachInterrupt(digitalPinToInterrupt(2), InterruptLenkung, CHANGE); // Interrupt 1 für Empfängersignal Lenkung (Kanal 1) einschalten
attachInterrupt(digitalPinToInterrupt(3), InterruptSchalter, CHANGE); // Interrupt 2 für Empfängersignal Schalter (Kanal 3) einschalten
s1.attach(7); // Pin für Servo 1 definieren
s2.attach(8); // Pin für Servo 2 definieren
pinMode(ledPin, OUTPUT); // Pin 13 als LED-Ausgang definieren
}
void InterruptLenkung()
{
uint32_t nMicros = micros(); // Aktuellen Zeitstempel merken
uint16_t nDifference = (uint16_t)(nMicros - LetzteLenkungAenderung); // Die Differenz zum letzten Aufruf errechnen
LetzteLenkungAenderung = nMicros; // Zeitstempel fuer das naechste mal merken
if ( (nDifference > 900) && ( nDifference < 2100)) // Zeiten zwischen 900 und 2100 Mikrosekunden sind das HIGH Signal
{
// Wert in der 8er Liste austauschen und Mittelwert errechnen. Dies erfolgt indem der alte Wert von der Summe subtrahiert wird
Empfaenger_Kanal1_Wert_Summe -= Empfaenger_Kanal1_Wert[Empfaenger_Kanal1_Wert_Index];
// Der neue Wert gemerkt wird
Empfaenger_Kanal1_Wert[Empfaenger_Kanal1_Wert_Index] = nDifference;
// Den neuen Wert auf die Summe addieren
Empfaenger_Kanal1_Wert_Summe += nDifference;
// Den Index auf die naechste Position schieben
Empfaenger_Kanal1_Wert_Index = ( ( Empfaenger_Kanal1_Wert_Index + 1 ) & 0x07 ); // Index erhoehen und ggf. von 8 auf 0 springen
// Den aktuellen Mittelwert errechnen indem die Summe durch 8 geteilt wird
AktuellerEmpfaengerWertLenkung = ( Empfaenger_Kanal1_Wert_Summe >> 3 ); // durch 8 teilen
}
}
void InterruptSchalter()
{
uint32_t nMicros = micros(); // Aktuellen Zeitstempel merken
uint16_t nDifference = (uint16_t)(nMicros - LetzteLenkungAenderung); // Die Differenz zum letzten Aufruf errechnen
LetzteLenkungAenderung = nMicros; // Zeitstempel fuer das naechste mal merken
if ( (nDifference > 900) && ( nDifference < 2100)) // Zeiten zwischen 900 und 2100 Mikrosekunden sind das HIGH Signal
{
// Wert in der 8er Liste austauschen und Mittelwert errechnen. Dies erfolgt indem der alte Wert von der Summe subtrahiert wird
Empfaenger_Kanal3_Wert_Summe -= Empfaenger_Kanal3_Wert[Empfaenger_Kanal3_Wert_Index];
// Der neue Wert gemerkt wird
Empfaenger_Kanal3_Wert[Empfaenger_Kanal3_Wert_Index] = nDifference;
// Den neuen Wert auf die Summe addieren
Empfaenger_Kanal3_Wert_Summe += nDifference;
// Den Index auf die naechste Position schieben
Empfaenger_Kanal3_Wert_Index = ( ( Empfaenger_Kanal3_Wert_Index + 1 ) & 0x07 ); // Index erhoehen und ggf. von 8 auf 0 springen
// Den aktuellen Mittelwert errechnen indem die Summe durch 8 geteilt wird
AktuellerEmpfaengerWertSchaltung = ( Empfaenger_Kanal3_Wert_Summe >> 3 ); // durch 8 teilen
}
}
void blinken()
{
// here is where you'd put code that needs to be running all the time.
// check to see if it's time to blink the LED; that is, if the difference
// between the current time and last time you blinked the LED is bigger than
// the interval at which you want to blink the LED.
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}
void loop()
{
// Hier kann nun mit dem Wert von AktuellerEmpfaengerWertSchaltung gearbeitet werden
if ( AktuellerEmpfaengerWertSchaltung > neutral + deadzone && antitoggle == true)
{
antitoggle = false;
if (Lenkprogramm < 3)
{
Lenkprogramm = Lenkprogramm + 1;
}
}
if ( AktuellerEmpfaengerWertSchaltung < neutral - deadzone && antitoggle == true)
{
antitoggle = false;
if (Lenkprogramm > 0)
{
Lenkprogramm = Lenkprogramm - 1;
}
}
if ( abs (AktuellerEmpfaengerWertSchaltung - neutral) < deadzone - hysteresis )
{
antitoggle = true; // set anti autotoggle flag
}
/* Im Versuchsaufbau gab es beim Eingangssignal der Lenkung im Bereich der Mittelstellung kleine Schwankungen, welche zu einem Zittern führten.
* Kleine Filterfunktion zum Glätten des Signals
*/
if (( ( AktuellerEmpfaengerWertLenkung >= ( 1500 - 150 ) ) && ( AktuellerEmpfaengerWertLenkung <= ( 1500 + 150 ) ) ))
{
AktuellerEmpfaengerWertLenkung = 1500;
}
/* Ab hier werden die einzelnen Lenkprogramme beschrieben
*
*/
if (Lenkprogramm == 1) // Standard-Lenkung
{
digitalWrite(LED_BUILTIN, HIGH);
wertin = AktuellerEmpfaengerWertLenkung;
wertaus1 = map(wertin, 1060, 1950, 0, 180); //Winkelwert erzeugen (die ersten beiden Werte aus min / max bei Serial.print(wertin) nutzen)
wertaus1 = wertaus1 + mitte1; //Mittelstellung Servo2 korregieren
wertaus1 = constrain(wertaus1, 0, 180); //Ausgabewert für Servo1 begrenzen als Schutz
wertaus2 = wertaus1 - 90;
wertaus2 = wertaus2 * mixer / 100; //Mixer für Servo2 einrechnen
wertaus2 = wertaus2 + 90;
wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
wertaus2 = constrain(wertaus2, 0, 180); //Ausgabewert für Servo2 begrenzen als Schutz
}
if (Lenkprogramm == 2) // Allrad-Lenkung
{
interval = 250; // Intervall der internen LED auf 750ms setzen
blinken(); // Aufruf der Funktion "blinken"
wertin = AktuellerEmpfaengerWertLenkung;
wertaus1 = map(wertin, 1060, 1950, 0, 180); //Winkelwert erzeugen
wertaus1 = wertaus1 + mitte1; //Mittelstellung Servo2 korregieren
wertaus1 = constrain(wertaus1, 0, 180); //Ausgabewert für Servo1 begrenzen als Schutz
wertaus2 = 180 - wertaus1;
wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
wertaus2 = constrain(wertaus2, 0, 180); //Ausgabewert für Servo2 begrenzen als Schutz
}
if (Lenkprogramm == 3) // Hundegang
{
interval = 750; // Intervall der internen LED auf 750ms setzen
blinken(); // Aufruf der Funktion "blinken"
wertin = AktuellerEmpfaengerWertLenkung;
wertaus1 = map(wertin, 1060, 1950, 0, 180); //Winkelwert erzeugen (die ersten beiden Werte aus min / max bei Serial.print(wertin) nutzen)
wertaus1 = wertaus1 + mitte1; //Mittelstellung Servo2 korregieren
wertaus1 = constrain(wertaus1, 0, 180); //Ausgabewert für Servo1 begrenzen als Schutz
wertaus2 = wertaus1;
wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
wertaus2 = constrain(wertaus2, 0, 180); //Ausgabewert für Servo2 begrenzen als Schutz
}
#ifdef debug
Serial.println(wertin); //Eingangswert anzeigen über Serial Monitor
Serial.println(" ");
Serial.println(Lenkprogramm); //Anzeige gewähltes Lenkprogramm über Serial Monitor
Serial.println(" ");
Serial.println(AktuellerEmpfaengerWertSchaltung); //Anzeige gewähltes Lenkprogramm über Serial Monitor
Serial.println(" ");
#endif
s1.write(wertaus1); //Servo 1 stellen
s2.write(wertaus2); //Servo 2 stellen
delay(20);
}
Leider erlaubt mir die Foren-Software keine genauen Referenz-Links zu den Sketch-Vorlagen, daher habe ich hier im Sketch-Text die allgemeinen Links verlinkt.
Über Tipps, Kritiken usw. würde ich mich sehr freuen.