Go Down

Topic: Gearshifter (Read 1 time) previous topic - next topic

Juless92

Mar 09, 2018, 07:30 pm Last Edit: Mar 09, 2018, 07:58 pm by Juless92
Guten Abend miteinander,

ich bin derzeit dabei für ein Projekt im Rahmen des Studiums einen Arduino zu programmieren.
Ich habe derzeit noch nicht wirklich viel Ahnung davon, ich bitte mich daher für dumme Fragen zu entschuldigen.
Das System besteht aus 2 Magnetventilen und einem doppeltwirkenenden Pneumatikzylinder. Mit dem Pneumatikzylinder soll das Getriebe eines Motorradmotors geschaltet werden.
Das System an sich funktioniert soweit, allerdings möchte ich, dass beim Drücken eines Buttons (Hoch-/oder Runterschalten) das Ventil nur für eine bestimme Zeit angesteuert wird, auch wenn der Button gedrückt bleibt. Das soll verhindern, dass der Schaltvorgang durch den Fahrer in irgendeiner Weise verlangsamt wird.
Nun meine Frage: Wie mache ich das?
Der Code lautet:

Code: [Select]
int solenoidPinup = 4; //upshift
int switchPinup = 7;
int switchStateup = 0;
int solenoidPindo = 8; //downshift
int switchPindo = 9;
int switchStatedo = 0;


void setup() {
// put your setup code here, to run once:
pinMode(solenoidPinup, OUTPUT);
pinMode(solenoidPindo, OUTPUT);
pinMode(switchPinup, INPUT);
pinMode(switchPindo, INPUT);
}

void loop() {
// put your main code here, to run repeatedly:
switchStateup = digitalRead(switchPinup);
switchStatedo = digitalRead(switchPindo);

if (switchStateup == HIGH) {
 digitalWrite(solenoidPinup, HIGH);
 
}

else if (switchStatedo == HIGH) {
 digitalWrite(solenoidPindo, HIGH);
}

else {
 
 digitalWrite(solenoidPinup, LOW);
 digitalWrite(solenoidPindo, LOW);
}

}


Schreibe ich nun beispielweise

Code: [Select]
if (switchStateup == HIGH) {
 digitalWrite(solenoidPinup, HIGH);
 delay(50);
 digitalWrite(solneoidPinup, LOW);
}

mag es nicht so richtig funktionieren.
Vielleicht kann mir jemand weiterhelfen, danke!
Den Schaltplan habe ich auch nochmals in den Anhang gemacht.

Grüße,
Juless

Tommy56

Setze Deinen Sketch bitte in Codetags (</> Button oben links im Forumseditor).

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

combie

Quote
delay(50);
Ich empfehle dir die konsequente Anwendung des "BinkWithoutDelay" Prinzips.

Dazu den einfachen endlichen Automaten.

Schreie nach Besserem, bis du es auch erhältst.
Das noch Bessere verabschiedet sich rechtzeitig vor deinem Lärm.

Quelle: Martin Gerhard Reisenberg

gregorss

... Wie mache ich das? ...
Wie Combie schon schrub, realisierst Du Dein Vorhaben am besten als „endlichen Automat". Was mir hierzu eingefallen ist, habe ich hier ins Netz gekippt. Beachte ggf. auch die Folgeseite.

Gruß

Gregor
Meine Pizza schmeckt am besten, wenn ich sie selber esse.

uwefed

#4
Mar 10, 2018, 12:00 am Last Edit: Mar 10, 2018, 12:00 am by uwefed
Die Flanke des Tasters detektieren (je nachdem wie er angeschlossen ist ein L-H Übergang oder ein H-L Übergang) und dann den Elektromagneten für die gewollte Zeit ansteuern.
Siehe https://www.arduino.cc/en/tutorial/switch

Grüße Uwe

Doc_Arduino

Hallo,

es erfordert einen entprellten Taster, damit wird ein Flag gesetzt, welches dafür sorgt das ein Zylinder angesteuert wird und gleichzeitig die Zeit dafür läuft. Der Taster darf während die Zeit läuft nicht nochmal abgefragt werden bzw. das Flag darf nicht weiterhin ausgewertet werden. Am Ende der Zeit Flag zurücksetzen und Zylinder abschalten.
Wie schon erwähnt führt dich ein Zustandsautomat sicher zum Ziel. Stichwort switch-case , enum und millis.
Das entprellen kann man nur weglassen wenn der Taster kürzer prellt wie der Zylinder angesteuert wird.
Anders gesagt, wenn du bei den Schaltzeiten den heutigen Automatikgetrieben Konkurrenz machen möchtest mußte entprellen.
Wären so meine Gedanken zum Thema.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Juless92

Vielen Dank für die vielen schnellen Antworten!
Ich werde mir die genannten Lösungen mal anschauen und mich bei Fragen melden.

Liebe Grüße


agmue

... im Rahmen des Studiums ...
Dann braucht es auch akademisches Niveau!

Konstanten sollten als solche deklariert werden und der Typ sollte stimmen:

Code: [Select]
const byte solenoidPinup = 4; //upshift
const byte switchPinup = 7;
bool switchStateup = 0;
const byte solenoidPindo = 8; //downshift
const byte switchPindo = 9;
bool switchStatedo = 0;


Mit R2-R3 machst Du bei HIGH einen Spannungsteiler. Je nach Transistor wird es funktionieren. Sauberer wären volle 5V am Gate, in dem Du R2 nach rechts verschiebst, ebenso R5.

Das System an sich funktioniert soweit, allerdings möchte ich, dass beim Drücken eines Buttons (Hoch-/oder Runterschalten) das Ventil nur für eine bestimme Zeit angesteuert wird, auch wenn der Button gedrückt bleibt.
Du möchtest eine monostabile Kippstufe.

Juless92

Danke agmue für die weitere Antwort!

Ich habe mich jetzt am endlichen Automaten versucht, bin aber leider gescheitert  :-[

Mein letzter Testsketch sah wie folgend aus:

Code: [Select]
const byte solenoidPinup = 4; //upshift
const byte switchPinup = 7;
bool switchStateup = 0;
const byte solenoidPindo = 8; //downshift
const byte switchPindo = 9;
bool switchStatedo = 0;
const int OPEN = 50;
unsigned long upMillis;
unsigned long downMillis;
enum Phase {UP, DOWN, INTERMEDIATE};
byte phase = INTERMEDIATE;


void setup() {
  // put your setup code here, to run once:
  pinMode(solenoidPinup, OUTPUT);
  pinMode(solenoidPindo, OUTPUT);
  pinMode(switchPinup, INPUT);
  pinMode(switchPindo, INPUT);
  phase = INTERMEDIATE;
}

void loop() {
  // put your main code here, to run repeatedly:
  switchStateup = digitalRead(switchPinup);
  switchStatedo = digitalRead(switchPindo);

  if (switchStateup == HIGH) {
    switch (phase) {{
      case INTERMEDIATE:
      phase = UP;
      upMillis = millis();
    }
    break;
    case UP:
    if (millis()-upMillis <= OPEN){
      digitalWrite(solenoidPinup, HIGH);
    }
    break;
 
  }
  }

  else if (switchStatedo == HIGH) {
    switch (phase) {{
      case INTERMEDIATE:
      phase = DOWN;
      downMillis = millis();
    }
    break;
    case DOWN:
    if (millis()-downMillis <= OPEN){
      digitalWrite(solenoidPindo, HIGH);
     }
     break;
   
   }
   }
 
 
  else {
     digitalWrite(solenoidPinup, LOW);
     digitalWrite(solenoidPindo, LOW);
   }
  }


Ich kann nun entweder den Button für Up 1x drücken und das Ventil schaltet beim gedrückt halten auch nicht zurück oder den Button für Down 1x. Danach geht gar nichts mehr.
Vielleicht kann mir jemand weiter helfen und Sorry für meine Planlosigkeit.

Viele Grüße
Juless

agmue

Das geht in die richtige Richtung :)

Wenn die Formatierung der IDE Dir

Code: [Select]
  }
  }

anzeigt, dann stimmt was nicht. In diesem Fall die Syntax von switch.

Im nächsten Schritt möchtest Du nur die Änderung eines Eingangs auswerten, also die Flanke. Aus

Code: [Select]
if (switchStatedo == HIGH)
wird dann

Code: [Select]
if (altSwitchStatedo == LOW && aktuellSwitchStatedo == HIGH)
oder kürzer

Code: [Select]
if (!altSwitchStatedo && aktuellSwitchStatedo)

Bei prellenden Tastern benötigst Du noch eine Entprellung, indem Du dies nur alle 30 ms ausführst:

Code: [Select]
  switchStateup = digitalRead(switchPinup);
  switchStatedo = digitalRead(switchPindo);

Juless92

Okay und hier der nächste Versuch:

Code: [Select]
const byte solenoidPinup = 4; //upshift
const byte switchPinup = 7;
bool aktuellswitchStateup = 0;
bool altswitchStateup = 0;
const byte solenoidPindo = 8; //downshift
const byte switchPindo = 9;
bool aktuellswitchStatedo = 0;
bool altswitchStatedo = 0;
const int OPEN = 50;
unsigned long upMillis;
unsigned long downMillis;
unsigned long debounce = 30;
unsigned long pushMillis;
enum Phase {UP, DOWN, INTERMEDIATE};
byte phase = INTERMEDIATE;


void setup() {
  // put your setup code here, to run once:
  pinMode(solenoidPinup, OUTPUT);
  pinMode(solenoidPindo, OUTPUT);
  pinMode(switchPinup, INPUT);
  pinMode(switchPindo, INPUT);
  phase = INTERMEDIATE;
}

void loop() {
  // put your main code here, to run repeatedly:
  if (millis() - pushMillis > debounce) {
  aktuellswitchStateup = digitalRead(switchPinup);
  aktuellswitchStatedo = digitalRead(switchPindo);
  pushMillis = millis();
  }
 

  if (!altswitchStateup && aktuellswitchStateup) {
    switch (phase) {{
      case INTERMEDIATE:
      phase = UP;
      upMillis = millis();
    }
    break;
    case UP:
    if (millis()-upMillis <= OPEN){
      digitalWrite(solenoidPinup, HIGH);
    }
    break;
 
  }
 }

  else if (!altswitchStatedo && aktuellswitchStatedo) {
    switch (phase) {{
      case INTERMEDIATE:
      phase = DOWN;
      downMillis = millis();
    }
    break;
    case DOWN:
    if (millis()-downMillis <= OPEN){
      digitalWrite(solenoidPindo, HIGH);
     }
     break;
   
   }
 
 }
 
 
  else {
     digitalWrite(solenoidPinup, LOW);
     digitalWrite(solenoidPindo, LOW);
   }
   altswitchStateup = aktuellswitchStateup;
   altswitchStatedo = aktuellswitchStatedo;
  }


Nun passiert gar nichts mehr, egal welchen Knopf ich drücke.
Was mache ich falsch?

Viele Grüße

Tommy56

Schau Dir mal die {} im switch/case an.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

gregorss

... Was mache ich falsch?
Wenn ich Code debugge, fange ich immer damit an, den Code in eine gut lesbare Form zu bringen. Meistens springen einem dann die Fehler geradezu ins Auge. Damit meine ich jetzt auch (aber nicht nur) solche Klammergeschichten wie sie Tommy gerade angemerkt hat.

Gruß

Gregor
Meine Pizza schmeckt am besten, wenn ich sie selber esse.

Juless92

Schau Dir mal die {} im switch/case an.

Gruß Tommy
Ist es so richtig?

Code: [Select]
const byte solenoidPinup = 4; //upshift
const byte switchPinup = 7;
bool aktuellswitchStateup = 0;
bool altswitchStateup = 0;
const byte solenoidPindo = 8; //downshift
const byte switchPindo = 9;
bool aktuellswitchStatedo = 0;
bool altswitchStatedo = 0;
const int OPEN = 50;
unsigned long upMillis;
unsigned long downMillis;
unsigned long debounce = 30;
unsigned long pushMillis;
enum Phase {UP, DOWN, INTERMEDIATE};
byte phase = INTERMEDIATE;


void setup() {
  // put your setup code here, to run once:
  pinMode(solenoidPinup, OUTPUT);
  pinMode(solenoidPindo, OUTPUT);
  pinMode(switchPinup, INPUT);
  pinMode(switchPindo, INPUT);
  phase = INTERMEDIATE;
}

void loop() {
  // put your main code here, to run repeatedly:
  if (millis() - pushMillis > debounce) {
  aktuellswitchStateup = digitalRead(switchPinup);
  aktuellswitchStatedo = digitalRead(switchPindo);
  pushMillis = millis();
  }
 

  if (!altswitchStateup && aktuellswitchStateup) {
    switch (phase) {
      case INTERMEDIATE:
        phase = UP;
        upMillis = millis();
        break;
      case UP:
        if (millis()-upMillis <= OPEN){
        digitalWrite(solenoidPinup, HIGH);
        }
      break;
   }
  }

  else if (!altswitchStatedo && aktuellswitchStatedo) {
    switch (phase) {
      case INTERMEDIATE:
        phase = DOWN;
        downMillis = millis();
        break;
      case DOWN:
        if (millis()-downMillis <= OPEN){
        digitalWrite(solenoidPindo, HIGH);
        }
      break;   
   }
  }
 
  else {
     digitalWrite(solenoidPinup, LOW);
     digitalWrite(solenoidPindo, LOW);
     }
   altswitchStateup = aktuellswitchStateup;
   altswitchStatedo = aktuellswitchStatedo;
}


Allerdings funktionierts es immer noch nicht. Bin wohl eher schlecht im Debugging  :-\

Doc_Arduino

#14
Mar 13, 2018, 05:17 pm Last Edit: Mar 13, 2018, 06:06 pm by Doc_Arduino
Hallo,

die Wartezeit OPEN oder was das sein soll muss unsigned sein. Also entweder unsigned int/long oder hier auch byte möglich.

Ansonsten verschachtelst du if/if else mit 2x switch case kompliziert ineinander was zum scheitern führt.
Der Zustand wechselt zum Bsp. auch nur zwischen UP und DOWN.
Eine zweite phase Zuweisung in setup ist überflüssig.

Male dir einen Ablaufplan bis der schlüssig ist. Dann kannste das programmieren.
Doppelte switch case mit gleichen Ausdruck sind auch tödlich.

Edit:
Was ich mich gerade frage ist, benötigt man dafür nicht 2 Zylinder. Je einen für hoch- und runterschalten. Wie macht ihr das mit einem Zylinder? Sonst schaltet man ja unweigerlich wieder runter wenn man vorher hochgeschalten hat. Da komme ich gerade nicht mit.  https://www.festo.com/wiki/de/Pneumatikzylinder
Außer ihr habt einen doppelten Zylinder der nach beiden Seiten einfach wirkt, also mit 2 Federn. Der demnach ohne Druckluft in seine Mittelstellung zurückkehrt. Wären jetzt so meine Gedanken.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Go Up