Kinder Kart Motor Softstart

Hallo,
Ich bin gerade dabei, für meinen Sohn ein E-Kart zu bauen. Jetzt mache ich mir Gedanken über den Antrieb. Ich habe einen Scheibenwischer Motor mit 24V.
Der soll jetzt irgendwie angetrieben werden.
Nicht einfach nur an und aus bzw vor und zurück, sonder ich hätte gern einen Softanlauf bzw Softstop.
Mot Arduino's habe ich mich früher ( vor 10 Jahren oder Länger) mal beschäftigt, aber wirklich Erfahrung haben ich nicht mehr viel. Es fällt mir auch ziemlich schwer, mich da neu rein zu lesen. Ich habe noch 5 oder auch mehr Arduino nano's liegen.
Jetzt die Frage, gibt's da schon Projekte zu? Habe ich erst mal nichts gefunden.
Meine Idee wäre jetzt, das der arduino einen Bts7960 steuert und der wiederum den Motor.
Der Motor hat 60Watt also so um die 2,5A mit 220 Upm.
Die Idee wäre jetzt. Ein Poti, das dann am Arduino den Bts steuert, mit Softstart. Also beim betätigen des Gaspedal, soll der Motor mit einer Rampe von 2 Sekunden anlaufen, um den Ruck beim Starten weg zu bekommen. Beim Stoppen ähnlich. Da vielleicht nur 1sek? Würde gern vermeiden, daß die Räder blockieren. Es soll auch einen Rückwärtsgang gegen, der aber nur mit 30% Drehzahl läuft.
Dafür sollte doch ein Arduino nano ausreichen, oder?
Irgendwie viel mir aber die Idee, wie ich das machen soll. Es gibt ja schon fertige Module mit dem Bts7960, mit vor und Rücklauf und Poti, aber alles ohne Softanlauf.

Gruß Christian

Als ausbaufähige Anregung könntest Du Motor Driver BTS7960 43A verwenden, da gibt es einen Sanftanlauf und eine rudimentäre Schrittkette.


Nachtrag

Hier das Programm aus dem Link, falls dieser mal verschwinden sollte:

/*........................
  BTS7960 Motor Driver Test
  Written By : Mohannad Rawashdeh
  Code for :
  https://www.instructables.com/member/Mohannad+Rawashdeh/
*/
int RPWM = 5;
int LPWM = 6;
// timer 0
int L_EN = 7;
int R_EN = 8;

void setup() {
  // put your setup code here, to run once:
  for (int i = 5; i < 9; i++) {
    pinMode(i, OUTPUT);
  }
  for (int i = 5; i < 9; i++) {
    digitalWrite(i, LOW);
  }
  delay(1000);
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("EN High");
  digitalWrite(R_EN, HIGH);
  digitalWrite(L_EN, HIGH);
  delay(1000);
  for (int i = 0; i < 256; i++) {
    analogWrite(RPWM, i);
    //  analogWrite(LPWM,255-i);
    delay(100);
  }
  delay(500);
  for (int i = 255; i > 0; i--) {
    analogWrite(RPWM, i);
    // analogWrite(LPWM,255-i);
    delay(100);
  }
  delay(500);
  Serial.println("EN LOW");
  digitalWrite(R_EN, LOW);
  digitalWrite(L_EN, LOW);
  delay(1000);
  for (int i = 0; i < 256; i++) {
    analogWrite(RPWM, i);
    delay(100);
  }
  delay(500);
  for (int i = 255; i > 0; i--) {
    analogWrite(RPWM, i);
    delay(100);
  }
  delay(500);
}

Der hat einen Sanfstart integriert? Habe bis jetzt nur gefunden, das er über pwm gesteuert wird.
Was ist eine rudimentäre Schrittkette?

Nein das ist nicht in der Hardware enthalten. Aber im Programm kannst du ja machen, was du willst. Vom Poti abhängiger PWM Wert, und den kannst du schnell oder langsam ansteigen lassen wie du willst. Alles ist mööööglich, Arduinooooooo :grinning: Und der Regler packt den Motor leicht.

