PWM-Signale "einfrieren" - Tempomat

Hallo zusammen,

ich habe mir eine Joystick-Steuerung für zwei Elektromotoren gebaut, das läuft auch sehr gut so weit. Der Vor- bzw. Rückwärtslauf der Motoren und die jeweilige Geschwindigkeit werden über die X- und Y-Achse gesteuert, ähnlich wie bei diesen Arduino gesteuerten Autos.

Ich würde gerne eine Funktion haben, dass man auf Knopfruck beide Signale einfriert und dauerhaft an die Motoren sendet, bis man den Knopf wieder drückt. Idealer Weise, bis man den Knopf wieder drückt oder X- und Y-Achse wieder auf Center waren und dann ein neues Signal senden.

Ich habe mir jetzt schon mehrere Tage den Kopf zerbrochen - keine Ahnung wie das anzustellen wäre. Ich muss allerdings auch dazu sagen, das ist mein erstes Arduino Projekt und ich habe vor 4 Monaten überhaupt erst mit solchen Sachen angefangen.

Ich möchte auch gar nichts vorgekaut bekommen, viel mehr einen Tipp oder eine Richtung aufgezeigt bekommen. :slight_smile:

Vielen Dank

Hallo j-mo85

Herzlich Willkommen im weltbesten Arduinoforum.

Im IDE findest du das State change detection Beispiel als Basis für einen Buttonmanager.
Daraus kannst die Variable mit dem Namen "lastButtonState" nehmen um die Ausgabe "einzufrieren"

if (lastButtonState==HIGH) analogWrite(pwmPin,pwmValue); 

Ich wünsche dir viel Spass beim Ausprobieren.

Hat der Joystick keinen Knopf zum Setzen und Rücksetzen des aktuellen Tempos?

Hallo
Du solltest das in mehrere ,für Dich nachvollziehbare Schritte aufteilen , damit du verstehst wie man sowas machen kann.

1Taster entprellen
2 Erkennen das er betätigen würde Flanke erkennen
3 mit der Flanke jedesmal einen Statusmerket umschalten (toggeln)

Für 1 U 2 gibt es mehrereLibs die machen das in einem Stepp
Bounce2 wäre eine

Heinz

Mein Tempomat im Auto wäre beleidigt, da der eine Geschwindigkeitsregelung durchführt. Der Begriff "einfrieren" trifft es besser.

Die Variable pwmWertXY wird, wie auch jetzt, ermittelt. Ist die Variable eingefroren wahr, so setzt Du pwmWertAktuell = pwmWertFrost, ansonsten pwmWertAktuell = pwmWertXY.

Mit dem Tipp aus #2 setzt Du pwmWertFrost = pwmWertXY.

Mein Vorschlag kann, wenn er denn mal funktioniert, vermutlich noch optimiert werden.

Setzt man sich mit Tastern auseinander, stolpert man zwangsläufig über Themen wie Entprellen, Flankenerkennung und dergleichen. Schau Dir mal die über die Bibliotheksverwaltung der IDE zu installierende Bibliothek MobaTools an, die Dich, wenn Du das möchtest, diesbezüglich unterstützen kann.

Guten Morgen zusammen,

da kamen ja schon einige Antworten, vielen dank dafür. :star_struck:

Ich habe ohnehin schon zwei Taster eingebunden und den Taster auf dem Joystick vorbereitet. Ich hatte mich entschieden das mit Pulldown-Wiederständen zu machen, das funktioniert auch gut bisher.

Alles andere verstehe ich bisher überhaupt nicht :D, werde mich aber einlesen die Tage und dann bestimmt nochmal mit der ein oder anderen Frage kommen.

Ich danke Euch, ein schönes Wochenende.

Jan

Zeige uns Dein nicht perfekt funktionierendes Programm, beschreibe die kritische Stelle und Dir wird geholfen.

Einfacher wäre zunächst, zwei Taster für "einfrieren" und "auftauen" zu verwenden.

Hallo, endlich hatte ich mal Zeit mich ein mit den Tipps auseinander zu setzen.

Aktuell habe ich schon 2 Taster in mein Projekt eingebunden. Diese lassen die Motoren, ist das Signal an Pin-X high, mit Geschw. X laufen.

Jetzt korrigiert mich bitte wenn ich falsch liege.... Der einzige Unterschied liegt doch darin, dass bei mir jetzt die Aktion nur ausgeführt wird, wenn der Taster gedrückt ist und die Aktion nur auf Grundlage des Signals "high" ausgeführt wird und nicht auf Grund eines abgespeicherten Zustandes, richtig? Ja, und dass die Aktion auch über Ende des Loops weiter ausgeführt werden kann. Habe ich das so weit richtig verstanden?

