• Die Forumsregeln und Nutzungsbedingungen findet ihr in der Navbar unter Impressum !
    Bitte unbedingt beachten!
    Wie überall im Leben gibt es Spielregeln, so auch hier!
    Die Datenschutzerklärung zum DSGVO findet ihr ebenfalls in der Navbar unter Datenschutzerklärung !
    Hinweis nach DSGVO :
    Es ist hier keinerlei Angabe erforderlich. Alle Angaben in diesem Bereich sind öffentlich sichtbar und werden freiwillig gemacht. Mit einem Eintrag in diesem Bereich erkenne ich dieses an, und bestätige die Datenschutzerklärung zur DSGVO für das Forum gelesen zu haben.

    Danke
  • Hallo Gast, beschränke dich hier bitte auf den Bereich der Elektronik. Die Fahrzeuge oder Gebäude, wo diese Elektronik eingebaut wird bitte in dem passenden Fachbereiich behandeln. Auch wenn Teile des Projektes dadurch im Forum doppelt vorhanden sind! Danke.

Arduino Gestaltung einer Allrad-Lenkung mittels Arduino

Rasenmäher

Unterstützt neuen Softwarekauf 2023
VIP Unterstützt modelltruck.net 2024
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.

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.
 
Bei meinem Bruder Claas Xerion 5000 möchte ich über die Fernbedienung einige unterschiedliche Lenkprogramme...............................

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.


Hallo Stefan.:winker

Wieso nicht :frage
Ich habe sie mal eingegeben.
 
Hallo Winni,

der von der Foren-Software bemängelte Link verweist auf einen einzelnen Beitrag in einem anderen Forum.

Stelle ich den gesamten Code mit der Code-Einfügen-Funktion in das Schriftfeld und klicke dann den Vorschau-Button, kommt folgende Fehlermeldung:

Die folgenden Fehler traten bei der Verarbeitung auf

Bild-Links zu Filehostern und anderen Foren sind in diesem Forum nicht erlaubt,

Hallo {user} bitte verwende die

Attachment-Funktionen des Forums.

Betroffener Link:
r.de/thread/39320-programme-und-tips-zu-arduino/?postID

Die Fehlermeldung kommt nicht mehr, wenn ich den Anhang auf den einzelnen Beitrag aus dem Link entferne. Auch kann ich den originalen Link als einzelnen Link ohne Fehlermeldung schreiben. Nur wenn ich die Code-Einfügen-Funktion nutze, wird rumgemeckert ;) .

Der originale Link lautet: https://www.rockcrawler.de/thread/39320-programme-und-tips-zu-arduino/?postID=1092157#post1092157
 
Ich habe es doch im Code eingesetzt.
Nur habe ich den Verweis auf den späteren Post genommen der den gesammten Code beinhaltet.
Siehe blauer Text im Code.
Ich muss mal sehen, eventuell werde ich als Admin da anders behandelt.
 
Moin Stefan,

ein interessantes Projekt, aber gibt es einen Grund für die Verwendung der MoBaTools? Du brauchst doch nur die Servo Funktion und die "Servo" Library erlaubt dir das Setzen der Werte in Mikrosekunden, da musst du nichts auf Gradzahlen umrechnen.

Benutzt du für die Lenkung zwei gleihe Servos?

Ich hätte noch ein paar kleine Vorschläge:
- Baue am Anfang eine automatische Erkennung für die Mittelstellung der Lenkung ein, du hast sie aktuell 1500 fest kodiert.
- Wenn du bei der Verwendung der Gradzahlen bleiben möchtest empfehle ich dir eine Einlernfunktion für die maximalen Lenkausschläge. So hast du korrekte Werte für die map() Funktion.
 
Moin Stefan,

ein interessantes Projekt, aber gibt es einen Grund für die Verwendung der MoBaTools? Du brauchst doch nur die Servo Funktion und die "Servo" Library erlaubt dir das Setzen der Werte in Mikrosekunden, da musst du nichts auf Gradzahlen umrechnen.

Ich bin Anfänger auf dem Arduino-Gebiet. In einigen anderen Foren wurde geraten, bei Servozittern usw. mal eine andere Bibliothek als die "Servo.h" auszuprobieren.
Daher hatte ich es mal mit der MoBaTools-Bibliothek probiert.

Benutzt du für die Lenkung zwei gleihe Servos?

Geplant sind zwei HiTec HS-645MG Servos.

Ich hätte noch ein paar kleine Vorschläge:
- Baue am Anfang eine automatische Erkennung für die Mittelstellung der Lenkung ein, du hast sie aktuell 1500 fest kodiert.
- Wenn du bei der Verwendung der Gradzahlen bleiben möchtest empfehle ich dir eine Einlernfunktion für die maximalen Lenkausschläge. So hast du korrekte Werte für die map() Funktion.

In dem Bereich kenne ich mich noch nicht aus. Als Vorlage habe ich nur Dein Programm aus Deinem "Multifix-Ersatz"-Thema gefunden. Leider steige ich bei den einzelnen Funktionen (noch) nicht ganz durch.
 
Moin Stefan,

bei Fragen einfach melden, die kann man klären... ;)
 
Hier jetz eine überarbeitete Version des Programmes;