Der bremst die Schritte fürs Gas einfach über Delay´s. Ich habe das Programm nicht ausprobiert. Aber schaut so aus als ob es etwa das macht was du willst. :grinning: rudimentäre heißt halt "ausbaufähig"

Schrittkette meint

ein Programm das nacheinander verschiedene Programmteile ausführt.
Das besondere an einer Schrittkette ist, das der Programmteil der ausgeführt werden soll über eine - ich nenne es mal salopp "Steuerungszahl" - steuern kann.

Steuerungszahl = 1 Programmteil "A"
Steuerungszahl = 2 Programmteil "B"
Steuerungszahl = 3 Programmteil "C"
usw.

Wenn du uns in etwa beschreibst wie viel du über programmieren weißt dann können die Antworten auf deinen Kenntnisstand hin angepasst werden.

vgs

Den habe ich nicht, daher diesbezüglich eine weitere ungetestete Anregung:

const byte DIR  = 4;
const byte VPWM = 5;
const byte RPWM = 6;
const byte L_EN = 7;
const byte R_EN = 8;
const byte POTI = A0;

void setup() {
  Serial.begin(115200);
  Serial.println(F("\nStart"));

  pinMode(DIR, INPUT_PULLUP);
  pinMode(VPWM, OUTPUT);
  pinMode(RPWM, OUTPUT);
  pinMode(L_EN, OUTPUT);
  pinMode(R_EN, OUTPUT);

  digitalWrite(R_EN, HIGH);
  digitalWrite(L_EN, HIGH);
  analogWrite(VPWM, 0);
  analogWrite(RPWM, 0);
}

void loop() {
  static uint8_t schritt = 0;
  uint8_t geschw = fahren();

  switch (schritt)
  {
    case 0:
      if ( (geschw == 0) && (!digitalRead(DIR)) )
      {
        schritt = 1;
      }
      analogWrite(VPWM, geschw);
      break;
    case 1:
      if ( (geschw == 0) && (digitalRead(DIR)) )
      {
        schritt = 0;
      }
      analogWrite(RPWM, geschw);
      break;
  }
}

uint8_t fahren()
{
  uint32_t jetzt = millis();
  static uint32_t vorhin = 0;
  const uint32_t intervall = 12;  // 3000 ms / 256
  static uint8_t istGeschw = 0;
  uint8_t sollGeschw = analogRead(POTI) / 4;
  const uint8_t beschl = 1;
  const uint8_t bremsen = 5;

  if ( (sollGeschw != istGeschw) && (jetzt - vorhin >= intervall) )
  {
    if (sollGeschw > istGeschw)
    {
      if ((istGeschw + beschl) < 255)
      {
        istGeschw += beschl;
      } else {
        istGeschw = 255;
      }
    } else {
      if ((istGeschw - bremsen) > 0)
      {
        istGeschw -= bremsen;
      } else {
        istGeschw = 0;
      }
    }
    vorhin = jetzt;
    char buf[50] = {"\0"};
    snprintf( buf, sizeof(buf), "sollGeschw: %u \tistGeschw: %u", sollGeschw, istGeschw );
    Serial.println(buf);
  }
  return istGeschw;
}

Die Umschaltung zwischen Vorwärts- und Rückwärtsfahrt geht nur über Stillstand, da muß man sicherlich nochmal drüber nachdenken.


@noiasca: Im NoiascaToolKit bin ich nicht fündig geworden, obwohl Smooth LED schon nahe dran ist. Habe ich ein Werkzeug in Deiner Bastelkiste übersehen?

@agmue was fehlt dir bei der Smoothled?
die hat eine Upspeed,
eine Downspeed
eine Begrenzung

  smoothLed.setOnInterval(30);     // you can modify the delay time for the smothing
  smoothLed.setOffInterval(5);     // you can modify the delay time for the smothing
  //smoothLed.setMaxBrightness(240); // you can limit the maximum brightness. Highest value on Arduino is 255. Default 255.

was klappt damit nicht?
(außer dass ich schon bereue, dass die Klassen LED heißen ...)

