Fahrtregler auf Arduino Basis

  • So habe mal versucht mit meinem bescheidenem Wissen einen Zweikanalfahrtregler zu programmieren.
    Soweit funktioniert das auch so halb.
    Habe erstmal nur einen Kanal programmiert für vorwärts und rückwärts. Solange ich in der Neutralzone bleibe geht alles gut. Gehe ich nur leicht raus (d.h. die Motoren bekommen kleine PWM Werte) gehen die auf Vollgas (bei mir blinken die LEDs). Gehe ich dann weiter funktioniert die Regelung wieder ganz gut. Allerdings komme ich nie auf Vollgas (PWM 255) da sonst der Regler dicht macht. Rein theoretisch ist 2000ms PWM255 aber da müsste ich nach ganz oben trimmen. Stell ich den Wert auf 1800ms PWM 255 und komme auf 1801ms stoppt der Motor wieder.
    Bin mit meinem Wissen am Ende könnt ihr mir helfen?

    Das Programm:

    Erfahrungen sind was sehr nützliches, leider macht man sie erst kurz nachdem man sie gebraucht hätte...

    Einmal editiert, zuletzt von Krümmel (7. Mai 2013 um 14:28)

    • Offizieller Beitrag

    Bevor ich jetzt lange suche...: was macht "map" ?

    Nach meiner Ansicht ist die Zeitmessung noch nicht ganz "abgeriegelt", kann mich jetzt aber täuschen.

    Weiterhin:
    "pulseIn(pin4, HIGH) >1549"

    Wann startet der Timer mit der Zeitmessung bei 0? Wenn der Eingangspuls auf "1" geht? Ganz sicher? Nicht dass nach 1.0ms Zeitdauer der Timer schon einen Überlauf hat und wieder von vorne anfängt.

    Die 1000ms und 2000ms sind auch etwas verwundertlich.

    Irgendwie kommt mir das alles recht simpel vor. Denn:

    Gemessene Zeit = 1.5ms : PWM1 muss 0 sein
    Gemessene Zeit > 1.5ms : Linear von 1.5ms bis 2.0ms den PWM von 0 bis 255 ansteuern.
    Gemessene Zeit < 1.5ms : Linear von 1.5ms bis 1.0ms (absteigend) den PWM von 0 bis 255 ansteuern. Das fehlt hier noch, augenblicklich schaltest Du offensichtlich ab. Ist ok für die ersten Gehversuche.

    Heißt also, dass Du für die Vorwärtsbewegung erst mal den Offset von 1.5ms unterdrücken must. Alles was über 1.5ms ist, muss linear im Bereich bis 2.0ms auf die PWM umgemünzt werden. (Stellwert = Gemessener Wert minus 1.5ms; ..)

    Wo legst Du fest, dass der Timer in uSek-Bereich läuft und bei der fallenden Flanke wieder auf 0 zurückgesetzt wird? (Oder ist das im Betriebssystem von dem Kistchen schon enthalten?)

    Weil Du die Trimmung angesprochen hast: Ich habe schon einige Funken ausgemessen. Die meisten machen nur Pulse zwischen 1.2ms und 1.8ms. Damit kommt man nie auf Vollgas. Wenn Du die Trimmung verstellst, kommst Du auf Vollgas. Aber der Nullpunkt stimmt nicht mehr. Somit radelt der Fahrtregler dann auch im Stand mit viertelter Geschwindigkeit vor sich hin.

  • map ist ein Umrechner. Der macht aus 1500-2000 z.b 0-255
    Der Timer startet sobald das Einganssignal auf 1 ist.

    Das Arduinoboard hat PWM und Zeitmesser(?) onboard. Der kann von 10µS bis 3Minuten messen.

    Es ist noch kein Failsafe eingebaut. Wenn ich den Empfänger trenne bleiben die Ausgänge noch einige Sekunden gesetzt. Es gibt bei den pulsIn() einen Timeout befehl der standartmäßig bei einer Sekunde liegt. Ich habe es aber noch nicht geschafft das zu ändern.

    "Gemessene Zeit = 1.5ms : PWM1 muss 0 sein
    Gemessene Zeit > 1.5ms : Linear von 1.5ms bis 2.0ms den PWM von 0 bis 255 ansteuern.
    Gemessene Zeit < 1.5ms : Linear von 1.5ms bis 1.0ms (absteigend) den PWM von 0 bis 255 ansteuern."

    Genau das habe ich ja versucht. Halt mit einem Totbereich in der Mitte.

    Erfahrungen sind was sehr nützliches, leider macht man sie erst kurz nachdem man sie gebraucht hätte...

    • Offizieller Beitrag

    Ok, ...

    bist Du sicher, dass die Umrechnung stimmt?

    Vorschlag:
    Entzerre mal die Variablen. Du hast eine Variable zum Zeitmessen. Die schickst Du in den map-Funktion. Das Rechenergebnis ist aber der gleiche Variablenname.
    Mach mal "RCOut1Wert" draus. Dann kannst Du genau prüfen, was "rein geht" und "was raus geht". ;)

    Weiterhin:
    Mir fehlt eine Verriegelung von der Zeitmessung.
    Angenommen, Du startest die Schleife und genau in diesem Augenblick legt der Timer mit der Messung los. Dann steht da z.B. "10" drin. Also wird die PWM für 10 berechnet. Du machst die nächste Schleife. Der Eingangspuls liegt weiterhin an. Aber jetzt zeigt der Timer 20 an. Also wird die PWM angehoben. Wieder die nächste Schleife... und wieder eine höhere PWM.

    Du musst die Schleife zum Messen von dem Eingangsimpuls solange laufen lassen, bis die "0" am Eingang anliegt. Dann den zuletzt gemessenen Timerwert nehmen und daraus dann die PWM berechnen.
    In Deinem Fall berechnest Du bei jedem Schleifendurchlauf eine neue PWM. (Die Schleife ist garantiert schneller durchlaufen als der gemessenen Puls anliegt. ;)


    Ich improvisiere jetzt mal die Systematik:

    if (pulseIn(pin4, HIGH) >100) // Es liegt ein High-Puls an => Messen
    {
    ..RCIn1Wert = pulseIn(pin4, HIGH) // Den aktuellen Timerwert der Messvariablen zuweisen => wird im Laufe der Zeit immer größer werden, da der Puls ja aktuell immer länger gemessen wird.
    }
    else // Es liegt eine Null vom Empfänger an => Der Puls ist beendet. => Jetzt die PWM anhand der letzten gemessenen Pulszeit setzen
    {
    ..if RCIn1Wert > 1550 // langer Puls, also Vorwärtsrichtung
    ..{
    ....RCOut1Wert=map(RCIn1Wert,1500,2000,0,255)
    ..}
    ..else if RCIn1Wert < 1450 // kurzer Puls, also Rückwärtsrichtung
    ..{
    ....RCOut1WErt=map(RCIn1Wert, 1500, 1000, 0, 255)
    ..}
    ..else // Wert liegt zwischen 1450 und 1550
    ..{
    .....=> Brücke abschalten => Kommando spare ich mir jetzt
    ..}
    }

  • Ok Variablen werden aufgedröselt und die Timeout Funktion geht jetzt auch. Die stand auf 3mS aber ein Frame ist ja 25mS lang.
    Jetzt schmeißt mir der Serielle Monitor nur Müll aus aber von Jeder Variable einzelnd. Wird also besser.

    Erfahrungen sind was sehr nützliches, leider macht man sie erst kurz nachdem man sie gebraucht hätte...

  • So funktioniert jetzt fast richtig.
    Keine Probleme um den Totpunkt und saubere Ansteuerung.
    Problem Failsafe in eine Richtung geht, in die andere richtung gibt es dann Volgas.

    Reiner deinen Post habe ich gerade erst gesehen ich probier das auch gleich mal aus.

    int pin7 = 7; //RC Eingang Motor 2
    int pin4 = 4; //RC Eingang Motor 1
    int Bruecke1_a = 6; //H-Brücke 1 vorwärts
    int Bruecke1_b = 5; //H-Brücke 1 rückwärts
    int Bruecke2_a = 10; //H-Brücke 2 vorwärts
    int Bruecke2_b = 9; //H-Brücke 2 rückwärts
    int RCOUT1Wert = 0;
    int RCOUT2Wert = 0;


    unsigned long RCIN1Wert; //Zeitmessung RC Eingang Motor 1
    unsigned long RCIN2Wert; //Zeitmessung RC Eingang Motor 1

    void setup()
    {
    pinMode(pin4, INPUT); //Pin4 als Eingang setzen
    pinMode(pin7, INPUT); //Pin7 als Eingang setzen
    Serial.begin(9600); //Baudrate festlegen
    }

    void loop()
    {
    RCIN1Wert = pulseIn(pin4, HIGH, 26000); //Variable Motor 1
    RCIN2Wert = pulseIn(pin7, HIGH, 26000); //Variable Motor 2

    //Motor 1
    //vorwärts

    if (RCIN1Wert >1549)
    {
    if (RCIN1Wert <2001)
    {
    RCOUT1Wert = map(RCIN1Wert, 1550, 2000, 0, 255); //umrechnen
    analogWrite(Bruecke1_a, RCOUT1Wert); //Setze Motor 1 Vorwärts PWM 0-255
    }
    }

    else
    {
    analogWrite(Bruecke1_a, 0); //Puls nicht zwischen 1549-2001 dann Ausgang aus
    }

    //Motor 1
    //rückwärts

    if (RCIN1Wert <1451)
    {
    if (RCIN1Wert >1000)
    {
    RCOUT1Wert = map(RCIN1Wert, 1000, 1450, 255, 0);
    analogWrite(Bruecke1_b, RCOUT1Wert);
    }
    }

    else
    {
    analogWrite(Bruecke1_b, 0);
    }



    //Diagnose über USB
    // Serial.print("mS = ");
    Serial.print(RCIN1Wert);
    Serial.print(" ");
    Serial.println(RCOUT1Wert);
    // Serial.print(" PWM2 = ");
    // Serial.println(PWM2);
    delay(20);

    }

    Erfahrungen sind was sehr nützliches, leider macht man sie erst kurz nachdem man sie gebraucht hätte...

  • Es Funktioniert :D:D:D:D:D:D:D:D:D:D:D:D:D:D:D:D:D:D:D:D:D:D:D
    Funke aus, ne gefühlte Sekunde warten, Motor ist aus.
    Noch etwas aufräumen kommentieren und Prototypen bauen.
    Eine Stromregelung will ich nicht interpretieren.
    Eine Sicherheit habe ich aber noch eingebaut. Bevor er einen Kanal setzt, resettet er erst den anderen. Das verhindert ein Ansteuern beider Kanäle gleichzeitig -> Kurzschluss.
    Ich sitze ja auch nur seit heute morgen 10Uhr daran :(
    Aber es geht. Nurnoch den zweiten Kanal dazufrickeln und das scharfschalten per Fernbedienung interplementieren.
    Verhindert das Losfahren des Roboters beim einschalten wenn ein Knüppel nicht in der Neutralposition ist.
    Und nein ein Kreutzmischer ist erstmal nicht vorgesehen ;) .


    int pin7 = 7; //RC Eingang Motor 2
    int pin4 = 4; //RC Eingang Motor 1
    int Bruecke1_a = 6; //H-Brücke 1 vorwärts
    int Bruecke1_b = 5; //H-Brücke 1 rückwärts
    int Bruecke2_a = 10; //H-Brücke 2 vorwärts
    int Bruecke2_b = 9; //H-Brücke 2 rückwärts
    int RCOUT1Wert = 0;
    int RCOUT2Wert = 0;


    unsigned long RCIN1Wert; //Zeitmessung RC Eingang Motor 1
    unsigned long RCIN2Wert; //Zeitmessung RC Eingang Motor 1

    void setup()
    {
    pinMode(pin4, INPUT); //Pin4 als Eingang setzen
    pinMode(pin7, INPUT); //Pin7 als Eingang setzen
    Serial.begin(9600); //Baudrate festlegen
    }

    void loop()
    {
    RCIN1Wert = pulseIn(pin4, HIGH, 26000); //Variable Motor 1
    RCIN2Wert = pulseIn(pin7, HIGH, 26000); //Variable Motor 2

    //Motor 1
    //vorwärts

    if (RCIN1Wert >999)
    {
    if (RCIN1Wert <2001)
    {
    if (RCIN1Wert <1421)
    {
    RCOUT1Wert = map(RCIN1Wert, 1000, 1420, 255, 0);
    analogWrite(Bruecke1_b, 0);
    analogWrite(Bruecke1_a, RCOUT1Wert);
    }

    else if (RCIN1Wert >1569)
    {
    RCOUT1Wert = map(RCIN1Wert, 1570, 2000, 0, 255); //umrechnen
    analogWrite(Bruecke1_a, 0);
    analogWrite(Bruecke1_b, RCOUT1Wert); //Setze Motor 1 Vorwärts PWM 0-255
    }

    else
    {
    analogWrite(Bruecke1_a, 0);
    analogWrite(Bruecke1_b, 0);
    }
    }

    }
    else if (RCIN1Wert <999)
    {
    analogWrite(Bruecke1_a, 0);
    analogWrite(Bruecke1_b, 0);
    }


    //Diagnose über USB
    // Serial.print("mS = ");
    Serial.print(RCIN1Wert);
    Serial.print(" ");
    Serial.println(RCOUT1Wert);
    // Serial.print(" PWM2 = ");
    // Serial.println(PWM2);
    //delay(20);

    }

    Erfahrungen sind was sehr nützliches, leider macht man sie erst kurz nachdem man sie gebraucht hätte...

  • //------------------------------------------------//
    //2 Kanal Fahrtregler mit Failsafe und ohne Bremse//
    //------------------------------------------------//

    int pin7 = 7; //RC Eingang Motor 2
    int pin4 = 4; //RC Eingang Motor 1
    int Bruecke1_a = 6; //H-Brücke 1 vorwärts
    int Bruecke1_b = 5; //H-Brücke 1 rückwärts
    int Bruecke2_a = 10; //H-Brücke 2 vorwärts
    int Bruecke2_b = 9; //H-Brücke 2 rückwärts
    int RCOUT1Wert = 0; //Variable für PWM Motor 1
    int RCOUT2Wert = 0; //Variable für PWM Motor 2

    unsigned long RCIN1Wert; //Zeitmessung RC Eingang Motor 1
    unsigned long RCIN2Wert; //Zeitmessung RC Eingang Motor 1


    void setup()
    {
      pinMode(pin4, INPUT); //Pin4 als Eingang setzen
      pinMode(pin7, INPUT); //Pin7 als Eingang setzen
      Serial.begin(115200); //Baudrate festlegen
    }


    void loop()
    {
    RCIN1Wert = pulseIn(pin4, HIGH, 26000); //Variable Motor 1 //Es wird maximal 26000µS gewartet bis ein Impuls anliegt sonst wir übersprungen
    RCIN2Wert = pulseIn(pin7, HIGH, 26000); //Variable Motor 2 //Es wird maximal 26000µS gewartet bis ein Impuls anliegt sonst wir übersprungen
      
      
      //MOTOR 1
      //-----------------------------------------------------------------------------------------------------
      
      if (RCIN1Wert >999) //
    { //
        if (RCIN1Wert <2001) //Ist die Pulsweite zwischen 1000µS und 2000µS
    {
            
            //VORWÄRTS
            
            if (RCIN1Wert <1200) //Der Bereich zwischen 1000µS und 1200µS wird auf 255 gesetzt d.H. Vollgas vorwärts
    {
               analogWrite(Bruecke1_b, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
               analogWrite(Bruecke1_a, 255); //PWM wird geschrieben
    }
             
           else if (RCIN1Wert <1421) //Der Bereich zwischen 1200µS und 1420µS ist zum feinfüligen Regeln
    {
    RCOUT1Wert = map(RCIN1Wert, 1200, 1420, 255, 0); //Zeit PWM Umrechnung
                analogWrite(Bruecke1_b, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
                analogWrite(Bruecke1_a, RCOUT1Wert); //PWM wird geschrieben
    }
             
             //RÜCKWÄRTS
             
           else if (RCIN1Wert >1800) //Der Bereich zwischen 1800µS und 2000µS ist Vollgas rückwärts
    {
               analogWrite(Bruecke1_a, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
               analogWrite(Bruecke1_b, 255); //PWM wird geschrieben
    }
             
           else if (RCIN1Wert >1569)
    {
    RCOUT1Wert = map(RCIN1Wert, 1570, 1800, 0, 255); //Zeit PWM Umrechnung
               analogWrite(Bruecke1_a, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
               analogWrite(Bruecke1_b, RCOUT1Wert); //PWM wird geschrieben
    }
             
             //nullstelle Kanäle aus
             
           else//Bei Werten zwischen 1420µS und 1570µS ist der Nullpunkt
    {
               analogWrite(Bruecke1_a, 0); //Motor aus
               analogWrite(Bruecke1_b, 0); //Motor aus
    }
    }
          
    }
      
      //FAILSAFE
      
      else if (RCIN1Wert <999) //Wenn kein Signal anliegt
    {
            analogWrite(Bruecke1_a, 0);
            analogWrite(Bruecke1_b, 0);
    }

      
      //MOTOR 2
      //-----------------------------------------------------------------------------------------------------
      
      if (RCIN2Wert >999) //
    { //
        if (RCIN2Wert <2001) //Ist die Pulsweite zwischen 1000µS und 2000µS
    {
            
            //VORWÄRTS
            
            if (RCIN2Wert <1200) //Der Bereich zwischen 1000µS und 1200µS wird auf 255 gesetzt d.H. Vollgas vorwärts
    {
               analogWrite(Bruecke2_b, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
               analogWrite(Bruecke2_a, 255); //PWM wird geschrieben
    }
             
           else if (RCIN2Wert <1421) //Der Bereich zwischen 1200µS und 1420µS ist zum feinfüligen Regeln
    {
    RCOUT2Wert = map(RCIN2Wert, 1200, 1420, 255, 0); //Zeit PWM Umrechnung
                analogWrite(Bruecke2_b, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
                analogWrite(Bruecke2_a, RCOUT2Wert); //PWM wird geschrieben
    }
             
             //RÜCKWÄRTS
             
           else if (RCIN2Wert >1800) //Der Bereich zwischen 1800µS und 2000µS ist Vollgas rückwärts
    {
               analogWrite(Bruecke2_a, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
               analogWrite(Bruecke2_b, 255); //PWM wird geschrieben
    }
             
           else if (RCIN2Wert >1569)
    {
    RCOUT2Wert = map(RCIN2Wert, 1570, 1800, 0, 255); //Zeit PWM Umrechnung
               analogWrite(Bruecke2_a, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
               analogWrite(Bruecke2_b, RCOUT2Wert); //PWM wird geschrieben
    }
             
             //nullstelle Kanäle aus
             
           else//Bei Werten zwischen 1420µS und 1570µS ist der Nullpunkt
    {
               analogWrite(Bruecke2_a, 0); //Motor aus
               analogWrite(Bruecke2_b, 0); //Motor aus
    }
    }
          
    }
      
      //FAILSAFE
      
      else if (RCIN2Wert <999) //Wenn kein Signal anliegt
    {
            analogWrite(Bruecke2_a, 0);
            analogWrite(Bruecke2_b, 0);
    }


      
       
      //Diagnose über USB AUsgabe auf den Seriellen Monitor
      //-----------------------------------------------------------------------------------------------------
      
      Serial.print(RCIN1Wert); //RC Kanal 1
      Serial.print(" "); //Leerzeichen
      Serial.print(RCOUT1Wert); //PWM Kanal 1
      Serial.print(" ");
      Serial.print(RCIN2Wert); //RC Kanal 2
      Serial.print(" ");
      Serial.println(RCOUT2Wert); //RC Kanal 1
      
    }

    Erfahrungen sind was sehr nützliches, leider macht man sie erst kurz nachdem man sie gebraucht hätte...

    Einmal editiert, zuletzt von Krümmel (8. Mai 2013 um 11:51)

  • Jetzt fehlt nurnoch das beim Einschalten beide Knüppel mindestens eine Sekunde in der Neutralposition sein müssen um den Regler aktiv zu schalten. Das soll verhinden das der Bot bei Störungen oder beim Vergessen die Funke vorher einzuschalten nicht los rollt.

    Nur wo packe ich das rein? Bei void loop() würde ich ja nach jedem Zyklus immer erst in die Nulstelle müssen bevor ich gasgeben kann.
    Gibt es Variabeln die nur einmal abgearbeitet werden?
    Also das Programm bleibt in einer Vorschleife hängen bis die Zeit abgelaufen ist worin die Knüppel in der Nullstelle sind. Und erst dann läuft der Timer und gibt nach einer Sekunde die Steuerung frei.

    Erfahrungen sind was sehr nützliches, leider macht man sie erst kurz nachdem man sie gebraucht hätte...

    • Offizieller Beitrag

    Zunächst mal Glückwunsch zum funktionsfähigen Programm! Siehste, geht doch ! ;) (... weil Du immer meinst, das ist alles zu kompliziert für Dich... => meinst Du, dass andere Programmierer anders angefangen haben? ;) )

    Ich würde die Neutral-Positionierung vor die jetzige Arbeitsschleife ("loop"..) hineinpacken.
    Die "loop" wird erst dann angesprungen bzw. erreicht, wenn die beiden Knüppel die Vorbedingung erfüllt haben. Und die lautet, dass sowohl RCIN1WERT als auch RCIN2WERT gleichzeitig zwischen 1450 und 1550 sein müssen.

    Es geht zwar eleganter über Flags, aber ich würd's jetzt mal auf die umfangreichere (aber verständlichere) Tour machen: Einfach den Hauptteil von Dir mit den markanten Abfragen in eine separate Subroutine ("void Vorchecking"..) packen. Diese Routine wird solange durchlaufen, bis die o.g. bedingungen erfüllt sind.
    Die Syntax von Arduino kenne ich nicht. Gibt's so etwas wie "while" oder "Do loop .... until (xxx < yyy)" ?

    Wäre dann auf die Art und Weise:
    Do loop
    {
    ..RCIN1Wert = ....
    ..RCIN2Wert = ...
    }
    Until ((RCIN1WERT > 1450) AND (RCIN1WERT < 1550) AND (RCIN2WERT > 1450) AND (RCIN2WERT < 1550))

  • So der Regler gibt kein Gas mehr beim Einschalten. Allerdings ist kein Timer verbaut.
    Ich habe zwei Variabeln und noch ein paar IF Abfragen eingebaut.
    Ist der Knüppel in Nullstellung -> Setze var1 = 1
    Ist var1 = 1 -> Steuerung Kanal 1 freigegeben
    usw.

    Zeit mal eine kleine testplatiene zu bauen.
    Ist das bremsen der Motoren eigentlich sinnvoll?
    Sonst muss ich meine Steuerung umarbeiten und eine andere Ansteuerung der H-Brücke nehmen.

    Erfahrungen sind was sehr nützliches, leider macht man sie erst kurz nachdem man sie gebraucht hätte...

    • Offizieller Beitrag
    Zitat

    Ist das bremsen der Motoren eigentlich sinnvoll?


    Für Ants eigentlich weniger, weil die kleinen Stirnradgetriebe genügend Selbsthemmung haben.

    Wenn Du Akkuschraubermotoren oder noch etwas Gewichtigeres einsetzen willst, dann solltest Du eine Bremse einbauen.

    Was in Deiner Software noch fehlt: Du solltest beim Richtungswechsel eine Verzögerungszeit mit vorsehen. Bei etwas kräftigeren MOSFETs werden sonst u.U. die gegenüberliegenden MOSFETs gleichzeitig angesteuert.
    Also: aktiven MOSFET abschalten (Gate auf GND legen) => 3uSek warten => anderen MOSFET anschalten.

  • Reicht das gegeneinander verriegeln nicht?
    analogWrite(Bruecke1_b, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
    analogWrite(Bruecke1_a, RCOUT1Wert); //PWM wird geschrieben
    Oder wegen der Trägheit der MOSFETs? Welche Frequenz nimmt man denn zum ansteuern?
    480Hz sind zu wenig oder?

    Erfahrungen sind was sehr nützliches, leider macht man sie erst kurz nachdem man sie gebraucht hätte...

    • Offizieller Beitrag

    Yep, die "Trägheit" der MOSFETs ist's. Auch wenn Du das Gate auf Null setzt, bleibt der MOSFET noch ein paar Mikrosekunden durchgesteuert.

    Gibt es beim Arduino einen "NOP"-Befehl ? (Da tritt der Prozessor für einen Taktzyklus auf der Stelle.

    analogWrite(Bruecke1_b, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
    NOP
    NOP
    NOP
    analogWrite(Bruecke1_a, RCOUT1Wert); //PWM wird geschrieben


    Ich benutzte anfangs immer 4Khz zum Ansteuern, aber die Akkuschraubermotoren hören sich dann irgendwie nicht so gesund an. Aktuell mit 1kHz betrieben. Ist besser. Die Conrad-Fahrtregler benutzen 500Hz. Würde bei Dir also auch passen.

  • So alle 4 Ausgänge laufen jetzt auf knapp 1KHz und ich habe wie du meintest jetzt eine 3 microsekunden Pause eingebaut.
    Edit: Den Failsafe noch etwas verbessert (nicht unten drin)


    //------------------------------------------------//
    //2 Kanal Fahrtregler mit Failsafe und ohne Bremse//
    //------------------------------------------------//

    int pin7 = 7; //RC Eingang Motor 2
    int pin4 = 4; //RC Eingang Motor 1
    int Bruecke1_a = 6; //H-Brücke 1 vorwärts
    int Bruecke1_b = 5; //H-Brücke 1 rückwärts
    int Bruecke2_a = 3; //H-Brücke 2 vorwärts
    int Bruecke2_b = 11; //H-Brücke 2 rückwärts
    int RCOUT1Wert = 0; //Variable für PWM Motor 1
    int RCOUT2Wert = 0; //Variable für PWM Motor 2
    int var1 = 0; //Freigabe Motor 1
    int var2 = 0; //Freigabe Motor 2


    unsigned long RCIN1Wert; //Zeitmessung RC Eingang Motor 1
    unsigned long RCIN2Wert; //Zeitmessung RC Eingang Motor 1


    void setup()
    {
      pinMode(pin4, INPUT); //Pin4 als Eingang setzen
      pinMode(pin7, INPUT); //Pin7 als Eingang setzen
      Serial.begin(115200); //Baudrate festlegen für die Werteausgabe
      pinMode(3, OUTPUT);
      pinMode(11, OUTPUT);
    TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); //Standartmäßig laufen die Kanäle 3 und 11 auf 490HZ und nicht auf 975,6Hz[/color]
    TCCR2B = _BV(CS22); //Setzt die Frequenz auf 975,6Hz[/color]
      
    OCR2A = 0; //Setzt die PWM auf 0 +1
    OCR2B = 0; //Setzt die PWM auf 0 +1
      analogWrite(Bruecke2_a, 0); //Setzt die PWM wirklich auf 0
      analogWrite(Bruecke2_b, 0); //ditto
      
    }


    void loop()
    {
    RCIN1Wert = pulseIn(pin4, HIGH, 26000); //Variable Motor 1 //Es wird maximal 26000µS gewartet bis ein Impuls anliegt sonst wir übersprungen
    RCIN2Wert = pulseIn(pin7, HIGH, 26000); //Variable Motor 2 //Es wird maximal 26000µS gewartet bis ein Impuls anliegt sonst wir übersprungen
      
      
      if (RCIN1Wert <1568 && RCIN1Wert >1420) //Ist Kanal 1 in Nulstellung
    {
    var1 = 1; //wird das Bit auf 1 gesetzt und der Kanal wird freigegeben
    }
       
       if (RCIN2Wert <1568 && RCIN2Wert >1420) //Ist Kanal 2 in Nulstellung
    {
    var2 = 1; //wird das Bit auf 1 gesetzt und der Kanal wird freigegeben
    }
      
      
      //Diagnose über USB AUsgabe auf den Seriellen Monitor
      //-----------------------------------------------------------------------------------------------------
      
      Serial.print(RCIN1Wert); //RC Kanal 1
      Serial.print(" "); //Leerzeichen
      Serial.print(RCOUT1Wert); //PWM Kanal 1
      Serial.print(" ");
      Serial.print(RCIN2Wert); //RC Kanal 2
      Serial.print(" ");
      Serial.print(RCOUT2Wert); //RC Kanal 2
      Serial.print(" ");
      Serial.print(var1);
      Serial.print(" ");
      Serial.println(var2);
      
      
      if (var1 == 1)
    {
      //MOTOR 1
      //-----------------------------------------------------------------------------------------------------
      
      if (RCIN1Wert >999) //
    { //
        if (RCIN1Wert <2001) //Ist die Pulsweite zwischen 1000µS und 2000µS
    {
            
            //VORWÄRTS
            
            if (RCIN1Wert <1200) //Der Bereich zwischen 1000µS und 1200µS wird auf 255 gesetzt d.H. Vollgas vorwärts
    {
               analogWrite(Bruecke1_b, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
               delayMicroseconds(3);
               analogWrite(Bruecke1_a, 255); //PWM wird geschrieben
    }
             
           else if (RCIN1Wert <1421) //Der Bereich zwischen 1200µS und 1420µS ist zum feinfüligen Regeln
    {
    RCOUT1Wert = map(RCIN1Wert, 1200, 1420, 255, 0); //Zeit PWM Umrechnung
                analogWrite(Bruecke1_b, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
                delayMicroseconds(3);
                analogWrite(Bruecke1_a, RCOUT1Wert); //PWM wird geschrieben
    }
             
             //RÜCKWÄRTS
             
           else if (RCIN1Wert >1800) //Der Bereich zwischen 1800µS und 2000µS ist Vollgas rückwärts
    {
               analogWrite(Bruecke1_a, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
               delayMicroseconds(3);
               analogWrite(Bruecke1_b, 255); //PWM wird geschrieben
    }
             
           else if (RCIN1Wert >1569)
    {
    RCOUT1Wert = map(RCIN1Wert, 1570, 1800, 0, 255); //Zeit PWM Umrechnung
               analogWrite(Bruecke1_a, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
               delayMicroseconds(3);
               analogWrite(Bruecke1_b, RCOUT1Wert); //PWM wird geschrieben
    }
             
             //nullstelle Kanäle aus
             
           else//Bei Werten zwischen 1420µS und 1570µS ist der Nullpunkt
    {
               analogWrite(Bruecke1_a, 0); //Motor aus
               analogWrite(Bruecke1_b, 0); //Motor aus
    }
    }
          
    }
      
      //FAILSAFE
      
      else if (RCIN1Wert <999) //Wenn kein Signal anliegt
    {
            analogWrite(Bruecke1_a, 0);
            analogWrite(Bruecke1_b, 0);
    }

    }
      //MOTOR 2
      //-----------------------------------------------------------------------------------------------------
      
      if (var2 == 1)
    {
      
      if (RCIN2Wert >999) //
    { //
        if (RCIN2Wert <2001) //Ist die Pulsweite zwischen 1000µS und 2000µS
    {
            
            //VORWÄRTS
            
            if (RCIN2Wert <1200) //Der Bereich zwischen 1000µS und 1200µS wird auf 255 gesetzt d.H. Vollgas vorwärts
    {
               analogWrite(Bruecke2_b, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
               delayMicroseconds(3);
               analogWrite(Bruecke2_a, 255); //PWM wird geschrieben
    }
             
           else if (RCIN2Wert <1421) //Der Bereich zwischen 1200µS und 1420µS ist zum feinfüligen Regeln
    {
    RCOUT2Wert = map(RCIN2Wert, 1200, 1420, 255, 0); //Zeit PWM Umrechnung
                analogWrite(Bruecke2_b, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
                delayMicroseconds(3);
                analogWrite(Bruecke2_a, RCOUT2Wert); //PWM wird geschrieben
    }
             
             //RÜCKWÄRTS
             
           else if (RCIN2Wert >1800) //Der Bereich zwischen 1800µS und 2000µS ist Vollgas rückwärts
    {
               analogWrite(Bruecke2_a, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
               delayMicroseconds(3);
               analogWrite(Bruecke2_b, 255); //PWM wird geschrieben
    }
             
           else if (RCIN2Wert >1569)
    {
    RCOUT2Wert = map(RCIN2Wert, 1570, 1800, 0, 255); //Zeit PWM Umrechnung
               analogWrite(Bruecke2_a, 0); //Gegenfahrtrichtung wird auf 0 gesetzt
               delayMicroseconds(3);
               analogWrite(Bruecke2_b, RCOUT2Wert); //PWM wird geschrieben
    }
             
             //nullstelle Kanäle aus
             
           else//Bei Werten zwischen 1420µS und 1570µS ist der Nullpunkt
    {
               analogWrite(Bruecke2_a, 0); //Motor aus
               analogWrite(Bruecke2_b, 0); //Motor aus
    }
    }
          
    }
      
      //FAILSAFE
      
      else if (RCIN2Wert <999) //Wenn kein Signal anliegt
    {
            analogWrite(Bruecke2_a, 0);
            analogWrite(Bruecke2_b, 0);
    }
      
    }
    }

    Erfahrungen sind was sehr nützliches, leider macht man sie erst kurz nachdem man sie gebraucht hätte...

    2 Mal editiert, zuletzt von Krümmel (9. Mai 2013 um 14:57)

  • Hier noch ein Beweisvideo das es auch funktioniert.
    http://www.youtube.com/watch?v=mqKOxUhvmdc&feature=youtu.be

    Jetzt muss die Hardware dran.
    -Die H-Brücke sollte mindestens 20A pro Kanal ab können. Es werden vermutlich zwei Motoren parallel angeschlossen.
    -Zwei (drei) eingänge (vorwärts, rückwärts, bremsen)
    -Mosfets möglichst in TO220 bauweise (kann keine Platienen ätzen)

    Wie entstöre ich die Motoren oder reicht es das am Regler zu tun?
    Wie sicher ich den Regler im falle eines Kurzschlusses ab (Motorkurzschluss)?
    Muss ich bei 1KHz die Mosfets mit pushpull ansteuern?

    Ich denke da kommen noch einige Fragen.


    Reiner ich sehe gerade du steuerst jeden Mosfet einzeln an. Das ist bei mir leider nicht möglich. Zumindest nicht alle mit PWM. Pro H-Brücke könnte ich nur zwei mit PWM und zwei mit 1 und 0 ansteuern. Heist ein Mosfets wäre immer durchgesteuert und der andere würde eine PWM bekommen. Geht das so?
    Ich habe nämlich nur 6PWM ausgänge und 8 IO Kanäle.
    Warum Optokoppler? Für einen möglichen Fehlerfall den Prozessor zu schützen?

    Meine Idee wäre jetzt die beiden highside Mosfets je nach Fahrtrichtung auf 1 zu setzen und die lowside Mosfets mit einer PWM anzusteuern. Somit wäre über die lowside eine PWM Bremse möglich.

    Bremst du bei deinen Reglern über eine Rampe oder einen festen Wert? Was hat Vor- und Nachteile.

    Erfahrungen sind was sehr nützliches, leider macht man sie erst kurz nachdem man sie gebraucht hätte...

    2 Mal editiert, zuletzt von Krümmel (9. Mai 2013 um 19:31)

    • Offizieller Beitrag

    > Mosfets möglichst in TO220 bauweise --> IRF1405 (guter und preiswerter N-Kanal-Typ mit etwa 5mOhm RDS-On)

    > Wie entstöre ich die Motoren oder reicht es das am Regler zu tun? --> Motoren: wie üblich (siehe diverse Threads)
    den Regler entstörst du, indem du die Totzeit gering hälst, die Brücke induktivitätsarm aufbaust (GANZ KURZE Pinne und Drähte (Leiterbahnen) !!!) und an den pssenden Stellen Abblock-Kondis einsetzt.
    Wenn es gut gemacht ist, ist hier ein "fliegender" Aufbau deutlich besser als ein Layout. Du kannst dann recht einfach dreidimensional bauen, dass verringert die "Drahtlängen" und damit die Induktivität der Brücke.


    > Wie sicher ich den Regler im falle eines Kurzschlusses ab (Motorkurzschluss)? --> Sicherung in der +Batterie-Leitung der H-Brücke
    Du solltest dir mehr Gedanken über Cross-Conduction als über Motorkutzschluss machen!!!

    > Muss ich bei 1KHz die Mosfets mit pushpull ansteuern? --> hmpf ... wieder die gruseligen 1kHz... ich sag nur STROMRIPPEL!! --> Threads nachlesen
    wenn die Totzeit gross genug ist (dürfte ohne vernünftige Treiber bei 5µs - 50µs liegen) geht es auch ohne Push-Pull, allerdings mit erhöhter Verlustleistung in den FETs (grösserer Kühlkörper notwendig)

    > Pro H-Brücke könnte ich nur zwei mit PWM und zwei mit 1 und 0 ansteuern. Heist ein Mosfets wäre immer durchgesteuert und der andere würde eine PWM bekommen. Geht das so?
    Das geht schon, ist aber äusserst unschön...
    Grund: die Body-Diode des nicht angesteuerten High-Side-FET leitet, wenn der Low-Side Fet nicht leitet (Freilaufstrom)
    bei 20A max Brückenstrom und ca. 1V Flusspannung der Body-Diode sind das bei 50% Tastverhältnis ca. 10W, die der FET verbrät...

    normalerweise wird hier ein High-Side-FET angesteuert und die High- und Low-Side-Fets der anderen Halbbrücke werden abwechselnd angesteuert (es leitet immer einer der FETS dieser Halbbrücke)

    > Warum Optokoppler? Für einen möglichen Fehlerfall den Prozessor zu schützen?--> eher, um den teuren Empfänger zu schützen *grins*


    Generelle Frage:
    Hast Du Dir schon Gedanken gemacht, ob du eine P-Channel/N-Channel Kombination oder nur N-CHannel für eine Halbbrücke verwenden willst?

  • Wie ich die Brücke ansteuer steht noch nicht ganz fest. Ich habe halt nur 6 PWM Ausgänge für zwei H-Brücken.
    Ich könnte ja immer über Kreutz zwei MOSFETs ansteuern. Hätte aber den nachteil von der fehleneden Bremse. Die Frequenz könnte ich noch hoch oder runter setzen. Allerdings müste ich mich damit dann noch auseinandersetzen.
    Bei dem Aufbau der H-Brücken bin ich frei für Ideen.
    Ich habe bei Reiners Regler mal gespickt und denke ich werde die MOSFET-Treiber übernehmen.

    Erfahrungen sind was sehr nützliches, leider macht man sie erst kurz nachdem man sie gebraucht hätte...

    • Offizieller Beitrag
    Zitat

    Ich könnte ja immer über Kreutz zwei MOSFETs ansteuern Hätte aber den nachteil von der fehleneden Bremse


    fehlende Bremse: nö... die ansteuerung nennt sich "locked-antiphase-drive". damit kriegt man die härteste art der bremse überhaupt hin! man kann den motor mit negativem strom (aus sicht der aktuellen drehrichtung) abbremsen. schneller bremsen geht auch mit motorkurzschluss nicht :D:D:D

    zur brücke:
    - P/N-Kombination:
    vorteil: einfachere ansteuerung der FET's
    nachteil: P-Fets sind schlechter als N-FET's

    - Nur N-FET's:
    Vorteil: leistungsfähigere N-FET's erhältlich als P-FET's
    Nachteil:
    aufwändigere ansteuerung. für die high-side-FET's muss eine spannung von 10-15V ÜBER der Batteriespannung erzeugt werden (eine Variante nennt sich "Bootstraping")