@paulpaulson ich glaube ich verstehe was du mir sagen möchtest, ich weiß aber leider nicht, wie ich pwmValue abgreife und das dann umsetze.

@agmue , auch was du geschrieben hast verstehe ich, bin aber total planlos und weiß nicht so recht, wie ich das angehen soll.

....oder ich sehe gerade den Wald vor Bäumen nicht.

Allerdings ist mir noch etwas eingefallen. Die Motortreiber arbeiten zusätzlich mit einem Signal, das den Rückwärtslauf steuert. Dieses müsste dann ja auch zusätzlich "eingefroren" werden, richtig?

Gruß
Jan

Warum soll ich dich korrigieren?
OK, ich versuchs mal...

Hier scheint mir ein Denkfehler zu lauern.
loop() ist die Mutter aller Anlaufsteuerungen.
loop() wird gerne hunderttausend mal pro Sekunde aufgerufen.
Es geht nicht über loop() hinaus.
(außer vielleicht ISR, aber die brauchst du hier nicht)

In Wirklichkeit möchtest du gerne endliche Automaten bauen.
Vielleicht einige davon, welche sich kooperativ Rechenzeit geben.
Suche mal das "Nachtwächter Beispiel" hier im Forum.

void main()
{
  setuo();
  while(1)
  {
    loop();
  }
}

Das Ende von loop() ist auch der Anfang von loop(), also eine Endlosschleife.

Und ich sehe Dein Programm nicht :roll_eyes:

Hallo,
ich gebe Dir mal einen Ansatz anhand eines kleinen Beispiels. Verwendet habe ich die lib Bounce2 und daraus das Beispiel Bounce_button als Vorlage genutzt.

/* Beispiel Bonce2 toggelt mit einem Button einen Merker
 *  Als Vorlage das Beispiel aus der Lib Bounce_button
 *  Wenn der merker H ist wird ein Analogeingang aktualisiert
 *  ansonsten wird der eingefrorene Wert auf eine pwm Ausgang gegeben
 */

#include <Bounce2.h>
const byte analogPin = A0;
const byte buttonpin = 2;
const byte pwmpin = 3;  
const byte led=13;      // Status aktualisieren anzeigen mit interner LED
bool merker = false;

int pwm;
Bounce2::Button button = Bounce2::Button();

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  button.attach(buttonpin, INPUT_PULLUP);
  button.interval(5);
  button.setPressedState(LOW);
  pinMode(led, OUTPUT); 

}

void loop() {
  // put your main code here, to run repeatedly:
  button.update();
  if (button.pressed()) {
    merker = !merker;
    digitalWrite(led, merker);
  }

  if (merker) { // wenn der merker H ist Wert einlesen
    pwm = analogRead(analogPin); // hier alle Deine analogwerte einlesen
  }

  analogWrite(pwmpin, pwm / 4); // hier analogwerte ausgeben und eventuell Richtung setzen

  // Zum testen und anzeigen auf dem Monitor
  Serial.print("Merker ");Serial.print(merker);
  Serial.print("\tpwm Wert ");Serial.println(pwm);
  delay(100); // nur zum testen mit serieller Ausgabe

}

Altrernativ kann man auch einfach die analogWrite- Ausgabe weglassen/überspringen, wenn der Zustand "eingefroren" sein soll. Ohne analogWrite-Aufruf läuft die Ansteuerung des pwmpin mit dem zuletzt eingestellten Wert weiter.
Oder man nimmt verschiedene Variable für das Einlesen der Joystick Werte und das Ansteuern der Motoren, und entscheidet, ob aktuell die Motor-Werte verändert werden oder nicht (eingefroren).

Ups
das ist natürlich richtig, danke für den Hinweis.
Damit könnte das analogWrite mit in die darüber stehende if... Bedingung mit rein

Heinz

Hallo zusammen,

danke für die ganzen Tipps. :slight_smile: Ich habe leider gar nicht so viel Zeit in den letzten Tagen, mich mit jedem Vorschlag so intensiv auseinander zu setzen. Aber ich bin dran... und seit gestern Abend arbeite ich auch en etwas, das ich euch dann hier vorstellen möchte. Ich möchte glauben, es hat "klick" gemacht bei mir und ich bin auf dem Weg eine Lösung zu finden. :smiley:

Das soll natürlich nicht bedeuten, dass ich hier irgendetwas ignoriere. Ich weiß das sehr zu schätzen und werde mich auch damit noch beschäftigen.

Danke euch

Hallo zusammen,

hier der erste Lösungsansatz - funktioniert natürlich nicht :smiley:

Ich finde, glaube ich zumindest, keine Möglichkeit das aktuell an die Motoren gesendete Signal "greifbar" zu machen und in die Variable zu packen. Ich habe den ganzen Morgen verschiedenste, zumindest für mich logische, Herangehensweisen getestet. Hat leider alles nicht funktioniert.

Da bin ich für einen Tipp sehr dankbar und auch generell über eine Aussage, ob man das so machen kann, oder ob ich komplett auf dem Holzweg bin.

Bitte seht mir nach, dass das ein erster Ansatz ist und ich nicht alle von euch geteilten Tipps da einfliessen lassen konnte.

So, jetzt nicht lachen.... here it comes :slight_smile:

TasterNeu = digitalRead(TasterFreeze);
  if (TasterAlt == 0 && TasterNeu == 1) {
    if (FreezeStatus == 0) {

      //delay(50); //richtige STelle für debounce?!

      FreezeStatus = 1;
      ValMotorRechts = motorRECHTS; //motorRechts = Variable zu Motor bei Joystickverw.
      ValMotorLinks = motorLINKS; //motorLinks = Variable zu Motor bei Joystickverw.
      analogWrite(enA, ValMotorRechts); //enA Output für Motor rechts
      analogWrite(enB, ValMotorLinks); //enB Output für Motor links, 
      
    }
    else {
      FreezeStatus = 0;
      ValMotorRechts = 0;
      ValMotorRechts = 0;
    }

  TasterAlt = TasterNeu;
  }

Edit: den Vor- und Rückwärtslauf habe ich erstmal ausser Acht gelassen.

Libs möchte ich an dieser Stelle nur ungern verwenden, Ich hätte gern, dass das Program in sich funktioniert.

Hallo,

was klappt denn nicht ?
es wäre zudem nicht schlecht wenn wir Deinen ganzen Sketch hätten , dann könnten wir das selber testen.
also wenn Du keine lib nehmen willst, warum auch immer , dann bau doch erst mal etwas mit einem Taster bei dem mit jedem drücken ein Zähler genau um 1 hochgezählt wird. Dann weist Du das das entprellen klappt und die Flanke richtig erkannt wird.

Natürlich kannst Du in den loop erst mal ein schmutziges delay(10) einbauen das entprellt auch super.

Heinz

Hallo Rentner,

ich habe schon zwei funktionierende Taster, die sind auch entprellt. Ich werde den hierfür verwendeten Taster mal unter die Lupe nehmen.

Hier auch noch der ganze Sketch, sorry.

#define enA 9
#define in1 4
#define enB 10
#define in4 7

int Taster1Pin = 8;   // Taster1Pin steht für Pin8
int Taster2Pin = 11;  // Taster2Pin steht für Pin11
int TasterFreeze = 12;  // TasterFreeze steht für Pin12

int FreezeStatus = 0;
int TasterNeu;
int TasterAlt = 1;  

int ValMotorRechts = 0;
int ValMotorLinks = 0;

int motorRECHTS = 0;
int motorLINKS = 0;

void setup() {

  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in4, OUTPUT);
  pinMode(Taster1Pin, INPUT);  //Pin8 = Eingang
  pinMode(Taster2Pin, INPUT);  //Pin11 = Eingang
  pinMode(TasterFreeze, INPUT);  //Pin12 = Eingang

  //Timer2 auf 31300Hz (PIN 9 & 10)
  TCCR2B = TCCR3B & 0b11111000 | 0x01;

}

void loop() {

int xAxis = analogRead(A0); // lese X-Achse
int yAxis = analogRead(A1); // lese Y-Achse

  // Y-Achse beide Motoren vorwärts und rückwärts
  if (yAxis < 512) {
    // Motor RECHTS rückwärts
    digitalWrite(in1, HIGH);
    // Motor LINKS rückwärts
    digitalWrite(in4, HIGH);
    // Konvertierung der abfallenden Y-Achsen-Messwerte für das Rückwärtsfahren von 512 auf 0 in einen Wert von 0 bis 255 für das PWM-Signal zum Erhöhen der Motordrehzahl
    motorRECHTS = map(yAxis, 512, 0, 0, 255);
    motorLINKS = map(yAxis, 512, 0, 0, 255);
  }
  else if (yAxis > 512) {
    // Motor RECHTS vorwärts
    digitalWrite(in1, LOW);
    // Motor LINKS vorwärts
    digitalWrite(in4, LOW);
    // Konvertierung der zunehmenden Y-Achsen-Messwerte für das Vorwärtsfahren von 512 bis 1023 in einen Wert von 0 bis 255 für das PWM-Signal zum Erhöhen der Motordrehzahl
    motorRECHTS = map(yAxis, 512, 1023, 0, 255);
    motorLINKS = map(yAxis, 512, 1023, 0, 255);
  }

  // Joystickposition auf Mitte, keine Bewegung
  else {
    motorRECHTS = 0;
    motorLINKS = 0;
  }

  // X-Achse links- und rechtskurven
  if (xAxis > 512) {
    // Konvertierung der abnehmenden X-Achsen-Messwerte von 512 bis 0 in steigende Werte von 0 bis 255
    int xMapped = map(xAxis, 512, 0, 0, 255);

    // Kurve nach links - verringere linke Motorgeschwindigkeit, erhöhe rechte Motorgeschwindigkeit
    motorRECHTS = motorRECHTS + xMapped;
    motorLINKS = motorLINKS - xMapped;

    // Beschränkung auf den Bereich auf 0 bis 255
    if (motorRECHTS < 0) {
      motorRECHTS = 0;
    }
    if (motorLINKS > 255) {
      motorLINKS = 255;
    }
  }
  if (xAxis < 512) {
    // Wandeln der zunehmenden X-Achsen-Messwerte von 512 bis 1023 in Werte von 0 bis 255
    int xMapped = map(xAxis, 512, 1023, 0, 255);

    // Kurve nach rechts - verringere rechte Motorgeschwindigkeit, erhöhe linke Motorgeschwindigkeit
    motorRECHTS = motorRECHTS - xMapped;
    motorLINKS = motorLINKS + xMapped;

    // Beschränkung auf den Bereich auf 0 bis 255
    if (motorRECHTS > 255) {
      motorRECHTS = 255;
    }
    if (motorLINKS < 0) {
      motorLINKS = 0;
    }
  }
    // Brummen bei niedrigen Geschwindigkeiten verhindern (an Motoren anpassen FP-Motoren Wert5)
  if (motorRECHTS < 5) {
      motorRECHTS = 0;
  }
  if (motorLINKS < 5) {
      motorLINKS = 0;
  }

  analogWrite(enA, motorRECHTS);
  analogWrite(enB, motorLINKS);

  if (digitalRead(Taster1Pin)==HIGH) {
      // Motor RECHTS rückwärts
      digitalWrite(in1, HIGH);
      // Motor LINKS vorwärts
      digitalWrite(in4, LOW);

      analogWrite(enA, motorRECHTS=255);
      analogWrite(enB, motorLINKS=255);
    }
    
  if (digitalRead(Taster2Pin)==HIGH) {
      // Motor RECHTS vorwärts
      digitalWrite(in1, LOW);
      // Motor LINKS rückwärts
      digitalWrite(in4, HIGH);

      analogWrite(enA, motorRECHTS=255);
      analogWrite(enB, motorLINKS=255); 
    }

  TasterNeu = digitalRead(TasterFreeze);
  if (TasterAlt == 0 && TasterNeu == 1) {
    if (FreezeStatus == 0) {

      //delay(50); //richtige STelle für debounce?!

      FreezeStatus = 1;
      ValMotorRechts = motorRECHTS; //motorRechts = Variable zu Motor bei Joystickverw.
      ValMotorLinks = motorLINKS; //motorLinks = Variable zu Motor bei Joystickverw.
      analogWrite(enA, ValMotorRechts); //enA Output für Motor rechts
      analogWrite(enB, ValMotorLinks); //enB Output für Motor links, 
      
    }
    else {
      FreezeStatus = 0;
      ValMotorRechts = 0;
      ValMotorRechts = 0;
    }

  TasterAlt = TasterNeu;
  }

}

Probier's doch mal mit

bool eingefroren; //Zustand des Tempomat
...
if (!eingefroren) {

}

Dann mußt Du Dir nur noch merken, ob eingefroren oder nicht.
So lange kein neues analogWrite() aufgerufen wird, bleiben die PWM Signale auf dem vorherigen Stand eingefroren.

@DrDiettrich , damit habe ich noch nie irgendwas gemacht. Mir ist das zwar schonmal über den Weg gelaufen aber da müsste ich mich erstmal einlesen. Jetzt gerade ist mir nichtmal klar, ob das ein neuer Ansatz ist, oder eine Ergänzung zu meinem Versuch.

Ist meine Herangehensweise falsch?

Wobei "meine" natürlich gut ist.. Ich versuche es ja gerade mit dem ersten Vorschlag von @paulpaulson, zumindest in der Art.

Danke und Gruß

Ja, in zweierlei Hinsicht:

  1. Zum Einfrieren der PWM Signale reicht es, sie einfach nicht mehr zu ändern. Das hilft aber nichts, weil:

  2. Zum Einfrieren des Tempos (Tempomat) ist eine ständige Messung und Anpassung der PWM erforderlich.

Du kannst zunächst Punkt 1 verfolgen und richtig implementieren. Ein wichtiger Lerneffekt! Das kann dann hilfreich sein, auch Punkt 2 in einem neuen Programm richtig zu implementieren.