Ich glaub eher dass das API nicht ganz dem entspricht was gewünscht ist:
Der Poti gibt ja Geschwindigkeit vor.
Daher müsste man die abhängig vom "ist größer" "ist kleiner als vorhergehender Wert" zwischen rauf und runter dimmen umschalten und beim neuen Sollwert aufhören.
vermutlich sollte man da eher einen leicht angepasste Klasse basteln.
Sollwert übergeben - pwm Wert anpassen lassen.

entspricht das eher deiner Vorstellung?
Ich könnte mir das ansehen, aber ich könnte mir auch vorstellen dass das in den Mobatools verfügbar ist (weis ich nicht).

edit: ... hm ja ... die Abfrage auf den on/off Status verhindert in der update() methode das einfache rauf und runter dimmen nur über den Sollwert.

Ja, ganz genau!

Die MobaTools verstehe ich einfacher als Deine Bibliotheken :flushed: , aber auch da bin ich nicht fündig geworden.

Ich wollte es dem TO etwas vereinfachen, letztlich benötigt man aber auch keine Bibliothek, selbst ist der Mann!

Danke für's Drüberschauen und die Bestätigung, war mit halt unsicher.

Wow, hier ist ja einiges passiert.
Vom Ansatz her verstehe ich das glaube ich.
Ist DIR für den Rechts/Links lauf?
Es ist scheinbar echt lange her bei mir.
Also selber was entwickeln bekomme ich nicht hin. Vorhanden Code anpassen oder aus 2 mach 1 wird vermutlich noch gehen. ( zum teil)
Warum geteilt durch 4?

uint8_t sollGeschw = analogRead(POTI) / 4;

Was machen die 1 und 5 ? Wegen der längeren Rampe fürs beschleunigen als beim Bremsen?
Wo wird das umgesetzt?

  const uint8_t beschl = 1;
  const uint8_t bremsen = 5;

Was passiert da?

 vorhin = jetzt;
    char buf[50] = {"\0"};
    snprintf( buf, sizeof(buf), "sollGeschw: %u \tistGeschw: %u", sollGeschw, istGeschw );
    Serial.println(buf);

Das Umschalten für L auf R also:

 digitalWrite(R_EN, HIGH);
  digitalWrite(L_EN, HIGH);

Ist in deiner Hilfestellung nicht umgesetzt oder finde ich das nur nicht? Die müssen doch ungleich sein, für den BTS oder?

Den Weg übers Bremsen/Stillstand ist schon ok. Hat ein Auto ja nicht anders. Eine Bremse, bzw eine Ansteuerung benötige ich (noch) nicht. Ich habe einen Motor mit Schneckenantrieb.
Pro: Egal kein Signal, Motor stoppt bzw dreht nicht.
Kontra: Man hat keinen Leerlauf zum schieben.

Ich habe mir jetzt mal einen BTS7960 43A bestellt. Arduinos habe ich ja noch liegen. Dann kann ich auch bisschen testen, was passiert.

Ja, RICHTUNG war mir zu lang :joy:

Der analoge Wert wird mit 0 bis 1023 gemessen, der PWM-Wert hat 0 bis 255, liegt der Faktor 4 dazwischen.

Das ist die Geschwindigkeitsänderung, langsam beschleunigen, schnell bremsen.

Beschreibung snprintf

Ist aber nicht wichtig, ich bin nur faul. Mehrere print gehen auch.

Nee, ich verwende die zwei PWM-Werte an VPWM (vorwärts) und RPWM (rückwärts) dazu. Ich habe das zweite Programm aus dem Link als Vorbild genommen. Wie es richtig funktioniert, kann ich mangels Hardware nicht testen.

Bitte berichte!

Das habe ich zum BTS gefunden. Das klinkt für mich so, also wenn er High / Löw im Wechsel an den Pins LPWM und RPWM benötigt. Wobei die Bezeichnung durch PWM irreführend ist.
Ich werde mal gucken, wenn ich das zusammen habe, und dann auch einem Breakboard mal testen. Ich berichte, und werde sicherlich noch fragen haben.

Diese Anschlußbeschreibung kommt mir bekannt vor, da ist das Programm schnell angepaßt. Getestet mit UNO und LEDs:

const byte DIR  = 4;
const byte MOTOR_PWM = 6;  // an PWM
const byte V_EN = 7;       // vorwärts Freigabe; an RPWM oder LPWM
const byte R_EN = 8;       // rückwärts Freigabe; an LPWM oder RPWM
const byte POTI = A0;

void setup() {
  Serial.begin(115200);
  Serial.println(F("\nStart"));

  pinMode(DIR, INPUT_PULLUP);
  pinMode(V_EN, OUTPUT);
  pinMode(R_EN, OUTPUT);

  analogWrite(MOTOR_PWM, 0);
}

void loop() {
  static uint8_t schritt = 0;
  bool stillstand = !fahren();
  
  switch (schritt)
  {
    case 0:
      if (digitalRead(DIR))
      {
        digitalWrite(R_EN, LOW);
        digitalWrite(V_EN, HIGH);
      } else {
        digitalWrite(R_EN, LOW);
        digitalWrite(V_EN, LOW);
        if ( stillstand ) schritt = 1;
      }
      break;
    case 1:
      if (!digitalRead(DIR))
      {
        digitalWrite(V_EN, LOW);
        digitalWrite(R_EN, HIGH);
      } else {
        digitalWrite(R_EN, LOW);
        digitalWrite(V_EN, LOW);
        if ( stillstand ) schritt = 0;
      }
      break;
  }
}

bool fahren()
{
  uint32_t jetzt = millis();
  static uint32_t vorhin = 0;
  const uint32_t intervall = 12;  // 3000 ms / 256
  static uint8_t istGeschw = 0;
  uint8_t sollGeschw = analogRead(POTI) / 4;
  const uint8_t beschl = 1;
  const uint8_t bremsen = 5;

  if ( (sollGeschw != istGeschw) && (jetzt - vorhin >= intervall) )
  {
    if (sollGeschw > istGeschw)
    {
      if ((istGeschw + beschl) < 255)
      {
        istGeschw += beschl;
      } else {
        istGeschw = 255;
      }
    } else {
      if ((istGeschw - bremsen) > 0)
      {
        istGeschw -= bremsen;
      } else {
        istGeschw = 0;
      }
    }
    analogWrite(MOTOR_PWM, istGeschw);
    vorhin = jetzt;
    char buf[50] = {"\0"};
    snprintf( buf, sizeof(buf), "sollGeschw: %u \tistGeschw: %u", sollGeschw, istGeschw );
    Serial.println(buf);
  }
  return (istGeschw > 0);
}

Vielen dank, das läuft soweit echt gut. Das hätte ich sicherlich nicht hin bekommen.
Was aber nicht geht, und ich auch im Code nicht gefunden habe, das der Rückwärtsgang (Linkslauf) langsamer ist. Sagen wir mal so 30% der sollGeschw.
Kann man das einfach umsetzten?

Zur Info da ist ein Schreibfeheler. das "t" ist zuviel bei "%u \tistGeschw: %u"

Nein. \t ist das Sonderzeichen für ein Tabulator-Sprung damit es einen ordentlichen Abstand zwischen der Ausgabe für soll und ist gibt.

Nö, das '\t' ist ein Tabulator.

Gruß Tommy

Hast Du denn einen Bts7960?

Das sollte durch

  const uint8_t beschl = 1;
  const uint8_t bremsen = 5;

gewährleistet werden. Tut es das nicht?

Doch, das ist ja aber nur Beschleunigen und Bremsen, jeweils für Rechts und Linkslauf (vor und zurück) identisch. Schön wäre noch das die Beschleunigung und Bremsen Rampen bleiben, aber bei Rechtslauf (Vor) volle Leistung möglich ist und bei Linkslauf (Rückwärts) nur z.B 80 Pwm möglich sind oder halt 1/3 PWM oder so.

EDIT: Ja der BTS ist heute gekommen.

@wno158 @Tommy56
Danke für die Info

Meinst Du eine maximale Geschwindigkeit für Rückwärts? Die habe ich tatsächlich noch nicht mit drin.

Ja genau. Also Vorwärts und Rückwärts unterschiedliche Vmax. Das wäre rückwärts sonnst bisschen viel.