Bremslicht für RC-Auto programmieren

Hallo zusammen,

ich bin noch recht neu hier und versuche gerade, ein Bremslicht für mein RC-Elektroauto zu programmieren. Mein RC-Empfänger ist mein digitaler Input, dessen Gaskanal-Werte laut Arduino UNO bei Vollgas bei etwa 2000, in der Neutralstellung bei etwa 1500 und bei vollem Rückwärtsgang bei ca. 1000 liegen. Die Motorbremse an meinem RC-Auto wird standardmäßig ausgelöst, wenn ich von „Vorwärtsgas“ direkt in den „Rückwärtsgang“ schalte (sieht und hört man auf dem Video: RC Motorbremse Demonstration - YouTube). Erst wenn ich wieder kurz in Neutralstellung gehe, wird die Bremse „gelöst“ und man kann jetzt wieder vorwärts oder rückwärts fahren.
Mein Problem ist nun folgendes: egal ob mein Motor gerade bremst oder rückwärts fährt, der Arduino liest als Wert bei beiden Szenarien ca. 1000. Allein von den Zahlen her kann mein Arduino also nicht zwischen Bremsen und Rückwärtsfahren unterscheiden. Meine Idee ist nun, eine spezielle if Bedingung zu programmieren, um den Bremsvorgang detektieren zu können. Mein Code sähe in Worte formuliert etwa so aus: if EmpfängerInput innerhalb von 300 Millisekunden (solange dauert es ungefähr physisch, den Gashebel von vorwärts auf rückwärts zu schieben) von einem Wert >1500 zu einem Wert <1500 springt, dann BremslichtLEDPin solange auf HIGH stellen, bis EmpfängerInput wieder =1500 beträgt. Sprich, BremslichtLEDPin erst wieder auf LOW schalten, wenn die Neutralstellung (ca. 1500) wieder erreicht ist.

Ich hoffe, man kann meiner Schilderung folgen, bei Unklarheiten gerne nachfragen. Könnt ihr mir helfen, wie und mit welchen Befehlen man das so Programmieren könnte? Danke im Voraus!

Im englischen Teil des Forum müssen die Beiträge und Diskussionen in englischer Sprache verfasst werden. Deswegen wurde diese Diskussion in den deutschen Teil des Forums verschoben.

mfg ein Moderator.

Eigentlich hast doch alles schon gesagt - Bedingung nehmen, daraus eine Funktion bauen und gut.

Wenn Du mehr willst, musst Deinen Code zeigen, damit man etwas hat, auf was zurückgegriffen werden kann.

Da ist doch was :wink:

Mit welchen Befehlen kann ich definieren, dass ein Wert von >1500 mein Ausgangspunkt sein soll und von diesem aus innerhalb von 300 Millisekunden ein Wert von <1500 erreicht werden soll? Da weiß ich nicht wie ich das als Code formulieren soll …

Mein Code ist bis jetzt noch nicht lang, bis jetzt ließt er nur drei Kanäle vom Empfänger aus. Für das Bremslicht kann man aber natürlich Kanal 1 und 3 ignorieren.

int CH[3];

void setup() {
  pinMode(A1, INPUT); //Lenkung
  pinMode(A2, INPUT); //Gas
  pinMode(A3, INPUT); //CH3
  Serial.begin(9600);
}

void loop() {
  CH[0] = pulseIn(A1, HIGH); //Lenkung
  CH[1] = pulseIn(A2, HIGH); //Gas
  CH[2] = pulseIn(A3, HIGH); //CH3
  
  Serial.print(CH[0]); //Lenkung
  Serial.print(" - ");
  delay(100);
  Serial.print(CH[1]); //Gas
  Serial.print(" - ");
  delay(100);
  Serial.println(CH[2]); //CH3
  delay(100);
}

Also für das Bremslicht brauchst du doch nur den Gas-Kanal.
oder willst du auch noch automatisches Blinken programmieren?

Wenn wirklich immer der Wert 1000 eingelesen wird, kannst du noch so Klimmzüge programmieren das Programm kann es dann nicht erkennen.

