RC Empfänger, 3 H-Brücken in Abhängigkeit des Ruders steuern, PWM Frequenz ?

Nachdem ich mir mehrere Nächte um die Ohren gehauen habe hier mal das Ergebnis. Der Arduino Nano liest den Kanal 1 (Fahrgeschwindigkeit) und den Kanal 4 (Ruderanlenkung) ein. Jede H-Brücke steuert einen Wellenmotor an. Je nach Ruderausschlag wird eine der äußeren Schrauben stufenlos gebremst. Die Abfrage bzw. das Einlesen der Empfängerkanäle erfolgt mittels Polling. Die Variante mit Interrupt funktioniert nicht zuverlässig, vermutlich liegts am PWM, welches ich an drei digitalen Ausgangspins für die H-Brücken brauche. Leider pfeifen auch die Motoren, weil die Frequenz zu niedrig ist. Ein manuelles anpassen der Timer hat nix gebracht, denn das bringt die Biblothek durcheinander. Die eingesetzten Biblotheken stammen von Wilfried Klaas, zu welchem ich leider keinen Kontakt herstellen kann. Hab auch schon versucht die Frequenz per SoftwarePWM Library einzustellen, aber das schafft der Arduino nicht mehr und die PWM Signale ruckeln, Vielleicht hat ja jemand eine Idee oder eventuell Kontakt zu Willi. Code im nächsten Post

/*
  RC_Template.ino - Template for RC Receiver enabled programs interrupt version - Version 0.2
 Copyright (c) 2014 Wilfried Klaas.  All right reserved.
 
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.
 
 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
 
// Achtung auf Grund der Bibilothek funktioniert PWM nur auf PIN 3, 5, 6, 11 und 3 ist schon belegt
// Es können nur zwei Kanäle ausgelesen werden diese müssen immer an digital 2 und 3 am Arduino

#include "makros.h"
#include "debug.h"
#include "RCReceive.h" 
 
int Bruecke1_a     = 4;  //Motor rechts H-Brücke 1 Richtungsvorgabe mit LOW oder HIGH
int Bruecke1_b     = 9;  //Motor rechts H-Brücke 1 Richtungsvorgabe mit LOW oder HIGH
int Bruecke1_ENA   = 5;  //Motor rechts PWM Eingang der H-Brücke

int Bruecke2_a     = 7;  //Motor links H-Brücke 1 Richtungsvorgabe mit LOW oder HIGH
int Bruecke2_b     = 8;  //Motor links H-Brücke 1 Richtungsvorgabe mit LOW oder HIGH
int Bruecke2_ENA   = 6;  //Motor links PWM Eingang der H-Brücke

int Bruecke3_a     = 10; //Motor mitte H-Brücke 1 Richtungsvorgabe mit LOW oder HIGH
int Bruecke3_b     = 12; //Motor mitte H-Brücke 1 Richtungsvorgabe mit LOW oder HIGH
int Bruecke3_ENA   = 11; //Motor mitte PWM Eingang der H-Brücke

int RCOUT1Wert         = 0;
int RCOUT2Wert         = 0;
int RCOUT1_2Berechnung = 0;

const byte PIN_RC1   = 2; //RC Eingang Geschwindigkeit Kanal 1 vom Empfänger
const byte PIN_RC2   = 3; //RC Eingang Lenkung Kanal 4 vom Empfänger

RCReceive rcReceiver;    // Der Empfänger der Befehl muss rein
RCReceive servoReceiver; // Jeder Kanal der ausgelesen wird bekommt einen Namen hier rcReceiver ist Kanal 1 und servoReceiver ist Kanal 4 auf der Fernbedienung

void setup() 
{


rcReceiver.attach(PIN_RC1);         // RC Receiver wird in Polling oder Interruptvariante gelesen atachInt ist Interrupt atach ist Polling
servoReceiver.attach(PIN_RC2);      // RC Receiver wird in Polling oder Interruptvariante gelesen atachInt ist Interrupt atach ist Polling
  

Serial.begin(9600);                    // Baudrate für serielle Konsole festlegen

// Wird weiterer Setup-Code benötigt dann kommt der hier rein
}
void loop() 

{
  rcReceiver.poll();                // Befehl für polling am rcReceiver
  servoReceiver.poll();             // Befehl für polling am servoReceiver
   
  if (rcReceiver.hasNP() && !rcReceiver.hasError())   // nur wenn der Nullpunkt bestimmt worden ist, 
  {                                                   // und es keinen Fehler gegeben hat
    doWork();                                         // soll die eigentliche Arbeit gemacht werden
  } 
  else if (rcReceiver.hasError())                     // Wenn ein Fehler am Empfänger vorliegt,
  {
    // Dann kommt hier der Code für die Fehlerbehandlung wie failsafe oder sowas...
    
    analogWrite(Bruecke1_ENA, 0);       // H-Brücke wird beim Failsafe abgeschaltet
    digitalWrite(Bruecke1_a, LOW);      // H-Brücke wird beim Failsafe abgeschaltet
    digitalWrite(Bruecke1_b, LOW);      // H-Brücke wird beim Failsafe abgeschaltet
    
    analogWrite(Bruecke2_ENA, 0);       // H-Brücke wird beim Failsafe abgeschaltet
    digitalWrite(Bruecke2_a, LOW);      // H-Brücke wird beim Failsafe abgeschaltet
    digitalWrite(Bruecke2_b, LOW);      // H-Brücke wird beim Failsafe abgeschaltet
    
    analogWrite(Bruecke3_ENA, 0);       // H-Brücke wird beim Failsafe abgeschaltet
    digitalWrite(Bruecke3_a, LOW);      // H-Brücke wird beim Failsafe abgeschaltet
    digitalWrite(Bruecke3_b, LOW);      // H-Brücke wird beim Failsafe abgeschaltet
  }
}

void doWork() 
{
  // Hier kommt der Hauptcode also der Programmablauf rein

int Millisekunden  = rcReceiver.getMsValue();    // Holt den aktuellen gemittelten Wert in ms von Kanal 1 Geschwindigkeit
int Millisekunden2 = servoReceiver.getMsValue(); // Holt den aktuellen gemittelten Wert in ms von Kanal 4 Lenkung  
  
//Motor links und rechts bzw. H-Brücke
//vorwärts

if ((Millisekunden >1549)&&(Millisekunden <2100)&&(Millisekunden2 <1440)&&(Millisekunden2 >1340)) // Wenn der aktuell geholte, gemittelte Wert in Millisekunden am Empfänger Kanal 1
{                                                                                                 // zwischen 1549 und 2100 liegt und der Wert am Kanal 2 zwischen 1440 und 1340 liegt, dann
  
RCOUT1Wert = map(Millisekunden, 1550, 2100, 75, 255); // wird der Wert zwischen 1550 und 2095 umgerechnet (gemappt) auf den Bereich 0-255
analogWrite(Bruecke1_ENA, RCOUT1Wert);                // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke1_a, LOW);                        // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke1_b, HIGH);                       // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
analogWrite(Bruecke2_ENA, RCOUT1Wert);                // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke2_a, LOW);                        // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke2_b, HIGH);                       // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
analogWrite(Bruecke3_ENA, RCOUT1Wert);                // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke3_a, LOW);                        // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke3_b, HIGH);                       // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt

}

muss Code teilen

//Motor links und rechts bzw. H-Brücke
//vorwärts Linkslenkung

else if ((Millisekunden >1549)&&(Millisekunden <2100)&&(Millisekunden2 >1440))  // Wenn der aktuell geholte, gemittelte Wert in Millisekunden am Empfänger Kanal 1
{                                                                               // zwischen 1549 und 2100 liegt und der Wert am Kanal 2 größer 1440 ist, dann
  
RCOUT1Wert = map(Millisekunden, 1550, 2100, 75, 255);       // wird der Wert zwischen 1550 und 2095 umgerechnet (gemappt) auf den Bereich 0-255
RCOUT2Wert = map(Millisekunden2, 1440, 1600, 0, 255);       // wird der Wert zwischen 1550 und 2095 umgerechnet (gemappt) auf den Bereich 0-255
RCOUT1_2Berechnung = RCOUT1Wert - RCOUT2Wert;
RCOUT1_2Berechnung = constrain(RCOUT1_2Berechnung, 0, 255); // begrenzt den berechnet Wert auf maximal 255
analogWrite(Bruecke1_ENA, RCOUT1Wert);                      // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke1_a, LOW);                              // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke1_b, HIGH);                             // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
analogWrite(Bruecke2_ENA, RCOUT1_2Berechnung);              // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke2_a, LOW);                              // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke2_b, HIGH);                             // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
analogWrite(Bruecke3_ENA, RCOUT1Wert);                      // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke3_a, LOW);                              // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke3_b, HIGH);                             // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
}

//Motor links und rechts bzw. H-Brücke
//vorwärts Rechtslenkung

else if ((Millisekunden >1549)&&(Millisekunden <2100)&&(Millisekunden2 <1340))  // Wenn der aktuell geholte, gemittelte Wert in Millisekunden am Empfänger Kanal 1
{                                                                               // zwischen 1549 und 2100 liegt und der Wert am Kanal 2 kleiner 1340 ist, dann
  
RCOUT1Wert = map(Millisekunden, 1550, 2100, 75, 255);       // wird der Wert zwischen 1550 und 2095 umgerechnet (gemappt) auf den Bereich 0-255
RCOUT2Wert = map(Millisekunden2, 1340, 1129, 0, 255);       // wird der Wert zwischen 1550 und 2095 umgerechnet (gemappt) auf den Bereich 0-255
RCOUT1_2Berechnung = RCOUT1Wert - RCOUT2Wert;
RCOUT1_2Berechnung = constrain(RCOUT1_2Berechnung, 0, 255); // begrenzt den berechnet Wert auf maximal 255
analogWrite(Bruecke1_ENA, RCOUT1_2Berechnung);              // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke1_a, LOW);                              // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke1_b, HIGH);                             // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
analogWrite(Bruecke2_ENA, RCOUT1Wert);                      // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke2_a, LOW);                              // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke2_b, HIGH);                             // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
analogWrite(Bruecke3_ENA, RCOUT1Wert);                      // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke3_a, LOW);                              // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke3_b, HIGH);                             // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
}

//Motor links bzw. H-Brücke
//rückwärts

else if ((Millisekunden <1451)&&(Millisekunden >885)&&(Millisekunden2 <1440)&&(Millisekunden2 >1340)) // Wenn der aktuell geholte, gemittelte Wert in Millisekunden am Empfänger Kanal 1
{                                                                                                     // zwischen 1451 und 896 liegt und der Wert am Kanal 2 zwischen 1340 und 1440 ist, dann


  
RCOUT1Wert = map((Millisekunden), 885, 1450, 255, 0); // wird der Wert zwischen 895 und 1450 umgerechnet (gemappt) auf den Bereich 255-0
analogWrite(Bruecke1_ENA, RCOUT1Wert);                // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke1_a, HIGH);                       // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt                       
digitalWrite(Bruecke1_b, LOW);                        // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
analogWrite(Bruecke2_ENA, RCOUT1Wert);                // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke2_a, HIGH);                       // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke2_b, LOW);                        // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
analogWrite(Bruecke3_ENA, RCOUT1Wert);                // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke3_a, HIGH);                       // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke3_b, LOW);                        // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
}
//Motor links und rechts bzw. H-Brücke
//rückwärts Linkslenkung

else if ((Millisekunden <1451)&&(Millisekunden >885)&&(Millisekunden2 >1440))  // Wenn der aktuell geholte, gemittelte Wert in Millisekunden am Empfänger Kanal 1
{                                                                              // zwischen 1451 und 895 liegt und der Wert am Kanal 2 größer 1440 ist, dann
  
RCOUT1Wert = map((Millisekunden), 885, 1450, 255, 0);       // wird der Wert zwischen 1550 und 2095 umgerechnet (gemappt) auf den Bereich 0-255
RCOUT2Wert = map(Millisekunden2, 1440, 1600, 0, 255);       // wird der Wert zwischen 1550 und 2095 umgerechnet (gemappt) auf den Bereich 0-255
RCOUT1_2Berechnung = RCOUT1Wert - RCOUT2Wert;
RCOUT1_2Berechnung = constrain(RCOUT1_2Berechnung, 0, 255); // begrenzt den berechnet Wert auf maximal 255
analogWrite(Bruecke1_ENA, RCOUT1_2Berechnung);              // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke1_a, HIGH);                             // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke1_b, LOW);                              // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
analogWrite(Bruecke2_ENA, RCOUT1Wert);                      // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke2_a, HIGH);                             // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke2_b, LOW);                              // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
analogWrite(Bruecke3_ENA, RCOUT1Wert);                      // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke3_a, HIGH);                             // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke3_b, LOW);                              // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
}

//Motor links und rechts bzw. H-Brücke
//rückwärts Rechtslenkung

else if ((Millisekunden <1451)&&(Millisekunden >885)&&(Millisekunden2 <1340))  // Wenn der aktuell geholte, gemittelte Wert in Millisekunden am Empfänger Kanal 1
{                                                                              // zwischen 1451 und 895 liegt und der Wert am Kanal 2 kleiner 1340 ist, dann
  
RCOUT1Wert = map((Millisekunden), 885, 1450, 255, 0);       // wird der Wert zwischen 1550 und 2095 umgerechnet (gemappt) auf den Bereich 0-255
RCOUT2Wert = map(Millisekunden2, 1340, 1129, 0, 255);       // wird der Wert zwischen 1550 und 2095 umgerechnet (gemappt) auf den Bereich 0-255
RCOUT1_2Berechnung = RCOUT1Wert - RCOUT2Wert;
RCOUT1_2Berechnung = constrain(RCOUT1_2Berechnung, 0, 255); // begrenzt den berechnet Wert auf maximal 255
analogWrite(Bruecke1_ENA, RCOUT1Wert);                      // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke1_a, HIGH);                             // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke1_b, LOW);                              // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
analogWrite(Bruecke2_ENA, RCOUT1_2Berechnung);              // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke2_a, HIGH);                             // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke2_b, LOW);                              // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
analogWrite(Bruecke3_ENA, RCOUT1Wert);                      // Der berechnete Wert wird als PWM-Wert geschrieben für die Drehzahl des Motors
digitalWrite(Bruecke3_a, HIGH);                             // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
digitalWrite(Bruecke3_b, LOW);                              // Hier wird mit dem LOW bzw. HIGH-Pegel die Drehrichtung bestimmt
}

else

{
analogWrite(Bruecke1_ENA, 0);                       // ist der Steuerknüppel im Nullpunkt bzw. 
digitalWrite(Bruecke1_a, LOW);                      // zwischen dem Wert 1451 und 1549
digitalWrite(Bruecke1_b, LOW);                      // dann wird die H-Brücke abgeschaltet

analogWrite(Bruecke2_ENA, 0);                       // ist der Steuerknüppel im Nullpunkt bzw. 
digitalWrite(Bruecke2_a, LOW);                      // zwischen dem Wert 1451 und 1549
digitalWrite(Bruecke2_b, LOW);                      // dann wird die H-Brücke abgeschaltet

analogWrite(Bruecke3_ENA, 0);                       // ist der Steuerknüppel im Nullpunkt bzw.
digitalWrite(Bruecke3_a, LOW);                      // zwischen dem Wert 1451 und 1549
digitalWrite(Bruecke3_b, LOW);                      // dann wird die H-Brücke abgeschaltet
}

//Serial.println(Millisekunden);                    // Kontrolle über serielle Konsole
//Serial.println(" ");                              // wird nur zum einstellen der Parameter gebraucht und sonst auskommentiert
//Serial.println(Millisekunden2);                   
//Serial.println(" ");                             
//Serial.println(RCOUT1Wert);                         
//Serial.println(" ");
//Serial.println(RCOUT2Wert);                    
//Serial.println(" ");       
//Serial.println(RCOUT1_2Berechnung);                    
//Serial.println(" ");       
}

Führst Du gerne Selbstgespräche? ;-)

Versuche mal, die einzelnen Probleme auch einzeln anzugehen, nicht gleich alles auf einmal in einem Sketch.

Ich vermute einen grundsätzliches Problem in Deiner Ansteuerung der H-Brücken. Bruecke1_ENA klingt nach "enable", da sollte IMO kein PWM Signal draufgehen. Wenn die Brücke zwei (komplementäre) PWM Signale auf a und b erwartet, einen Inverter dazwischenschalten. Dann sind die Treiber ständig eingeschaltet. Mit PWM auf ENA werden die Treiber nur während der Impulszeit (HIGH) eingeschaltet, während der Pause dawzischen abgeschaltet. Der Effekt ist in beiden Fällen ähnlich, aber nicht gleich, und könnte das Pfeifen der Motoren erklären. Schon mal ausprobiert?

Die H-Brücken die ich verwende sind folgende Bausteine. http://www.ebay.de/itm/5pcs-L298N-Stepper-Motor-Driver-Module-Dual-H-Bridge-Control-Board-for-Arduino-/251609046410?hash=item3a95115d8a

Zur Drehzahlregelung wird an ENA ein PWM Signal angelegt und an Int1 bzw. Int2 wechselseitig HIGH LOW zur Bestimmung der Drehrichtung. Wenn ich die PWM Frequenz mit einem anderen Sketch erhöhe, dann ist das Pfeifen weg. So wird das bei fertigen Fahrtreglern IMHO auch gemacht die laufen mit 18 khz. Da pfeift nix.