Code:
/*              Programm zur Ansteuerung von mehreren Lenkungsarten für einen Claas Xerion 5000 - Version 3 - Mai 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 gleich 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 : dqb321    - https://www.rockcrawler.de/thread/22643-mehrachser-lenkung-von-2-achsen-%C3%BCber-einen-fernsteuerkanal/
                - Modul Neutralstellung     : Joerg1972 - https://www.rockcrawler.de/thread/39320-programme-und-tips-zu-arduino
                - Modul Interruptabfrage    : gismow    - https://www.modelltruck.net/showthread.php?55990-Auslesen-von-Servosignalen-per-Interrupt
                - Modul Blinken             :           - Beispielsketch Arduino IDE - Kapitel 2 Digitial - BlinkWithoutDelay
                - Modul Nullpunktbestimmung : gismow    - https://www.modelltruck.net/showthread.php?59771-Lichtmodul-mit-Blinker-Bremslicht-und-R%FCckfahrwarner

                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.



                - Servo 1 - HiTec HS-645MG Lenkausschlag ohne Räder (1128 Microseconds - 1812 Microseconds) 1° = 10,3 microseconds, Nullpunkt 1472
                - Servo 2 - HiTec HS-645MG Lenkausschlag ohne Räder (1128 Microseconds - 1812 Microseconds) 1° = 10,3 microseconds, Nullpunkt 1472
                
                - Kanal 1 muss immer am Empfänger zur Signalauswertung angeschlossen sein
*/



#include <Servo.h>     //Library für Servoausgabe einbinden


#define debug                                                           // bedingte Compilierung

//  Variablen fuer die Lenkung
volatile  uint16_t    Empfaenger_Kanal1_Wert[4]        = {1500, 1500, 1500, 1500}; //  Die letzten 4 Werte werden gespeichert um einen Mittelwert zu bilden
volatile  uint16_t    Empfaenger_Kanal1_Wert_Summe     = 6000;           //  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[4]        = {1500, 1500, 1500, 1500}; //  Die letzten 4 Werte werden gespeichert um einen Mittelwert zu bilden
volatile  uint16_t    Empfaenger_Kanal3_Wert_Summe     = 6000;           //  Die Summe der letzten 4 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

//  Die gemessenen Mittelstellungen
int ErmittelterNullpunktLenkung    = 1500;
int ErmittelterNullpunktSchaltung  = 1500;

int   WertInSchalter; // Wert des Eingangssignal Schaltung

int   wertin; //Wert des Eingangssignale Lenkung
int   wertaus1 = 1472;  //Wert des Ausgangssignales Achse 1 (auf Mitte stellen)
int   wertaus2 = 1472;  //Wert des Ausgangssignales Achse 2 (auf Mitte stellen)
int   mixer = 40; //Mixer in % von Servo 1 auf Servo 2
int   mitte1 = 0; //Mittelstellung Servo 1 anpassen
int   mitte2 = 0; //Mittelstellung Servo 2 anpassen

const byte   deadzone = 125; // pulse lenght difference in µS between neutral and point to switch on
const byte   hysteresis = 50; // pulse lenght hysteresis (between on and off)

boolean antitoggle = true; // flag to prevent from auto toggling

Servo  s1, s2; //Servoobjekte definieren


// constants won't change. Used here to set a pin number:
const byte 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()
{
  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

  //  Den Interrupts Zeit geben aktuelle Werte zu sammeln
  delay(500);

  //  Die aktuellen Werte als gemessene Mittelstellungen verwenden
  ErmittelterNullpunktLenkung     = AktuellerEmpfaengerWertLenkung;
  ErmittelterNullpunktSchaltung   = AktuellerEmpfaengerWertSchaltung;

  s1.attach(7);                                                           // Pin für Servo 1 definieren
  s2.attach(8);                                                           // Pin für Servo 2 definieren

  s1.writeMicroseconds(ErmittelterNullpunktLenkung);                      //Servoposition Servo 1 in Neutrallage 
  s2.writeMicroseconds(ErmittelterNullpunktLenkung);                      //Servoposition Servo 2 in Neutrallage

  pinMode(ledPin, OUTPUT);                                                // Pin 13 als LED-Ausgang definieren

#ifdef debug

  Serial.begin( 57600 );                                                  // Serielle Datenübertragung zur Kontrolle aktivieren

#endif
}


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 4er 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 ) & 0x03 ); //  Index erhoehen und ggf. von 4 auf 0 springen
    //  Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
    AktuellerEmpfaengerWertLenkung             = ( Empfaenger_Kanal1_Wert_Summe >> 2 ); //  durch 4 teilen
  }
}

void InterruptSchalter()
{
  uint32_t    nMicros3   = micros();                                       //  Aktuellen Zeitstempel merken
  uint16_t    nDifference3  = (uint16_t)(nMicros3 - LetzteSchalterAenderung);       //  Die Differenz zum letzten Aufruf errechnen

  LetzteSchalterAenderung = nMicros3;                                              //  Zeitstempel fuer das naechste mal merken

  if ( (nDifference3 > 900) && ( nDifference3 < 2100))                      //  Zeiten zwischen 900 und 2100 Mikrosekunden sind das HIGH Signal
  {
    //  Wert in der 4er 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]  = nDifference3;
    //  Den neuen Wert auf die Summe addieren
    Empfaenger_Kanal3_Wert_Summe              += nDifference3;
    //  Den Index auf die naechste Position schieben
    Empfaenger_Kanal3_Wert_Index             = ( ( Empfaenger_Kanal3_Wert_Index + 1 ) & 0x03 ); //  Index erhoehen und ggf. von 4 auf 0 springen
    //  Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
    AktuellerEmpfaengerWertSchaltung             = ( Empfaenger_Kanal3_Wert_Summe >> 2 ); //  durch 4 teilen
  }
}


void blinken()

{
  // 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
  //  Abfrage, ob Schalter hochgeschalten wird
  if ( AktuellerEmpfaengerWertSchaltung > ErmittelterNullpunktSchaltung + deadzone && antitoggle == true)
  {
    antitoggle = false;
    if (Lenkprogramm < 3)
    {
      Lenkprogramm = Lenkprogramm + 1;
    }
  }

  // Abfrage, ob Schalter heruntergeschalten wird
  if ( AktuellerEmpfaengerWertSchaltung < ErmittelterNullpunktSchaltung - deadzone && antitoggle == true)
  {
    antitoggle = false;
    if (Lenkprogramm > 0)
    {
      Lenkprogramm = Lenkprogramm - 1;
    }
  }
  //  Abfrage, ob Nullpunkt Schalter vorhanden ist
  if ( abs (AktuellerEmpfaengerWertSchaltung - ErmittelterNullpunktSchaltung) < 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 >= ( ErmittelterNullpunktLenkung - 150 ) ) && ( AktuellerEmpfaengerWertLenkung <= ( ErmittelterNullpunktLenkung + 150 ) ) ))
  {
    // AktuellerEmpfaengerWertLenkung = 1472;
    AktuellerEmpfaengerWertLenkung = ErmittelterNullpunktLenkung;
  }


  /* Ab hier werden die einzelnen Lenkprogramme beschrieben

  */


  if (Lenkprogramm == 1)                          // Standard-Lenkung
  {
    digitalWrite(LED_BUILTIN, HIGH);

    wertin = AktuellerEmpfaengerWertLenkung;
    wertaus1 = wertin + mitte1; //Mittelstellung Servo1 korregieren
    wertaus2 = wertaus1 - 1472;
    wertaus2 = wertaus2 * mixer / 100; //Mixer für Servo2 einrechnen
    wertaus2 = wertaus2 + 1472;
    wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
    wertaus1 = constrain(wertaus1, 1128, 1812); //Ausgabewert für Servo1 begrenzen als Schutz
    wertaus2 = constrain(wertaus2, 1128, 1812); //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 = wertin + mitte1; //Mittelstellung Servo1 korregieren
    wertaus2 = 1472 - wertaus1;
    wertaus2 = (wertaus2 + 1472);
    wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
    wertaus1 = constrain(wertaus1, 1128, 1812); //Ausgabewert für Servo1 begrenzen als Schutz
    wertaus2 = constrain(wertaus2, 1128, 1812); //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 = wertin + mitte1; //Mittelstellung Servo1 korregieren
    wertaus2 = wertaus1;
    wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
    wertaus1 = constrain(wertaus1, 1128, 1812); //Ausgabewert für Servo1 begrenzen als Schutz
    wertaus2 = constrain(wertaus2, 1128, 1812); //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.writeMicroseconds(wertaus1);                                                   //Servo 1 stellen
  s2.writeMicroseconds(wertaus2);                                                   //Servo 2 stellen

  delay(20);

}

- dynamische Nullpunktermittlung beim Starten
- Steuerung der Servos mittels "Servo.writeMicroseconds"
- Auswertung der Empfängersignale mittels Interrupt
- viele Teile des Sketches stammen aus Themen von Peter (gismow), vielen Dank dafür!
 
Moin Stefan,

es geht voran.... ;)

Ich hätte noch einen Tipp aus eigener Erfahrung. Du machst eine statische Pause im setup() damit die Interrupts Daten sammeln können. Dies setzt allerdings voraus dass der Empfänger sofort vom Beginn an Signale liefert. Schaltet man mal erst das Modell und danach den Sender ein sind die 500ms bereits verstrichen.

Ich mache es bei mir wie folgt:

Ich definiere eine Variable (volatile) mit einem Counter und eine Statusvariable, Die Statusvariable kennt die Werte 0 (Startwert - Sammele Daten) und 1 (Programmausführung). Der Counter wird mit 0 initialisiert. Im Interrupt kommt eine Abfrage rein

if (Startwert == 0 && Counter < 10) Counter++;

Im loop() kommt am Anfang folgende Abfrage rein:

Code:
if (Startwert == 0)
{
    if (Counter >= 10)
   {
        //  den aktuellen Servowert als gemessenen Wert eintragen
        ... hier etws tun...
        //  und danach den Startwert anders setzen
        Startwert = 1;
    }
    else
    {
           //   Es wird noch auf gueltige Daten gewartet....
          delay(20);
         return;
    }
}

Dieser Code hat den Vorteil dass das Modul erst anfängt zu arbeiten wenn mindestens 10 gültige Werte ermittelt wurden. So ist ein eventuel verzögerter Verbindungsaufbau zwischen Sender und Empfänger kein Problem.
 
Vielen Dank für Deine Hinweise!

Meinst Du mit der Funktion einfügen, das so?

Code:
....

void loop()
{
  if (Initialisierung == 1)
  {
    if (AnzahlLegaleWerte >= 10)
    {
      Initialisierung = 0;
    }
    else
    {
      //   Es wird noch auf gueltige Daten gewartet....
      delay(20);
      return;
    }
  }


  //  Hier kann nun mit dem Wert von AktuellerEmpfaengerWertSchaltung gearbeitet werden
  //  Abfrage, ob Schalter hochgeschalten wird
  if ( AktuellerEmpfaengerWertSchaltung > ErmittelterNullpunktSchaltung + deadzone && antitoggle == true)
  {
    antitoggle = false;
    if (Lenkprogramm < 3)
    {
      Lenkprogramm = Lenkprogramm + 1;
    }
  }

.....

Ist nur ein Programmausschnitt. Ich habe die Werte für die Variable Initialisierung nur getauscht.
 
Moin Stefan,

genau, und im Interrupt des Lenkkanals zählst du den Counter bei jedem gültigen Signal hoch.
 
So dann mal hier die gesamte Version:

Code:
/*              Programm zur Ansteuerung von mehreren Lenkungsarten für einen Claas Xerion 5000 - Version 4 - Mai 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 gleich 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 3

                Vorlagen:
                - Grundgerüst der Lenkarten : dqb321    - https://www.rockcrawler.de/thread/22643-mehrachser-lenkung-von-2-achsen-%C3%BCber-einen-fernsteuerkanal/
                - Modul Neutralstellung     : Joerg1972 - https://www.rockcrawler.de/thread/39320-programme-und-tips-zu-arduino
                - Modul Interruptabfrage    : gismow    - https://www.modelltruck.net/showthread.php?55990-Auslesen-von-Servosignalen-per-Interrupt
                - Modul Blinken             :           - Beispielsketch Arduino IDE - Kapitel 2 Digitial - BlinkWithoutDelay
                - Modul Nullpunktbestimmung : gismow    - https://www.modelltruck.net/showthread.php?59771-Lichtmodul-mit-Blinker-Bremslicht-und-R%FCckfahrwarner

                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.



                - Servo 1 - HiTec HS-645MG Lenkausschlag ohne Räder (1128 Microseconds - 1812 Microseconds) 1° = 10,3 microseconds, Nullpunkt 1472
                - Servo 2 - HiTec HS-645MG Lenkausschlag ohne Räder (1128 Microseconds - 1812 Microseconds) 1° = 10,3 microseconds, Nullpunkt 1472

                - Kanal 1 muss immer am Empfänger zur Signalauswertung angeschlossen sein
*/



#include <Servo.h>     //Library für Servoausgabe einbinden


#define debug                                                           // bedingte Compilierung

//  Variablen fuer die Lenkung
volatile  uint16_t    Empfaenger_Kanal1_Wert[4]        = {1500, 1500, 1500, 1500}; //  Die letzten 4 Werte werden gespeichert um einen Mittelwert zu bilden
volatile  uint16_t    Empfaenger_Kanal1_Wert_Summe     = 6000;           //  Die Summe der letzten 4 Werte
volatile  uint8_t     Empfaenger_Kanal1_Wert_Index     = 0;            //  Der Index des naechsten auszutauschenden Wwets

volatile  uint8_t     Initialisierung   = 1;
volatile  uint8_t     AnzahlLegaleWerte = 0;

//  Variablen fuer die Schaltung
volatile  uint16_t    Empfaenger_Kanal3_Wert[4]        = {1500, 1500, 1500, 1500}; //  Die letzten 4 Werte werden gespeichert um einen Mittelwert zu bilden
volatile  uint16_t    Empfaenger_Kanal3_Wert_Summe     = 6000;           //  Die Summe der letzten 4 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

//  Die gemessenen Mittelstellungen
int ErmittelterNullpunktLenkung    = 1500;
int ErmittelterNullpunktSchaltung  = 1500;

int   WertInSchalter; // Wert des Eingangssignal Schaltung

int   wertin; //Wert des Eingangssignale Lenkung
int   wertaus1 = 1472;  //Wert des Ausgangssignales Achse 1 (auf Mitte stellen)
int   wertaus2 = 1472;  //Wert des Ausgangssignales Achse 2 (auf Mitte stellen)
int   mixer = 40; //Mixer in % von Servo 1 auf Servo 2
int   mitte1 = 0; //Mittelstellung Servo 1 anpassen
int   mitte2 = 0; //Mittelstellung Servo 2 anpassen

const byte   deadzone = 125; // pulse lenght difference in µS between neutral and point to switch on
const byte   hysteresis = 50; // pulse lenght hysteresis (between on and off)

boolean antitoggle = true; // flag to prevent from auto toggling

Servo  s1, s2; //Servoobjekte definieren


// constants won't change. Used here to set a pin number:
const byte 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()
{
  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

  //  Den Interrupts Zeit geben aktuelle Werte zu sammeln
  delay(500);

  //  Die aktuellen Werte als gemessene Mittelstellungen verwenden
  ErmittelterNullpunktLenkung     = AktuellerEmpfaengerWertLenkung;
  ErmittelterNullpunktSchaltung   = AktuellerEmpfaengerWertSchaltung;

  s1.attach(7);                                                           // Pin für Servo 1 definieren
  s2.attach(8);                                                           // Pin für Servo 2 definieren

  s1.writeMicroseconds(ErmittelterNullpunktLenkung);                      //Servoposition Servo 1 in Neutrallage
  s2.writeMicroseconds(ErmittelterNullpunktLenkung);                      //Servoposition Servo 2 in Neutrallage

  pinMode(ledPin, OUTPUT);                                                // Pin 13 als LED-Ausgang definieren

#ifdef debug

  Serial.begin( 57600 );                                                  // Serielle Datenübertragung zur Kontrolle aktivieren

#endif
}


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 4er 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 ) & 0x03 ); //  Index erhoehen und ggf. von 4 auf 0 springen
    //  Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
    AktuellerEmpfaengerWertLenkung             = ( Empfaenger_Kanal1_Wert_Summe >> 2 ); //  durch 4 teilen
    //Abfrage gültiger Daten
    if (Initialisierung == 1 && AnzahlLegaleWerte < 10) AnzahlLegaleWerte++;
  }
}

void InterruptSchalter()
{
  uint32_t    nMicros3   = micros();                                       //  Aktuellen Zeitstempel merken
  uint16_t    nDifference3  = (uint16_t)(nMicros3 - LetzteSchalterAenderung);       //  Die Differenz zum letzten Aufruf errechnen

  LetzteSchalterAenderung = nMicros3;                                              //  Zeitstempel fuer das naechste mal merken

  if ( (nDifference3 > 900) && ( nDifference3 < 2100))                      //  Zeiten zwischen 900 und 2100 Mikrosekunden sind das HIGH Signal
  {
    //  Wert in der 4er 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]  = nDifference3;
    //  Den neuen Wert auf die Summe addieren
    Empfaenger_Kanal3_Wert_Summe              += nDifference3;
    //  Den Index auf die naechste Position schieben
    Empfaenger_Kanal3_Wert_Index             = ( ( Empfaenger_Kanal3_Wert_Index + 1 ) & 0x03 ); //  Index erhoehen und ggf. von 4 auf 0 springen
    //  Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
    AktuellerEmpfaengerWertSchaltung             = ( Empfaenger_Kanal3_Wert_Summe >> 2 ); //  durch 4 teilen
  }
}


void blinken()

{
  // 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()
{
  if (Initialisierung == 1)
  {
    if (AnzahlLegaleWerte >= 10)
    {
      Initialisierung = 0;
    }
    else
    {
      //   Es wird noch auf gueltige Daten gewartet....
      delay(20);
      return;
    }
  }


  //  Hier kann nun mit dem Wert von AktuellerEmpfaengerWertSchaltung gearbeitet werden
  //  Abfrage, ob Schalter hochgeschalten wird
  if ( AktuellerEmpfaengerWertSchaltung > ErmittelterNullpunktSchaltung + deadzone && antitoggle == true)
  {
    antitoggle = false;
    if (Lenkprogramm < 3)
    {
      Lenkprogramm = Lenkprogramm + 1;
    }
  }

  // Abfrage, ob Schalter heruntergeschalten wird
  if ( AktuellerEmpfaengerWertSchaltung < ErmittelterNullpunktSchaltung - deadzone && antitoggle == true)
  {
    antitoggle = false;
    if (Lenkprogramm > 0)
    {
      Lenkprogramm = Lenkprogramm - 1;
    }
  }
  //  Abfrage, ob Nullpunkt Schalter vorhanden ist
  if ( abs (AktuellerEmpfaengerWertSchaltung - ErmittelterNullpunktSchaltung) < 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 >= ( ErmittelterNullpunktLenkung - 150 ) ) && ( AktuellerEmpfaengerWertLenkung <= ( ErmittelterNullpunktLenkung + 150 ) ) ))
  {
    // AktuellerEmpfaengerWertLenkung = 1472;
    AktuellerEmpfaengerWertLenkung = ErmittelterNullpunktLenkung;
  }


  /* Ab hier werden die einzelnen Lenkprogramme beschrieben

  */


  if (Lenkprogramm == 1)                          // Standard-Lenkung
  {
    digitalWrite(LED_BUILTIN, HIGH);

    wertin = AktuellerEmpfaengerWertLenkung;
    wertaus1 = wertin + mitte1; //Mittelstellung Servo1 korregieren
    wertaus2 = wertaus1 - 1472;
    wertaus2 = wertaus2 * mixer / 100; //Mixer für Servo2 einrechnen
    wertaus2 = wertaus2 + 1472;
    wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
    wertaus1 = constrain(wertaus1, 1128, 1812); //Ausgabewert für Servo1 begrenzen als Schutz
    wertaus2 = constrain(wertaus2, 1128, 1812); //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 = wertin + mitte1; //Mittelstellung Servo1 korregieren
    wertaus2 = 1472 - wertaus1;
    wertaus2 = (wertaus2 + 1472);
    wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
    wertaus1 = constrain(wertaus1, 1128, 1812); //Ausgabewert für Servo1 begrenzen als Schutz
    wertaus2 = constrain(wertaus2, 1128, 1812); //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 = wertin + mitte1; //Mittelstellung Servo1 korregieren
    wertaus2 = wertaus1;
    wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
    wertaus1 = constrain(wertaus1, 1128, 1812); //Ausgabewert für Servo1 begrenzen als Schutz
    wertaus2 = constrain(wertaus2, 1128, 1812); //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.writeMicroseconds(wertaus1);                                                   //Servo 1 stellen
  s2.writeMicroseconds(wertaus2);                                                   //Servo 2 stellen

  delay(20);

}

Hier dann nochmal der Versuchsaufbau:

modul_lenkung_01_Steckplatine.jpg
 
Moin Stefan,

zur Sicherheit würde ich beim Nano noch einen Elko als Puffer einbauen. Wenn beide Servos unter Last arbeiten könnte die Spannung abfallen. Sinkt sie unter die Minimalspannung des Nano resettet er. Ein Elko kann hier kurzfristig den Einbruch dämpfen.

Du kannst, wenn du auf 7,2V fährst den Nano über Vin auch direkt an den Akku anschließen. Laut Specs verträgt der 7-12V.
 
Danke für den Tipp!

Welcher Elko wäre denn empfehlenswert? In meiner Bastelkiste habe ich 25V-10µF, einen 35V-100µF, 25V-22µF und einen 16V-100µF gefunden.

Sorry, aber in Sachen Elektronik bin ich nicht so bewandert.
 
Moin Stefan,

ich meine ein 16V-100 ist prima.
 
Hallo,

ich habe mir das Programm heute mal angesehn, da ich für meinen Autoblinda auch so etwas brauche.

Das Programm hatte noch einen Bug, man konnte auch auf Lenkart 0 schalten, der ist jetzt raus.
Neu sind:
- die interne LED dient zur Anzeiger des gewählten Lenkprogrammes, das blinkt dann 1 bis 3 mal
- man kann Servo 2 invertieren (wegen Einbaulage) wenn man D6 auf Masse schaltet
- Es gibt einen Nullpunktabgleich mit einem Poti an A0 für Servo 2. Nutzt man den nicht, so schaltet sich die Funktion automatische ab
- das Debuggen wurde um einige Werte und Beschreibungen erweitert.


Code:
/*              Programm zur Ansteuerung von mehreren Lenkungsarten für eine Allradlenkung - Version 5 - Dezember 2019

                - Programm verwendet die beiden Interrupts zur Signalabfrage anstelle der Funktion pulseIn
                - Pin D2: Kanal 1 der Fernsteuerung dient zur Lenkung
                - Pin D3: Kanal 3 der Fernsteuerung dient zum Einstellen von eines der drei Lenkprogramme (hoch- bzw- runterschalten mittels Senderhebel)

                - Lenkprogrammarten:
                  1 - normale Lenkung (1x blinken)
                  2 - Allrad-Lenkung (2x blinken), vordere und hintere Lenkachse werden entgegengesetzt angelenkt
                  3 - Hundegang (3x blinken), vordere und hintere Lenkachse werden gleich angelenkt
                - interne LED dient zur Anzeiger des gewählten Lenkprogrammes 

                - Abgleich Servo 2 (update BordIng)
                  Servo 2 kann invertiert werden (wegen Einbaulage gespiegelt)und es gibt einen Nullabgleich
                  D6 auf masse invertiert Servo 2
                  A0 mit Poti auf Uref führt einen Nullpunktabgleich nur für Poti 2 durch. Liegt kein Signal an A0, dann schaltet sich der Abgleich aus.

                Vorlagen:
                - Grundgerüst der Lenkarten : dqb321    - https://www.rockcrawler.de/thread/22643-mehrachser-lenkung-von-2-achsen-%C3%BCber-einen-fernsteuerkanal/
                - Modul Neutralstellung     : Joerg1972 - https://www.rockcrawler.de/thread/39320-programme-und-tips-zu-arduino
                - Modul Interruptabfrage    : gismow    - https://www.modelltruck.net/showthread.php?55990-Auslesen-von-Servosignalen-per-Interrupt
                - Modul Blinken             : BordIing   
                - Modul Nullpunktbestimmung : gismow    - https://www.modelltruck.net/showthread.php?59771-Lichtmodul-mit-Blinker-Bremslicht-und-R%FCckfahrwarner

                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.



                - Pin D7: Servo 1 - HiTec HS-645MG Lenkausschlag ohne Räder (1128 Microseconds - 1812 Microseconds) 1° = 10,3 microseconds, Nullpunkt 1472
                - Pin D8: Servo 2 - HiTec HS-645MG Lenkausschlag ohne Räder (1128 Microseconds - 1812 Microseconds) 1° = 10,3 microseconds, Nullpunkt 1472

                - Kanal 1 muss immer am Empfänger zur Signalauswertung angeschlossen sein
*/



#include <Servo.h>     //Library für Servoausgabe einbinden


#define debug                                                           // bedingte Compilierung

//  Variablen fuer die Lenkung
volatile  uint16_t    Empfaenger_Kanal1_Wert[4]        = {1500, 1500, 1500, 1500}; //  Die letzten 4 Werte werden gespeichert um einen Mittelwert zu bilden
volatile  uint16_t    Empfaenger_Kanal1_Wert_Summe     = 6000;           //  Die Summe der letzten 4 Werte
volatile  uint8_t     Empfaenger_Kanal1_Wert_Index     = 0;            //  Der Index des naechsten auszutauschenden Wwets

volatile  uint8_t     Initialisierung   = 1;
volatile  uint8_t     AnzahlLegaleWerte = 0;

//  Variablen fuer die Schaltung
volatile  uint16_t    Empfaenger_Kanal3_Wert[4]        = {1500, 1500, 1500, 1500}; //  Die letzten 4 Werte werden gespeichert um einen Mittelwert zu bilden
volatile  uint16_t    Empfaenger_Kanal3_Wert_Summe     = 6000;           //  Die Summe der letzten 4 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

//  Die gemessenen Mittelstellungen
int ErmittelterNullpunktLenkung    = 1500;
int ErmittelterNullpunktSchaltung  = 1500;

int   WertInSchalter;                    // Wert des Eingangssignal Schaltung

int   wertin;                            //Wert des Eingangssignale Lenkung
int   wertaus1 = 1472;                   //Wert des Ausgangssignales Achse 1 (auf Mitte stellen)
int   wertaus2 = 1472;                   //Wert des Ausgangssignales Achse 2 (auf Mitte stellen)
int   mixer = 40;                        //Mixer in % von Servo 1 auf Servo 2
int   mitte1 = 0;                        //Mittelstellung Servo 1 anpassen
int   mitte2 = 0;                        //Mittelstellung Servo 2 anpassen