pulsein ist blockierend.
Warte bis signal high wird ist an dieser Stelle ungeeignet.
RC-Signale haben alle 0,02 Sekunden einen gaanz kurzen HIGH-pulse der zwischen 1,0 und 2,0 Millisekunden lang ist. Da ist es mit Warte bis Signal auf HIGH geht nicht getan.
Du musst warten bis das Signal HIGH geht dann den aktuellen Wert von micros() speichern
Warten bis das Signal auf LOW geht und dann die Zeitdifferenz berechnen.

Aber dafür gibt es fertige libraries
schnell mal gequogelt
github arduino read rc receiver signal

vgs

1 Like

Wenn das gesichert ist, dann

ist das doch logisch gar nicht schwer abzubilden.

Du kommst von 2000 und gehst in 1000. Das passiert innerhalb einer gewissen Zeit.
Ist die Zeit abgelaufen und der Wert erreicht, geht die Bremsleuchte an solange bis wieder "neutral" oder zumindest etwas davor erreicht ist.

Doppelte Bedingung mit Ausstiegsmöglichkeit.

Mir scheint, du möchtest einen endlichen Automaten, eine °finite state machine", bauen!
(Auch wenn du vielleicht noch nicht weißt, was das ist)

„Wenn mein Wert größer als 1500 ist“ kann ich ja so programmieren: „if (CH[2] >1500).
Dann brauche ich aber noch zwei weitere Bedingungen: „es soll das Bremslicht nur an gehen, wenn innerhalb der gewissen Zeitspanne der Wert von >1500 kleiner als 1500 wird“.
Meine Frage: wie kann ich dem Arduino mitteilen, dass der Wert VON >1500 AUF <1500 gehen muss, um mein Bremslicht anzuschalten? Also ich weiß nicht, welche Begriffe ich für „VON Wert X“ und „AUF Wert Y“ benutzen soll.

Ja genau, jetzt soll es erstmal nur um den Gaskanal für das Bremslicht gehen. CH1 (Lenkkanal) ist nur als Test mit im Sketch mit drin, genau wie CH3.

Viele Mikrocontroller zählen die Zeit mit seit „Start“. Diese könntest du als Referenz nehmen, um zu ermitteln, wieviel Zeit vergangen ist.

millis() z.B. liefert dir die vergangenen Millisekunden seit Start.

Ich hab mal was ins blaue geschrieben.
Der Code soll folgendes machen:
Wenn der Speed im Vorwärts einen Grundwert erreicht hat und DANACH der Speed im Rückwärts den anderen Grundwert innerhalb einer bestimmten Zeit erreicht hat, soll die Bremsleuchte angehen.
Aus dann, wenn Du bei neutral bist.

const uint8_t numCh = 3;
uint16_t chInput[numCh] = {0};
uint16_t lastChInput[numCh] = {0};
uint8_t chInputPin[numCh] = {A0, A1, A2};
const char myType[numCh][10] = {"lenkung", "gas", "ch3"};
const byte bremsLichtPin = LED_BUILTIN;
const uint16_t forwardSpeed = 1750; // Grenzwert bei dem Vorwärtsbewegung erkannt wird
const uint16_t neutralSpeed = 1500; // Hier ist nüscht
const uint16_t rearSpeed = 1250;    // Grenzwert bei dem Rückwärtsbewegung erkannt wird
void setup()
{
  Serial.begin(9600);
  for (byte b = 0; b < numCh; b++)
  { pinMode(chInputPin[b], INPUT); }
  digitalWrite(bremsLichtPin, LOW);
  pinMode(bremsLichtPin, OUTPUT);
}

