Schaltautomat Motorrad / Proof of Concept

Wie weit bist du denn schon mit dem tüfteln?

1 Like

Im Moment bin ich noch an einem anderen Projekt zugange. Aber der QuickShifter wird auf jedenfall ausprobiert. Hauptproblem aktuell ist ein Kraftaufnahmesensor der bezahlbar ist. Find im Moment nur welche aus der Messtechnik die weit über dem Budget liegen. Der Kollege der einen Quickshifter für sein pitbike vertreibt bietet auch welche an zum Nachkauf für ca.80 Euro. D.h. irgendwo im Netz muss es welche geben die u100€ kosten.
Ich suche nach Kraftmessdose, Kraftmesser, Zug&Drucksensor aber bisher kein bezahlbares Ergebnis. Oder ich frage bei dem Pitbike Kollege an ob er mir einen verkauft mit Library und technischen Daten für die Ansteuerung. Mache mir generell im vorhinein mehr Gedanken zum Projekt, besorge dann alle Teile und mache das Ding in einem Schwung übers Wochenende fertig. (Zumindest wenn es funktioniert =)_). Ein Kraftmesser mit 2 metrischen Gewinden wäre Optimal, weil einfach nur 2 neue Schaltgestänge mit Innengewinde gedreht werden müssen für Plug&Play. Vorschläge gern einbringen. Danke

Ich sagte dir schon: Dehnmessstreifen!
10 Stück für unter 5 Euronen beim Chinamann deines Vertrauens.

Aber gut, wenn dir das zu einfach/billig ist…

1 Like

Hohl dir einfach schon empfohlenen die Dehnmessstreifen und fang an zu testen :wink:

1 Like

Ja wenn dann muss das schon Haltbar und qualitativ sein. Aber ok, werde dann mal nach ordentlichen Dehnmessstreifen suchen. Und ja, Anbau und Auslesen der Messdaten im fahrbetrieb per Display erscheint mir erstmal vernünftig.

Hast du zufällig noch ein 12V auf Arduino Spannung Netzteil da, oder weißt wo man sowas günstig herbekommt?

Ne, zumindest nichts fertiges. Habe ja alles direkt auf einer Platine.
Man kann aber bestimmt auch einen einfachen Stepdown Wandler benutzen.
Die gibt es massenweise für kleines Geld. Auch regelbar. LM2596 zum Beispiel.
Ist erstmal recht groß, aber für einen Testaufbau bestimmt nicht so verkehrt.

Ob die das Optimum für den Betrieb an einem Motorrad sind, kann ich leider nicht sagen.

1 Like

Habe jetzt mal angefangen. Programmgrundaufbau steht soweit. Ein und Ausschalten per Schalter und das Kupplungssignal unterbricht das Auslösen. Unterbrecherzeiten in ms mit Poti einstellbar. Soll dann aber nach Testphase fest eingestellt werden. Display gibt die Werte aus und LED´s zeigen Systemzustand. Also ,AN, für Betrieb und eine andere LED ob die Kupplung gezogen wird. Habe mit dem Optokoppler (4N35) experimentiert. Habe ein Dehnmesssensor und noch ein paar Kleinigkeiten bestellt. Messtechnik und Sensorik ist eine weile her…kann der Sensor zwischen Zug und Druckspannung überhaupt unterscheiden? Aufgebaut wie ein Aluprofil mit Bohrungen durch die Neutrale Faser für Materialschwächung. An der Randfaser dann die Aufgeklebten DMS. Bei AMZN für unter 10€. Wenn nicht, kann das nicht funktionieren, da ich Softwaretechnisch klar unterscheiden muss wann ich normal herunterschalte, und wann im Vollgasbetrieb hochgeschalten wird. Hoffe das geht =)

Des weiteren muss ich mir nochmal die Okto-Beschaltung anschauen. Ich habe zu Testzwecken die UNO Spannung verwendet beim Eingang 1 und 2. Also einfach um den Okto zum durchschalten zu bringen. An der Ausgangsseite versucht das Signal an den UNO zu senden. Was bis dahin nicht funktioniert hat. Eine angeschlossene LED am Ausgang war auch so gut wie fast ganz dunkel. Schaltet aber sichtbar.

Real wird dann auf einer Seite wahrscheinlich ein schlecht gleichgerichtetes 12V Signal in den Opto reinkommen, auf der anderen seite soll ein nutzbares Digitalsignal für den UNO rauskommen. Das muss noch verbessert werden.