const byte   deadzone = 125;             // pulse lenght difference in µS between neutral and point to switch on
const byte   hysteresis = 50;            // pulse lenght hysteresis (between on and off)

boolean antitoggle = true;               // flag to prevent from auto toggling

Servo  s1, s2;                           //Servoobjekte definieren


// Servo 2 invertieren und Nullstellungspoti
const byte Invert_Servo2 = 6;            // Eingang D6 ist für die Invertierung Servo 2
int invert2 = 0;                         // Variable für die Invertierung

const byte POTI_1 = 0;                   // analoger Eingang auf Pin 23 (ADC0) für das Poti
int Poti_analog_1= 0;                    // analoger Wert von Poti
int Servo2_offset = 0;                   // Offset für das Servo 2


// Blinker -- Anzeige der Lenkarten
byte ledPin = 13;                        // LED liegt am (digitalen) Pin 13
boolean value = LOW;                     // Startwert der LED
unsigned long previousMillis = 0;        // speichert wie viele Millisekunden seit derletzten Änderung vergangen sind
unsigned long interval = 500;            // Interval zwischen zwei Änderungen
byte counter = 0;                        // Zähler
byte Lenkart = 0;                        // Lenkartnummer die angezeigt werden soll



void setup()
{
  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

  //  Den Interrupts Zeit geben aktuelle Werte zu sammeln
  delay(500);

  //  Die aktuellen Werte als gemessene Mittelstellungen verwenden
  ErmittelterNullpunktLenkung     = AktuellerEmpfaengerWertLenkung;
  ErmittelterNullpunktSchaltung   = AktuellerEmpfaengerWertSchaltung;

  s1.attach(7);                                                           // Pin D6 für Servo 1 definieren
  s2.attach(8);                                                           // Pin D7 für Servo 2 definieren

  s1.writeMicroseconds(ErmittelterNullpunktLenkung);                      //Servoposition Servo 1 in Neutrallage
  s2.writeMicroseconds(ErmittelterNullpunktLenkung);                      //Servoposition Servo 2 in Neutrallage

  pinMode(ledPin, OUTPUT);                                                // Pin 13 als LED-Ausgang definieren
  pinMode(Invert_Servo2, INPUT);                                          // Eingang D6 ist für die Invertierung Servo 2  
  digitalWrite(Invert_Servo2, HIGH);                                      // Pull Up Widerstand aktivieren

#ifdef debug

  Serial.begin( 57600 );                                                  // Serielle Datenübertragung zur Kontrolle aktivieren

#endif

}


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 4er 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 ) & 0x03 ); //  Index erhoehen und ggf. von 4 auf 0 springen
    //  Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
    AktuellerEmpfaengerWertLenkung             = ( Empfaenger_Kanal1_Wert_Summe >> 2 );         //  durch 4 teilen
    //Abfrage gültiger Daten
    if (Initialisierung == 1 && AnzahlLegaleWerte < 10) AnzahlLegaleWerte++;
  }
}

void InterruptSchalter()
{
  uint32_t    nMicros3   = micros();                                          //  Aktuellen Zeitstempel merken
  uint16_t    nDifference3  = (uint16_t)(nMicros3 - LetzteSchalterAenderung); //  Die Differenz zum letzten Aufruf errechnen

  LetzteSchalterAenderung = nMicros3;                                         //  Zeitstempel fuer das naechste mal merken

  if ( (nDifference3 > 900) && ( nDifference3 < 2100))                        //  Zeiten zwischen 900 und 2100 Mikrosekunden sind das HIGH Signal
  {
    //  Wert in der 4er 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]  = nDifference3;
    
    //  Den neuen Wert auf die Summe addieren
    Empfaenger_Kanal3_Wert_Summe              += nDifference3;
    
    //  Den Index auf die naechste Position schieben
    Empfaenger_Kanal3_Wert_Index             = ( ( Empfaenger_Kanal3_Wert_Index + 1 ) & 0x03 ); //  Index erhoehen und ggf. von 4 auf 0 springen
    
    //  Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
    AktuellerEmpfaengerWertSchaltung             = ( Empfaenger_Kanal3_Wert_Summe >> 2 );  //  durch 4 teilen
  }
}


void blinken()

{   //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
       // Blinker Anzeige Lenkart
             
       if (millis() - previousMillis > interval) {  // ist die Intervallzeit abgelaufen, so wird dies ausgeführt
         previousMillis = millis();                 // aktuelle Zeit abspeichern
         counter++;                                 // Zähler einen hochzählen
  
           if (counter <= (2*Lenkart)) {            // der Zähler wird abgefragt, solange der Wert kleiner/gleich ist wird der Code ausgeführt. Der
                                                    // Vergleichswert ist die Fehlernummer mal 2 (an/aus)
             value = !value;                        // der Ausgangswert wird getoggelt und ändert sich mit jedem loop
             digitalWrite(ledPin, value);           // Wert auf den Ausgang schreiben
             }
        }

       if (Lenkart == 0) {                          // wenn kein Fehler anliegt wird die LED auf jeden Fall ausgeschaltet
        digitalWrite(ledPin, LOW);
        value = LOW;                                // value = LOW
        counter = 0;                                // counter reset
       }
       
   if (counter == (2*Lenkart + 5)) {                // der gesamte Loop für den Counter berechnet sich aus der 2*Fehleranzahl plus 5 Takte warten
    counter = 0;                                    // Zähler zurück setzen
    }   
    
  // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 
}