void loop()
{
  readChInput();
  printSerialChInput();
  myBremsLicht();
}
//
void readChInput()
{
  for (byte b = 0; b < numCh; b++)
  { chInput[b] = pulseIn(chInputPin[b], HIGH); }
}
//
void printSerialChInput()
{
  for (byte b = 0; b < numCh; b++)
  {
    if (lastChInput[b] != chInput[b])
    {
      Serial.print(myType[b]);
      Serial.print(": ");
      Serial.println(chInput[b]);
    }
  }
}
//
void myBremsLicht()
{
  static bool isForward = false;      // Merker
  static uint32_t lastSpeedTime = 0;  // Zeitmerker
  static bool isBreak = false;        // Merker
  const uint32_t reaktionsZeit = 200; // Zeit in ms... Das muss getestet werden
  if (chInput[1] > forwardSpeed)      //Grenzwert erreicht?
  {
    isForward = true;                 // merkern
    lastSpeedTime = millis();
  }
  //
  if (isForward)                      // Vorwärts wurde erkannt...
  {
    if (millis() - lastSpeedTime < reaktionsZeit) //  ... und Zeit nicht abgelaufen ...
    {
      if (chInput[1] < rearSpeed)     // ... und jetzt rückwärts? ...
      {
        isBreak = true;               // ... Bremse aktiviert!
        isForward = false;
      }
    }
    else
    { isForward = false; }
  }
  //
  if (isBreak)                        // Bremse aktiv ...
  {
    digitalWrite(bremsLichtPin, HIGH);
    if (chInput[1] >= neutralSpeed)   // und jetzt nicht mehr
    {
      isBreak = false;
      digitalWrite(bremsLichtPin, LOW);
    }
  }
}

Wenn das tut, kann man das auflösen auf ne Handvoll saubere Zeilen.

Danke, das ist sehr nett und hilfreich. Versuche mal als Neuling, den Code so gut wie möglich zu verstehen :wink:

Das ist Nebensache.
Er soll machen, was Du willst.
Also aufspielen, Vollgas. Dann zurück und sehen was passiert.
Wenn das so geht, kann man das verständlich schreiben.
Wenn das nicht so ist, kann man an den *speedVariablen bzw. der Reaktionszeit arbeiten oder aber sich ein neues Konzept ausdenken.

Also ich habe es ausprobiert und leider hat sich nix getan. Habe bereits die Zahlen von forwardSpeed, neutralSpeed und rearSpeed modifiziert, außerdem die reaktionsZeit auf 400 Millisekunden hochgeschraubt. Leider immer noch nix … Könnte es sein, dass die drei Speed Variablen feste Zahlen sind und dort das Problem liegt? Mein RC-Empfänger liefert ja keine festen Zahlen, die schwanken nämlich immer: bspw. die Neutralstellung schwankt zwischen ca. 1470 und 1510. Sollte also z. B. neutralSpeed mit genau 1500 definiert sein, ist die Wahrscheinlichkeit natürlich sehr gering, dass der genaue Wert 1500 getroffen wird.

Das ist kein Problem.
Die Voraussetzung für die Bremsleuchte ist, das erstmal vorwärts gefahren wird und dann der Wert 1750 erreicht wurde.
Die Idee ist, das jetzt innerhalb der reaktionsZeit der Speed auf weniger als 1250 gezogen wird.
Dann sollte die Bremsleuchte angehen...
Wenn Sie das nicht macht, stell mal die reaktonsZeit auf 1000ms - vielleicht ziehst zu langsam am Joystick :wink:

Ich schau morgen nochmal drauf, ob ich irgendwo einen Schnitzer habe...

@etoilevolante: Bitte versuche mal diese Ergänzungen:

const uint16_t GIVEUP = 50000;      // maximale Lauschzeit in µs
...
    chInput[b] = pulseIn(chInputPin[b], HIGH, GIVEUP);

Damit wird die Wartezeit auf ein gültiges Signal reduziert. Dadurch sehe ich ein Bremslicht :slightly_smiling_face:

Noch besser müßte es werden, wenn alle Kanäle ein gültiges Signal erhalten.

Sollte Dein Signal anders als dieses aussehen, müßtest Du es genauer beschreiben:

Hi agmue, danke für deinen Beitrag! Habe es in den Sketch eingefügt und gerade getestet. Jetzt hat sich etwas getan :slight_smile:

So habe ich alles angeschlossen:

Hier mal eine kleine Aufzählung, was ich beobachtet habe:

  1. GUT: Wenn ich vorwärts Gas gebe, ist das Bremslicht aus, ebenso wenn ich rückwärts fahre, so wie es sein soll.
  2. GUT: Wenn ich von Vorwärts schnell auf Rückwärts ziehe (bremsen), geht das Bremslicht (Pin 13) an. Perfekt!
  3. Beim Ausschalten des Bremslichts gibt es ein kleines Problem: es bleibt in der Neutralstellung an. Auch wenn ich in der Neutralstellung gewesen bin und danach rückwärts fahre, bleibt das Bremslicht weiterhin an. Erst wenn ich vorwärts fahre, geht es wieder aus.

Hier das Beschriebene als Video: Bremslicht Test: Sketch von my_xy_projekt mit Ergänzung von agmue - YouTube

Außerdem noch ein zweites Video: es ist eine fertige, gekaufte RC-Lichtsteuerung, die u. a. ein Bremslicht hat. So würde ich gerne mein Arduino Bremslicht haben: beim Bremsen das Bremslicht an und wenn die Neutralstellung wieder erreicht ist, aus. Beim Rückwärtsfahren ebenfalls das Bremslicht ausschalten (stattdessen sollen die Rückfahrscheinwerfer an gehen, aber das ist hier erstmal Nebensache). Ignoriert bitte, dass die Rücklichter auf dem Video gedimmt leuchten, wenn gerade nicht gebremst wird, das ist hier ebenfalls erstmal Nebensache. Bremslicht Beispiel - YouTube

Und zu guter Letzt der Sketch, den ich verwendet habe. Die Zahlen bei forwardSpeed, rearSpeed und reaktionsZeit habe ich etwas angepasst (aber nur grob, ist noch nicht komplett fein ausgemessen)

const uint8_t numCh = 3;
uint16_t chInput[numCh] = {0};
uint16_t lastChInput[numCh] = {0};
uint8_t chInputPin[numCh] = {A0, A1, A2};
const char myType[numCh][10] = {"lenkung", "gas", "ch3"};
const byte bremsLichtPin = LED_BUILTIN;
const uint16_t forwardSpeed = 1600; // (von 1750 zu 1600 geändert) Grenzwert bei dem Vorwärtsbewegung erkannt wird
const uint16_t neutralSpeed = 1500; // Hier ist nüscht
const uint16_t rearSpeed = 1350;    // (von 1250 auf 1350 geändert) Grenzwert bei dem Rückwärtsbewegung erkannt wird
const uint16_t GIVEUP = 50000;  //(Ergänzung von agmue) maximale Lauschzeit in µs

void setup()
{
  Serial.begin(9600);
  for (byte b = 0; b < numCh; b++)
  { pinMode(chInputPin[b], INPUT); }
  digitalWrite(bremsLichtPin, LOW);
  pinMode(bremsLichtPin, OUTPUT);
}

void loop()
{
  readChInput();
  printSerialChInput();
  myBremsLicht();
}
//
void readChInput()
{
  for (byte b = 0; b < numCh; b++)
  { chInput[b] = pulseIn(chInputPin[b], HIGH, GIVEUP); }  //(Ergänzung von agmue)
}
//
void printSerialChInput()
{
  for (byte b = 0; b < numCh; b++)
  {
    if (lastChInput[b] != chInput[b])
    {
      Serial.print(myType[b]);
      Serial.print(": ");
      Serial.println(chInput[b]);
    }
  }
}
//
void myBremsLicht()
{
  static bool isForward = false;      // Merker
  static uint32_t lastSpeedTime = 0;  // Zeitmerker
  static bool isBreak = false;        // Merker
  const uint32_t reaktionsZeit = 400; // (von 200 auf 400 geändert) Zeit in ms... Das muss getestet werden
  if (chInput[1] > forwardSpeed)      //Grenzwert erreicht?
  {
    isForward = true;                 // merkern
    lastSpeedTime = millis();
  }
  //
  if (isForward)                      // Vorwärts wurde erkannt...
  {
    if (millis() - lastSpeedTime < reaktionsZeit) //  ... und Zeit nicht abgelaufen ...
    {
      if (chInput[1] < rearSpeed)     // ... und jetzt rückwärts? ...
      {
        isBreak = true;               // ... Bremse aktiviert!
        isForward = false;
      }
    }
    else
    { isForward = false; }
  }
  //
  if (isBreak)                        // Bremse aktiv ...
  {
    digitalWrite(bremsLichtPin, HIGH);
    if (chInput[1] >= neutralSpeed)   // und jetzt nicht mehr
    {
      isBreak = false;
      digitalWrite(bremsLichtPin, LOW);
    }
  }
}