Falls der Sensor zwischen Zug und Druck unterscheiden kann, und das mit dem Okto funktioniert, sehe ich keine Probleme für erste Testläufe.

Der DMS kann das in der Theorie problemlos (Funktionsweise). Jedoch wird das mit dem Aufbau zusammenhängen ob das so funktioniert.

Muss gestehen, persönlich glaube ich nicht an eine langfristig funktionale und verlässliche Lösung mit Dehnmessstreifen. Sonst würden die Hersteller der marktführenden Systeme nicht so einen Aufwand betreiben.
Zumindest nicht ohne eine Art Mechanik in einem kleinen Gehäuse.
Aber ich lasse mich äußerst gerne vom Gegenteil überzeugen :slight_smile:

1 Like

Druckmesser verbaut und trocken getestet. Im Moment habe ich das Problem dass die Unterbrecherzeit zu lange erreicht ist. Der Druckmesser baut den Aufgebauten Druckwert zu langsam ab, sodass das Schaltrelais nach der eingestellten Unterbrecherzeit von ein paar Millisekunden erneut getriggert wird. (Also ein Unterbrechintervall ist einprogrammiert ohne delay, dieser wird jedoch direkt wieder getriggert)
Mir fällt im Moment keine elegante Lösung ein um zu erreichen das nur 1x Unterbochen wird, und dann erst wieder nach einer gewissen zeit z.b… Es wäre jedoch schade wenn man beim fahren nicht schnell hintereinander schalten kann und erst eine abklingzeit abwarten muss. Villeicht sollte ein Schaltvorgang erst wieder möglich sein wenn z.b. 75% der Auslösekraft erreicht ist? Oder gibt es ganz andere Lösungsvorschläge. Kann man den Sensor villeicht schneller auslesen oder ähnliches.

(Unterbrecherzeit und andere Werte zu Testzwecken verändert.)

Jemand tipps?

//hauptschalter
int QS_schaltstatus = 0;
const int hauptschalterpininput = 2;
const int hauptschalterled = 7;


//schalthebelsensor auslesen
#include <HX711_ADC.h>
#if defined(ESP8266)|| defined(ESP32) || defined(AVR)
#include <EEPROM.h>
#endif
const int HX711_dout = 4; //mcu > HX711 dout pin
const int HX711_sck = 5; //mcu > HX711 sck pin
HX711_ADC LoadCell(HX711_dout, HX711_sck);
const int calVal_eepromAdress = 0;
unsigned long t = 0;


//zündunterbrechung
const int zuendunterbrecher_led_gruen = 13;
const int ausloesekraft = 200;
const int unterbrecherzeit = 500;     //TEST


//kupplungscheck
const int kupplungsgeberpin = 8;      //BUTTON als TEST muss später über Opto gehen
int kupplungsstatus = 0;
const int kupplungsgeberled = 10;


void setup() {

  //hauptschalter
  pinMode(hauptschalterpininput, INPUT);
  pinMode(hauptschalterled, OUTPUT);

  //schalthebelsensor auslesen
  Serial.begin(57600); delay(10);
  Serial.println();
  Serial.println("Starting...");

  LoadCell.begin();
  float calibrationValue;
  calibrationValue = 696.0;
#if defined(ESP8266)|| defined(ESP32)
#endif
  unsigned long stabilizingtime = 2000;
  boolean _tare = true;
  LoadCell.start(stabilizingtime, _tare);
  if (LoadCell.getTareTimeoutFlag()) {
    Serial.println("Timeout, check MCU>HX711 wiring and pin designations");
    while (1);
  }
  else {
    LoadCell.setCalFactor(calibrationValue);
    Serial.println("Startup is complete");
  }


  //zündunterbrechung
  pinMode(zuendunterbrecher_led_gruen, OUTPUT);


  //kupplungscheck
  pinMode(kupplungsgeberpin, INPUT);
  pinMode(kupplungsgeberled, OUTPUT);

}




void loop() {

  hauptschalter();

  schalthebelsensor_lesen();

  zuendunterbrechung();

  kupplungscheck();

  serialPrint();

}



void hauptschalter() {

  QS_schaltstatus = digitalRead(hauptschalterpininput);

  if (QS_schaltstatus == HIGH ) {         //&& clutchState != 1
    digitalWrite(hauptschalterled, HIGH);
  }
  else {
    digitalWrite(hauptschalterled, LOW);
  }
}


int schalthebelsensor_lesen() {

  static boolean newDataReady = 0;
  const int serialPrintInterval = 0;

  if (LoadCell.update()) newDataReady = true;

  if (newDataReady) {
    if (millis() > t + serialPrintInterval) {
      float i = LoadCell.getData();
      newDataReady = 0;
      t = millis();
    }
  }

  if (Serial.available() > 0) {
    char inByte = Serial.read();
    if (inByte == 't') LoadCell.tareNoDelay();
  }

  if (LoadCell.getTareStatus() == true) {
    //Serial.println("Tare complete");
  }
  return LoadCell.getData();
}


void zuendunterbrechung() {

  static uint32_t previousMillis = 0;
  if (LoadCell.getData() >= ausloesekraft && digitalRead(hauptschalterpininput) == HIGH && digitalRead(kupplungsgeberpin) == LOW ) {
    digitalWrite(zuendunterbrecher_led_gruen, HIGH);          //Geht LED an / SSR AN /Zündung wird unterbrochen
    previousMillis = millis();
  }
  if (millis() - previousMillis > unterbrecherzeit && digitalRead(zuendunterbrecher_led_gruen) == HIGH)
  {
    digitalWrite(zuendunterbrecher_led_gruen, LOW);           //Geht LED aus / SSR AUS / Zündunterbrechung aufheben
  }
}


void kupplungscheck() {

  kupplungsstatus = digitalRead(kupplungsgeberpin);

  if (kupplungsstatus == HIGH) {
    kupplungsstatus = 1;
    digitalWrite(kupplungsgeberled, HIGH);
  }
  else {
    kupplungsstatus = 0;
    digitalWrite(kupplungsgeberled, LOW);
  }
}


void serialPrint() {

  Serial.print("digitalRead(hauptschalterpininput)= ");
  Serial.print(digitalRead(hauptschalterpininput));

  Serial.print("\t");

  Serial.print("LoadCell.getData()= ");
  Serial.print(LoadCell.getData());

  Serial.print("\t");

  Serial.print("digitalRead(zuendunterbrecher_led_gruen)= ");
  Serial.print(digitalRead(zuendunterbrecher_led_gruen));

  Serial.print("\t");

  Serial.print("digitalRead(kupplungsgeberpin)= ");
  Serial.println(digitalRead(kupplungsgeberpin));


}



Nur kurz, um nicht ganz dumm zu sterben:

Wo finde ich das in Deinem Sketch?

Ich hab auch ne Idee, wie man das lösen könnte…

Bei, void zuendunterbrechung(), wird die Zündung für die zeit von, unterbrecherzeit, unterbrochen. D. H. Anstelle der zuendunterbrecher-led-grün soll das Halbleiterrelais für die unterbrecherzeit in dem fall zu test Zwecken 200ms schalten (später dann aber villeicht 25ms oder 50ms). Im Moment wird jedoch öfters hintereinander die Unterbrechung getriggert weil der druckwert vom sensor langsam sinkt. Es fehlt also im Moment eine Lösung wie ich den Schalthebel für das erforderliche schaltsignal belasten kann, ohne das es drauf ankommt wie stark ich den Schalthebel gedrückt habe. Im Moment kann ich 5 kg anlegen, und warte eine halbe Ewigkeit bis der wert wieder unter meinen Kraftschwellenwert sinkt. Viel zu lange wenn man mal schnell 2-3 gänge hintereinander hochschalten möchte.
Oder was meinst genau?

Das ich nicht weiss, was Dein Drucksensor ist.

Aber schau mal, was ich Dir alles ein und auskommentiert habe und Dein loop auch verändert.

Du hast Dir vermutlich eher ein Zeitproblem geschaffen, als das die Werte nicht richtig erfasst werden.

//hauptschalter
int QS_schaltstatus = 0;
const int hauptschalterpininput = 2;
const int hauptschalterled = 7;


//schalthebelsensor auslesen
#include <HX711_ADC.h>
#if defined(ESP8266)|| defined(ESP32) || defined(AVR)
#include <EEPROM.h>
#endif
const int HX711_dout = 4; //mcu > HX711 dout pin
const int HX711_sck = 5; //mcu > HX711 sck pin
HX711_ADC LoadCell(HX711_dout, HX711_sck);
const int calVal_eepromAdress = 0;
unsigned long t = 0;


//zündunterbrechung
const int zuendunterbrecher_led_gruen = 13;
const int ausloesekraft = 200;
const int unterbrecherzeit = 500;     //TEST


//kupplungscheck
const int kupplungsgeberpin = 8;      //BUTTON als TEST muss später über Opto gehen
int kupplungsstatus = 0;
const int kupplungsgeberled = 10;


void setup() {

  //hauptschalter
  pinMode(hauptschalterpininput, INPUT);
  pinMode(hauptschalterled, OUTPUT);

  //schalthebelsensor auslesen
  Serial.begin(57600); delay(10);
  Serial.println();
  Serial.println("Starting...");

  LoadCell.begin();
  float calibrationValue;
  calibrationValue = 696.0;
#if defined(ESP8266)|| defined(ESP32)
#endif
  unsigned long stabilizingtime = 2000;
  boolean _tare = true;
  LoadCell.start(stabilizingtime, _tare);
  if (LoadCell.getTareTimeoutFlag()) {
    Serial.println("Timeout, check MCU>HX711 wiring and pin designations");
    while (1);
  }
  else {
    LoadCell.setCalFactor(calibrationValue);
    Serial.println("Startup is complete");
  }

  //zündunterbrechung
  pinMode(zuendunterbrecher_led_gruen, OUTPUT);

  //kupplungscheck
  pinMode(kupplungsgeberpin, INPUT);
  pinMode(kupplungsgeberled, OUTPUT);
}

void loop() {
  hauptschalter();
  schalthebelsensor_lesen(); // Der Rückgabewert ist unnütz?
  zuendunterbrechung();
  kupplungscheck();
  zuendunterbrechung();

  serialPrint(); // das hier schaffst Du nicht in der Kürze der Zeit...
}

void hauptschalter() {
  /*
    QS_schaltstatus = digitalRead(hauptschalterpininput);

    if (QS_schaltstatus == HIGH ) {         //&& clutchState != 1
      digitalWrite(hauptschalterled, HIGH);
    }
    else {
      digitalWrite(hauptschalterled, LOW);
    }
  */
  digitalWrite(hauptschalterled, digitalRead(hauptschalterpininput));
}

int schalthebelsensor_lesen() {   // Was soll da zurück gegeben werden?
  /*
    static boolean newDataReady = 0;
    const int serialPrintInterval = 0;

    if (LoadCell.update()) newDataReady = true;

    if (newDataReady) {
      if (millis() > t + serialPrintInterval) {
        float i = LoadCell.getData();
        newDataReady = 0;
        t = millis();
      }
    }

    if (Serial.available() > 0) {
      char inByte = Serial.read();
      if (inByte == 't') LoadCell.tareNoDelay();
    }
  */
  if (LoadCell.update()) {
    if (millis() > t) {
      float i = LoadCell.getData(); // was macht i???
      t = millis();
    }
  }

  if (Serial.available() > 0) {
    char inByte = Serial.read();
    if (inByte == 't') LoadCell.tareNoDelay();
  }
  if (LoadCell.getTareStatus() == true) {
    //Serial.println("Tare complete");
  }
  return LoadCell.getData(); // Soll hier etwa i hin???? Hier gibt es VIELE Zweifel!
}

void zuendunterbrechung() {
  static uint32_t previousMillis = 0;
  if (LoadCell.getData() >= ausloesekraft && digitalRead(hauptschalterpininput) == HIGH && digitalRead(kupplungsgeberpin) == LOW ) {
    digitalWrite(zuendunterbrecher_led_gruen, HIGH);          //Geht LED an / SSR AN /Zündung wird unterbrochen
    previousMillis = millis();
  }
  if (millis() - previousMillis > unterbrecherzeit && digitalRead(zuendunterbrecher_led_gruen) == HIGH)
  {
    digitalWrite(zuendunterbrecher_led_gruen, LOW);           //Geht LED aus / SSR AUS / Zündunterbrechung aufheben
  }
}

void kupplungscheck() {
  /*
    kupplungsstatus = digitalRead(kupplungsgeberpin);

    if (kupplungsstatus == HIGH) {
      kupplungsstatus = 1;
      digitalWrite(kupplungsgeberled, HIGH);
    }
    else {
      kupplungsstatus = 0;
      digitalWrite(kupplungsgeberled, LOW);
    }
  */
  digitalWrite(kupplungsgeberled, digitalRead(kupplungsgeberpin));
}


void serialPrint() {

  Serial.print("digitalRead(hauptschalterpininput)= ");
  Serial.print(digitalRead(hauptschalterpininput));

  Serial.print("\t");

  Serial.print("LoadCell.getData()= ");
  Serial.print(LoadCell.getData());

  Serial.print("\t");

  Serial.print("digitalRead(zuendunterbrecher_led_gruen)= ");
  Serial.print(digitalRead(zuendunterbrecher_led_gruen));

  Serial.print("\t");

  Serial.print("digitalRead(kupplungsgeberpin)= ");
  Serial.println(digitalRead(kupplungsgeberpin));
}

Schaue es mir morgen genauer an! Danke schonmal. Immer schwierig das nachzuvollziehen ohne Aufbau nebenan und Schaltplan.

void hauptschalter() → Einen Hauptschalter zum An und Ausschalten des Schaltautomaten am Lenker.

int schalthebelsensor_lesen() → gibt einen Kraftwert vom Dehnungssensor in Gewichtskraft [gramm] aus. Ist geklaut aus dem Beispiel, check ich auch nicht ganz was das i soll =D

void zuendunterbrechung() → Wenn eine Kraft von 200 (gramm) am Sensor erreicht wird, mein Hauptschalter aktiv ist, und die Kupplung nicht gezogen ist, soll die Zündung für erstmal zu testzwecken 500 (ms) unterbrochen werden. Die LED soll den Status anzeigen erstmal.

void kupplungscheck()–> Checkt ob man gerade die Kupplung zieht, z.b. fürs Anfahren oder runterschalten. Soll ja nicht beim Anfahren unterbrochen werden, sondern erst ab gang 2 bis 6…

Ich könnte ja auch sagen. Wenn der Kraftwert von 200gramm erreicht ist, Unterbreche die Zeit für 500ms → und setzte den Kraftsensor wert auf 0, um direkt wieder einzusteigen und die abklingzeit und die mehrfachtriggerung zu verhindern. Aber nicht die eleganteste Lösung schätze ich.

Danke für die Rückmeldung

Gerne.
Ich schau nochmal drüber, wenn ich nachher Zeit finde. Das kann vermutlich noch eingestampft werden.

1 Like

Was genau meinst du mit
serialPrint(); // das hier schaffst Du nicht in der Kürze der Zeit…
Bisher dachte ich der Serielle Monitor ist dafür da sich anzeigen zu lassen was das Programm macht in der Programmierphase. Danach würde ich Serial.begin(…) auskommentieren. Der Drucksensor braucht das ja nicht um mit dem UNO zu kommunizieren im Betrieb richtig?
Oder was genau meinst du damit?

Genau das ist gemeint. Die Ausgabe der ganzen Serial.print´s dauert einige Zeit und verfälscht damit das Messergebnis.

Mir ist überhaupt nicht klar was die

schalthebelsensor_lesen()

überhaupt für einen Sinn hat. Denn

void zuendunterbrechung() {
  if (LoadCell.getData() [...]

Holt den Wert frisch aus dem Sensor. Klar, ist für die Tarierung mit “t” einmalig sinnvoll. Aber jeder Aufruf von getData wird wieder Verzögerungen hervorrufen.

Dann das Hauptproblem in meinen Augen:
Du misst dauerhaft den Wert (Gewicht) ohne zu erkennen in welcher Richtung Du unterwegs bist.
Was Du haben möchtest ist eine Flankenerkennung. Also:
198
199
200 → Jetzt 50ms reagieren
201
202
199 → Zurücksetzen und auf die nächste Flanke warten

1 Like

Ich verstehe, stimmt du hast vollkommen recht. Habe das restliche programm drumherum gebaut. Werde ich heute abend testen und rausschmeißen. Und dann ohne Serial villeicht mit OLED auslesen.
Flankenerkennung hört sich gut an und wird untersucht!

Dir ist das zu langsam.

Dann erlaube mir bitte folgende Fragen:
Das Modul kann 80SPS hast du das aktiviert?
Die Lib bildet den Mittelwert aus 16 Messungen, hast du das verändert?
Da ist eine Geschwindigkeitssteigerung um den Faktor 128 möglich, gegenüber den default Einstellungen.
Natürlich auf Kosten der Genauigkeit.

Und jetzt die Kernfrage:
Wozu eine 24Bit Wandlung, ist das nicht völlig überzogen?
Welche Genauigkeit und Auflösung benötigst du wirklich?

1 Like

Kenne mich überhaupt noch nicht mit dem Gerät aus. Habe einfach das gegebene Beispiel weiterverarbeitet. Weist du was ich machen muss bzw. wo dokumentations content ist um mich einzulesen?
Kann die Fragen nicht beantworten. Zumindest noch nicht.