void loop()
{
  if (Initialisierung == 1)
  {
    if (AnzahlLegaleWerte >= 10)
    {
      Initialisierung = 0;
    }
    else
    {
      //   Es wird noch auf gueltige Daten gewartet....
      delay(20);
      return;
    }
  }


  //  Hier kann nun mit dem Wert von AktuellerEmpfaengerWertSchaltung gearbeitet werden
  //  Abfrage, ob Schalter hochgeschalten wird
  if ( AktuellerEmpfaengerWertSchaltung > ErmittelterNullpunktSchaltung + deadzone && antitoggle == true)
  {
    antitoggle = false;
    if (Lenkprogramm < 3)
    {
      Lenkprogramm = Lenkprogramm + 1;
    }
  }

  // Abfrage, ob Schalter heruntergeschalten wird
  if ( AktuellerEmpfaengerWertSchaltung < ErmittelterNullpunktSchaltung - deadzone && antitoggle == true)
  {
    antitoggle = false;
    if (Lenkprogramm > 1)
    {
      Lenkprogramm = Lenkprogramm - 1;
    }
  }
  //  Abfrage, ob Nullpunkt Schalter vorhanden ist
  if ( abs (AktuellerEmpfaengerWertSchaltung - ErmittelterNullpunktSchaltung) < 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 >= ( ErmittelterNullpunktLenkung - 150 ) ) && ( AktuellerEmpfaengerWertLenkung <= ( ErmittelterNullpunktLenkung + 150 ) ) ))
  {
    AktuellerEmpfaengerWertLenkung = ErmittelterNullpunktLenkung;
  }


// Ab hier werden die einzelnen Lenkprogramme beschrieben

   if (Lenkprogramm == 1)                       // Standard-Lenkung
  {
    Lenkart = 1; 
    blinken();                                  // Aufruf der Funktion "blinken"

    wertin = AktuellerEmpfaengerWertLenkung;
    wertaus1 = wertin + mitte1;                 //Mittelstellung Servo 1 korregieren
    wertaus2 = 1500;
  }

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  if (Lenkprogramm == 2)                        // Allrad-Lenkung
  {
    Lenkart = 2; 
    blinken();                                  // Aufruf der Funktion "blinken"

    wertin = AktuellerEmpfaengerWertLenkung;
    wertaus1 = wertin + mitte1;                 //Mittelstellung Servo 1 korregieren
    wertaus2 = 1500 - wertaus1;
    wertaus2 = (wertaus2 + 1500);
    wertaus2 = wertaus2 + mitte2;               //Mittelstellung Servo2 korregieren
   }

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  if (Lenkprogramm == 3)                        // Hundegang
  {
    Lenkart = 3; 
    blinken();                                  // Aufruf der Funktion "blinken"

    wertin = AktuellerEmpfaengerWertLenkung;
    wertaus1 = wertin + mitte1;                 //Mittelstellung Servo1 korregieren
    wertaus2 = wertaus1;
    wertaus2 = wertaus2 + mitte2;               //Mittelstellung Servo2 korregieren
   }

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


// Servo 2 invertieren
 if (digitalRead (Invert_Servo2) == LOW) {                 // wenn Eingang D6 auf Masse ist, wird Servo 2 invertiert
  invert2 = wertaus2-1500;                                 // umrechnen der invertierten Werte für Servo 2 
  wertaus2 = 1500-invert2;
 }

// Neutralabgleich Servo 2
    Poti_analog_1 = analogRead(POTI_1);                    // Liest den Analogwert vom Pin 23 zwischen 0 und 1023)
    if ((Poti_analog_1 <= 50)|| (Poti_analog_1 >= 950)) 
      {Servo2_offset == 0;}                                // Drahtbrucherkennung Poti, dann kein Offset
   
    else { 
      Servo2_offset = map(Poti_analog_1, 51, 949, -200, 200);  // Skaliert den analogen Eingangswert (+/- 200)
      wertaus2 = wertaus2 + Servo2_offset;
    } 

// Ausgabe der Werte an die PWM Ausgänge
  wertaus1 = constrain(wertaus1, 800, 2000);     //Ausgabewert für Servo1 begrenzen als Schutz
  wertaus2 = constrain(wertaus2, 800, 2000);     //Ausgabewert für Servo2 begrenzen als Schutz
  s1.writeMicroseconds(wertaus1);                //Servo 1 stellen
  s2.writeMicroseconds(wertaus2);                //Servo 2 stellen

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

#ifdef debug

  Serial.print  ("Lenkung ");
  Serial.println(AktuellerEmpfaengerWertSchaltung);     //Eingangswert Lenkung anzeigen über Serial Monitor
  Serial.print  ("Lenkprogramm ");    
  Serial.println(Lenkprogramm);                         //Anzeige gewähltes Lenkprogramm über Serial Monitor
  Serial.print  ("Poti ");    
  Serial.println(Poti_analog_1); 
  Serial.print  ("Offset ");    
  Serial.println(Servo2_offset); 
  Serial.print  ("Servo 1 an D7 ");                     //Anzeige Servo 1 Position
  Serial.println(wertaus1);
  Serial.print  ("Servo 1 an D8 ");                     //Anzeige Servo 1 Position
  Serial.println(wertaus2);
 

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
#endif

  delay(20);

}
 

Servonaut
Zurück
Oben Unten