[EDIT: Nachdem ich neutralSpeed ich auf 1480 runtergeschraubt habe, geht das Bremslicht in der Neutralstellung aus, so wie es sein soll. 1500 war einfach nur etwas zu hoch.
reaktionsZeit = 400 war in meinem Fall jetzt doch zu lang, für mich waren 200 Millisekunden besser. Aber das kann je nach Belieben adjustiert werden.]

Versuch mal:
[EDIT: Aus dem || ein && gemacht um das Bremslicht abzuschalten]

const uint8_t numCh = 3;
uint16_t chInput[numCh] = {0};
uint16_t lastChInput[numCh] = {0};
uint8_t chInputPin[numCh] = {A0, A1, A2};
const char myType[numCh][10] = {"lenkung", "gas", "ch3"};
const byte bremsLichtPin = LED_BUILTIN;
const uint16_t neutralSpeed = 1490; // Hier ist nüscht
const uint8_t  hysterese = 21;      // Pendel der Neutralstellung +/-
const uint16_t giveUp = 50000;  //(Ergänzung von agmue) maximale Lauschzeit in µs

void setup()
{
  Serial.begin(9600);
  for (byte b = 0; b < numCh; b++)
  { pinMode(chInputPin[b], INPUT); }
  digitalWrite(bremsLichtPin, LOW);
  pinMode(bremsLichtPin, OUTPUT);
}

void loop()
{
  readChInput();
  printSerialChInput();
  myBremsLicht();
}
//
void readChInput()
{
  for (byte b = 0; b < numCh; b++)
  { chInput[b] = pulseIn(chInputPin[b], HIGH, GIVEUP); }  //(Ergänzung von agmue)
}
//
void printSerialChInput()
{
  for (byte b = 0; b < numCh; b++)
  {
    if (lastChInput[b] != chInput[b])
    {
      Serial.print(myType[b]);
      Serial.print(": ");
      Serial.println(chInput[b]);
    }
  }
}
//
void myBremsLicht()
{
  static bool isForward = false;      // Merker
  static uint32_t lastSpeedTime = 0;  // Zeitmerker
  static bool isBreak = false;        // Merker
  const uint32_t reaktionsZeit = 400; // (von 200 auf 400 geändert) Zeit in ms... Das muss getestet werden
  if (chInput[1] > neutralSpeed + hysterese) // NeutralStellung vorwärts verlassen
  {
    isForward = true;                 // merkern
    lastSpeedTime = millis();
  }
  //
  if (isForward)                      // Vorwärts wurde erkannt...
  {
    if (millis() - lastSpeedTime < reaktionsZeit) //  ... und Zeit nicht abgelaufen ...
    {
      if (chInput[1] < neutralSpeed - hysterese)  // ... und jetzt rückwärts? ...
      {
        isBreak = true;               // ... Bremse aktiviert!
        isForward = false;
      }
    }
    else
    { isForward = false; }
  }
  //
  if (isBreak)                        // Bremse aktiv ...
  {
    digitalWrite(bremsLichtPin, HIGH);
    if ((chInput[1] > neutralSpeed - hysterese) &&
        (chInput[1] < neutralSpeed + hysterese))   // und jetzt nicht mehr
    {
      isBreak = false;
      digitalWrite(bremsLichtPin, LOW);
    }
  }
}

Super, es funktioniert! DANKE! :smiley:

Dieser Sketch funktioniert jetzt übrigens auch, nachdem ich neutralSpeed auf 1480 runtergeschraubt habe. neutralSpeed =1500 war einfach nur etwas zu hoch.

Habe es gerade nochmal getestet und festgestellt, dass reaktionsZeit = 200 doch besser als 400 ist :wink: :+1: