Go Down

Topic: Servo in 4 Verschiedene Positionen fahren mit 3 Tastern (Read 1 time) previous topic - next topic

BeMarvelous

Das ist er jetzt der Code, das einzige das mir noch fehlt ist,
dass er der Servo erst fährt wenn die Zündung aus ist,und nicht so wie jetzt zuvor, am besten noch mit nem kleinen delay...
aber das bekomme ich einfach nicht gebacken...


Code: [Select]
#include <Servo.h>

Servo S1;                         //Stellservo für Gänge
int T0 = 4;                       //Taster für Gang 0
int T1 = 2;                       //Taster für Gang 1
int T2 = 6;                       //Taster für Gang 2
int T3 = 7;                       //Taster für Gang 3

int potPin = 0;
int valPot = 0;
int ZuendungsWert = 0;
int Zuendung = 13;
byte Merker;

void setup() {
  Serial.begin(9600);
  pinMode(T0, INPUT);
  pinMode(T1, INPUT);
  pinMode(T2, INPUT);
  pinMode(T3, INPUT);
  pinMode(Zuendung, OUTPUT);
  S1.attach(9);
}

void loop() {
  valPot = analogRead(potPin);
  Serial.print("Wert: ");
  Serial.print(valPot);
  delay(300);

  byte ZuendungsWert = 0;
  ZuendungsWert += digitalRead(T0);                      //Ausschalten der Zuendung bei betätigen eines Tasters
  ZuendungsWert += digitalRead(T1);
  ZuendungsWert += digitalRead(T2);
  ZuendungsWert += digitalRead(T3);
  if(ZuendungsWert >0) {
    digitalWrite(Zuendung,LOW);
  }
//Hier soll die Abfrage erfolgen ob der Servo auch wirklich richtig Steht, noch sind es nur ausgedachte Zahlenwerte und Winkel
 
   if((Merker == 1)&&(valPot>950)&&(valPot<1000)) {              //Wenn Servo die 9 Grad Angabe hat und ein Wertebereich vom Poti erreicht wird, schaltet die Zündung an
    digitalWrite(Zuendung,HIGH);
  }
   if((Merker == 0)&&(valPot>780)&&(valPot<820)) {              //Wenn Servo die 30 Grad Angabe hat und ein Wertebereich vom Poti erreicht wird, schaltet die Zündung an
    digitalWrite(Zuendung,HIGH);
  }
   if((Merker == 2)&&(valPot>480)&&(valPot<520)) {             //Wenn Servo die 60 Grad Angabe hat und ein Wertebereich vom Poti erreicht wird, schaltet die Zündung an
    digitalWrite(Zuendung,HIGH);
  }
   if((Merker == 3)&&(valPot>10)&&(valPot<100)) {            //Wenn Servo die 90 Grad Angabe hat und ein Wertebereich vom Poti erreicht wird, schaltet die Zündung an
    digitalWrite(Zuendung,HIGH);
  }
 
  if(digitalRead(T0) == HIGH) {                         //Servoposition für Leerlauf
    byte(Merker = 0);
    S1.write(30);
  }
  if(digitalRead(T1) == HIGH) {                         //Servoposition für 1.Gang
    byte(Merker = 1);
    S1.write(9);
  }
  if(digitalRead(T2) == HIGH) {                         //Servoposition für 2.Gang
    byte(Merker = 2);
    S1.write(60);
  }
  if(digitalRead(T3) == HIGH) {                         //Servoposition für 3.Gang
    byte(Merker = 3);
    S1.write(90);
  }
}


Vielen Dank schon mal für Hilfe und Anregungen hierzu :)

combie

Quote
dass er der Servo erst fährt wenn die Zündung aus ist,und nicht so wie jetzt zuvor, am besten noch mit nem kleinen delay...
Du möchtest an der Stelle einen einfachen endlichen Automaten einsetzen.
(ja, auch wenn du noch nicht weißt, was das ist)
Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

Doc_Arduino

Hallo,

hab mir mal Gedanken gemacht u.a. auch wegen der Zündungsverzögerung.

Das switch case besteht nur aus Funktionsaufrufen die fast alle einen bool Status zurückmelden, sobald sie fertig sind. Wenn die Funktion ein "okay" (true) zurück gibt, dann springt switch zum nächsten case.
Wenn ich im Ablauf nichts falsch verstanden habe sollte es funktionieren wie gewünscht.

Du musst jetzt die Werte in Zeile
17, 18, 19
und
Zeile 44 bis 47
und
die Verzögerungszeiten für die Zündung in Zeile 86 und 112 anpassen. Derzeit beide auf 1000 ms gesetzt, damit was sieht.

Code: [Select]

/*
  Doc_Arduino - german Arduino Forum
  IDE 1.8.8
  Arduino Mega2560
  21.12.2018

  https://forum.arduino.cc/index.php?topic=564644.0

  Pinouts  >>> http://www.pighixxx.net/pinoutspg/boards/
  Uno      >>> http://www.pighixxx.net/portfolio-items/uno/?portfolioID=314
  Mega2560 >>> http://www.pighixxx.net/portfolio-items/mega/?portfolioID=314
*/

#include <Servo.h>

Servo S1;                         // Stellservo für Gänge
const byte pinPoti = A2;          // analoger Eingang vom Poti
const byte pinZuendung = 34;
const byte pinServo = 11;

enum state {WARTEN, ZUEND_AUS, SCHALTEN, CHECK_POS, ZUEND_EIN};
state zustand = WARTEN;

enum debug {RELEASE, DEBUG};    // serielle Debugausgaben nein/ja
const debug debugging = DEBUG;  

struct t_setup
{
  const byte taster;
  const byte servoWinkel;
  const unsigned int potiMin;
  const unsigned int potiMax;

  // Konstruktor
  t_setup (byte _t, byte _w, unsigned int _min, unsigned int _max):
    taster(_t),
    servoWinkel(_w),
    potiMin(_min),
    potiMax(_max)
  {}
};

t_setup Getriebe[] = {  // sämtliche konstante Einstellungen, Gänge gleich Indexnummer
  {2, 30, 780,  820},   // Tasterpin, Servowinkel, Poti Min/Max
  {3,  9, 950, 1000},
  {4, 60, 480,  520},
  {5, 90,  10,  100},
};
  
const byte ANZAHL = sizeof(Getriebe) / sizeof(Getriebe[0]);

struct t_aktuell  // Merker bzw. Zwischenspeicher
{
  byte gang = 0;                          // Neutralgang Startbedingung
  byte winkel = Getriebe[0].servoWinkel;  // Servo in Neutralgang Position
  unsigned long zeit = 0;
} merker;


void setup()
{
  Serial.begin(9600);
  
  for (byte i = 0; i < ANZAHL; i++) {
    pinMode(Getriebe[i].taster, INPUT);
  }
 
  pinMode(pinZuendung, OUTPUT);
  S1.attach(pinServo);
}

void loop()
{
  
  switch (zustand) {
    case WARTEN:  if (update_GetriebeGang() ){
                    zustand = ZUEND_AUS;  
                    merker.zeit = millis();
                    if (debugging == DEBUG) {
                      Serial.print("Gangwechsel zu "); Serial.println(merker.gang);  
                      Serial.println("status: ZUEND AUS");
                    }
                  }  
                  break;

    case ZUEND_AUS: if (delayZuendungAUS(1000, merker.gang, merker.zeit) ) {  // erster Wert Verzögerung zum Zündung ausschalten
                      zustand = SCHALTEN;
                      if (debugging == DEBUG) {
                        Serial.println(F("Zuendung ist aus"));
                        Serial.println(F("status: SCHALTEN "));
                      }
                    }
                    break;
      
    case SCHALTEN:  merker.winkel = Getriebe[merker.gang].servoWinkel;
                    zustand = CHECK_POS;
                    if (debugging == DEBUG) {
                      Serial.print(F("Servo move to "));Serial.println(merker.winkel);
                      Serial.println(F("status: CHECK_POS"));
                    }
                    break;
      
    case CHECK_POS: if (checkServoPosition(merker.gang) ) {
                      zustand = ZUEND_EIN;
                      merker.zeit = millis();
                      if (debugging == DEBUG) {
                        Serial.println(F("status: ZUEND EIN"));
                      }
                    }
                    break;

    case ZUEND_EIN: if (delayZuendungEIN(1000, merker.zeit) ) { // erster Wert Verzögerung zum Zündung einschalten
                      zustand = WARTEN;
                      if (debugging == DEBUG) {
                        Serial.println(F("Zuendung ist ein"));
                        Serial.println(F("status: WARTEN"));
                      }
                    }
                    break;                

    default: break;
  }

  moveServo(merker.winkel);   // Servo muss immer angesteuert werden

}


//

void moveServo(byte winkel)
{
  static unsigned long last_ms = 0;

  if (millis() - last_ms > 19) {
    S1.write(winkel);
    last_ms = millis();
  }

}

bool delayZuendungAUS(unsigned int delay, byte gang, unsigned long last_ms)
{
  static byte last_Gang = 0;
  bool state = false;

  if (last_Gang != gang)
  {
    if (millis() - last_ms >= delay) {
      digitalWrite(pinZuendung, LOW);
      last_Gang = gang;
      state = true;
    }
  }
  return state;
}


bool delayZuendungEIN(unsigned int delay, unsigned long last_ms)
{
  bool state = false;

  if (millis() - last_ms >= delay) {
    digitalWrite(pinZuendung, HIGH);
    state = true;
  }
  return state;
}


bool checkServoPosition(byte i)   // Gangnummer = Indexnummer
{
  bool state = false;

  unsigned int value = analogRead(pinPoti);

  if ( (Getriebe[i].potiMin < value) && (value < Getriebe[i].potiMax) )
  {
    state = true;
  }
  return state;
}


bool update_GetriebeGang()
{
  static byte last_Gang = 0;
  static byte new_Gang = 0;
  bool state = false;
  
  for (byte i = 0; i < ANZAHL; i++) {
    if (!digitalRead(Getriebe[i].taster) )
    {
      new_Gang = i;
    }
  }
 
  if (last_Gang != new_Gang) {
    last_Gang = new_Gang;
    merker.gang = new_Gang;
    state = true;
  }
  
  return state;
}

/*
// wie vorher nur mit Tasterentprellung
bool update_GetriebeGang()
{
  static byte last_Gang = 0;
  static byte new_Gang = 0;
  static unsigned long last_ms = 0;
  bool state = false;
  
  if (millis() - last_ms > 10) {
    last_ms = millis();
    
    for (byte i = 0; i < ANZAHL; i++) {
      if (digitalRead(Getriebe[i].taster) )
      {
        new_Gang = i;
      }
    }
  }

  if (last_Gang != new_Gang) {
    last_Gang = new_Gang;
    merker.gang = new_Gang;
    state = true;
  }
  
  return state;
}
*/
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

BeMarvelous

#33
Dec 22, 2018, 01:39 pm Last Edit: Dec 22, 2018, 01:51 pm by BeMarvelous
Sau stark, danke!!!

Ich probier's mal über die Feiertage aus, danke für den Vorschlag :)
Muss mich da dann aber auch erst mal gewaltig reinfuchsen...

Meine momentane, ich glaub sogar tatsächlich funktionierende(soweit getestete) Version sieht so aus:

Code: [Select]
##include <Servo.h>

Servo S1;                         //Stellservo für Gänge
int T0 = 4;                       //Taster für Gang 0
int T1 = 2;                       //Taster für Gang 1
int T2 = 6;                       //Taster für Gang 2
int T3 = 7;                       //Taster für Gang 3

int potPin = 0;
int valPot = 0;
int ZuendungsWert;
int Zuendung = 13;
byte Merker;

void setup() {
  Serial.begin(9600);
  pinMode(T0, INPUT);
  pinMode(T1, INPUT);
  pinMode(T2, INPUT);
  pinMode(T3, INPUT);
  pinMode(Zuendung, OUTPUT);
  S1.attach(9);
}

void loop() {
  valPot = analogRead(potPin);
  Serial.print("PotiWert: ");
  Serial.println(valPot);
  Serial.print("Merker: ");
  Serial.println(Merker);
  delay(500);

  if(digitalRead(T0) == HIGH) {                         //Servoposition für Leerlauf
    byte(Merker = 0);
  }
  if(digitalRead(T1) == HIGH) {                         //Servoposition für 1.Gang
    byte(Merker = 1);
  }
  if(digitalRead(T2) == HIGH) {                         //Servoposition für 2.Gang
   byte(Merker = 2);
  }
  if(digitalRead(T3) == HIGH) {                         //Servoposition für 3.Gang
    byte(Merker = 3);
  }

  byte ZuendungsWert = LOW; {Serial.println(ZuendungsWert);}
  ZuendungsWert += digitalRead(T0);                      //Ausschalten der Zuendung bei betätigen eines Tasters
  ZuendungsWert += digitalRead(T1);
  ZuendungsWert += digitalRead(T2);
  ZuendungsWert += digitalRead(T3);
  if(ZuendungsWert ==HIGH) {
    digitalWrite(Zuendung,LOW);{Serial.println(Zuendung);}
    delay(1000);
  }

  if((Merker == 1)&&(ZuendungsWert==HIGH)){
    S1.write(9);
  }
  if((Merker == 0)&&(ZuendungsWert==HIGH)){
    S1.write(30);
  }
  if((Merker == 2)&&(ZuendungsWert==HIGH)){
    S1.write(60);
  }
  if((Merker == 3)&&(ZuendungsWert==HIGH)){
    S1.write(90);
  }

  //Hier soll die Abfrage erfolgen ob der Servo auch wirklich richtig Steht, noch sind es nur ausgedachte Zahlenwerte und Winkel
 
   if((Merker == 1)&&(valPot>950)&&(valPot<1000)) {              //Wenn Servo die 9 Grad Angabe hat und ein Wertebereich vom Poti erreicht wird, schaltet die Zündung an
    digitalWrite(Zuendung,HIGH);
  }
   if((Merker == 0)&&(valPot>780)&&(valPot<820)) {              //Wenn Servo die 30 Grad Angabe hat und ein Wertebereich vom Poti erreicht wird, schaltet die Zündung an
    digitalWrite(Zuendung,HIGH);
  }
   if((Merker == 2)&&(valPot>480)&&(valPot<520)) {             //Wenn Servo die 60 Grad Angabe hat und ein Wertebereich vom Poti erreicht wird, schaltet die Zündung an
    digitalWrite(Zuendung,HIGH);
  }
   if((Merker == 3)&&(valPot>10)&&(valPot<100)) {            //Wenn Servo die 90 Grad Angabe hat und ein Wertebereich vom Poti erreicht wird, schaltet die Zündung an
    digitalWrite(Zuendung,HIGH);
  }
}

postmaster-ino

Hi
Code: [Select]
byte ZuendungsWert = LOW; {Serial.println(ZuendungsWert);}
  ZuendungsWert += digitalRead(T0);                      //Ausschalten der Zuendung bei betätigen eines Tasters
  ZuendungsWert += digitalRead(T1);
  ZuendungsWert += digitalRead(T2);
  ZuendungsWert += digitalRead(T3);
  if(ZuendungsWert ==HIGH) {

Das liest Sich irgendwie 'unrund'.
byte ... = LOW :o
Die dahinter liegende Klammer bringe Dir was?
Das =LOW weg, dafür beim ersten ZuendungsWert=digitalRead(T0);
Da, mindestens Theoretisch, Zuenungswert auf 4 ansteigen kann, empfinde ich die darauf folgende Abfrage ebenfalls als 'unrund'.
HIGH wird als NOT FALSE definiert sein und FALSE wohl als 0(Null) - kA, ob Das auch noch funktioniert, wenn zwei der Input's HIGH sind.
Statt += wäre meine Wahl |= (oder gleich), wodurch die(meine) Logik erhalten bleibt.
Spaßeshalber könnte man versuchen, wie oft man +=HIGH machen muß, um auf LOW zu kommen - sofern der Compiler hier nicht vorsorgt, wäre Das ein ziemlich netter Fehler ... alle drei Wochen klappt der Sketch nicht ...

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

michael_x

Quote
if(ZuendungsWert ==HIGH)
HIGH ist nicht "NOT FALSE" sondern 1.
Die Bedingung ist also nur true, wenn genau einer der T0 ... T3 HIGH ist..
Das ist vermutlich so nicht gemeint?
Wenn ein ODER gemeint ist,  sollte man die digitalRead auch per ODER verknüpfen.

Zuendungswert |= digitalRead(T0) ;

oder per if ( Zuendungswert != LOW ) abfragen.

Tommy56

Wieso? Wenn man 0 und 1 Werte addiert, kommt größer 0 raus, wenn mindestens einer gesetst (==1) war.

Passt doch. Die |= Lösung natürlich auch.

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

Doc_Arduino

Hallo,

gefallen tut mir der Code ehrlich gesagt auch nicht so. Sonst hätte ich den nicht komplett umgebaut.  ;)

Wenn dein Code prinzipiell funktioniert, okay, dann lasse ihn erstmal so. Du musst ihn selbst verstehen. Das ist wichtig.
Aber! Du steuerst dein Servo falsch an. Ein Servo muss ständig seinen Steuerimpuls im richtigen Timing bekommen. Dann kann es seine Position sicher halten mit voller Kraft. Schaue dir wenigstens meine Funktion moveServo an und übernehme sie.
Alle anderen delays müssen dann bei dir aus.

Ich weiß nicht ob dein erstes delay(500) nur zum testen drin ist oder drin bleiben soll.
Damit bekommst du 2 Probleme. Falsche Servosteuerung und du verlierst Zeit auf die Reaktions vom Gangwechsel, was dich locker den Sieg kosten kann. 3x schalten und 1,5s verloren. Falls er überhaupt schaltet, wenn der Taster nicht abgefragt wird in dem Moment. Die anderen einmaligen 1000ms werden sicherlich nicht stören.

Ich wollte deinen Sketch nicht schlecht machen, nur die Schwachstellen aufzeigen. Schließlich soll der Aufwand nicht nach hinten losgehen.
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

qualidat

Ein digitales Servo ist bei den Impulsabständen extrem großzügig bzw. hält die Position auch dann, wenn aktuell keine Impulse kommen.

postmaster-ino

Hi

Bei dem Preisunterschied 'normales' Servo zu einem Digital-Servo kann man auch einen eigenen Arduino sich nur um dieses eine Servo kümmern lassen - man ruft ihm nur ab und zu die Soll-Position zu.

Bei zeitkritischen Aufgaben ist delay() tödlich - selbst, wenn DU per ISR den Tastendruck mitbekommst, die Verarbeitung und der gewünschte Gangwechsel findet erst statt, wenn der Arduino ausgeschlafen hat - also das delay() vorbei ist.

Sichere Dir diesen Sketch (Archivieren, meine unter Werkzeuge, erstellt eine ZIP-Datei) bevor Du versucht, Ihn auf millis() umzubauen - Das wird Dir nämlich nicht im ersten Anlauf glücken und dann ist Es doch beruhigend, wenn man noch ein halbwegs funktionierende Vor-Version liegen hat.

Dazu ist das Beispiel in der IDE 'Blink_without_delay' einen Blick wert, hier im Forum gibt's dazu auch immer wieder Links, z.B. auf den Nachtwächter oder einige Foristen haben einen ganzen Katalog dazu in petto.

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

Doc_Arduino

Hallo,

nichts für ungut, aber solche sinnfreien Tipps mit 2. µC sollte man sich einfach schenken.

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

postmaster-ino

Hi

Dazu eine Nachfrage: Why?
Ein 'Nein' ist nicht sonderlich intelligent - ein 'Nein, weil ...' würde Deinen Standpunkt untermauern und mir zeigen, wo ich falsch liege.
Und, ganz nebenbei, macht ein 16fach-Servo-IC nichts Anderes - heißt dann halt nicht Nano oder Uno - also warum nicht Auslagern, was ich Innen nicht gebrauchen kann?
Aus welchen Gründen ist DAS gerade nicht Innen haben will, kann ja auch ungenügende Programmier-Kenntnis sein, soll dabei, bitte, keine Rolle spielen.

MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

Doc_Arduino

Hallo,

du schweifst immer zu sehr ab. Warum soll man unnötige Peripherie ranklöppeln wenn das der µC alleine kann?
Der Programmieraufwand nimmt unnötig zu. Zudem mehr Rechenpower noch nie sinnvoll war um Programmierschwächen auszubügeln.
Gegenfragen.
Lässt du deinen Kofferraum leer um einen Kasten Bier im Anhänger nach Hause zu fahren?
Stellst du dir einen Ölradiator ins Zimmer auch wenn es der normale Heizkörper schafft?
Klemmst du einen PCA9685 an, weil du ein Servo steuern möchtest?

a) erst vernünftig programmieren lernen, zumindestens halbwegs und blockierfrei
b) dann µC ausreizen
c) wenn b) erfüllt ist kann man über Alternativen nachdenken

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

postmaster-ino

Hi

An b) stört mich, daß bei den Arduinos 'eine ganze Menge Pins unbenutzt bleiben' - da war ich beim ATtiny45 'glücklicher' ;)
Da hier wohl auch die Experten b) wohl kaum als erledigt unterschreiben können, wird C nie angegangen.

Hier habe wir momentan das Problem, daß ein Analog-Servo wohl zu selten die Impuls-Information bekommt.
Daraufhin wurde mit einem Digital-Servo geantwortet, da Das bei dem Programm noch funktioniert - Dem ist der Abstand der Impulse sch*** egal.
Klar - ich verbaue ein 40€-Servo, weil mir ein 3€ Nano 'zu teuer/zu unausgereizt' ist.

Der vom TO vorgestellte Code lässt noch einiges an Optimierungen zu, keine Frage - bin aber momentan irgendwie faul und möchte Das doch eher den TO selber machen lassen.

Aber bevor ICH zigfach teurere Hardware verbaue, bekommt ein weiterer µC einen Lebenssinn - wenn's auch nur das Ansteuern EINES Servo und ab und zu an der Seriellen zu lauschen ist.
Bar gespartes Geld - und Umprogrammieren kann man dann immer noch - auch ohne digitales Servo.

MfG

PS: Nicht Alles, was der µC kann, kann ICH aus Ihm auch heraus holen - aber zumindest kann ich mir dann mit einer Krücke helfen. Nicht schön, aber läuft.
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

Doc_Arduino

Hallo,

es geht hier alleine um das was der TO machen möchte. Man benötigt für all das keinen 2. µC. 
Das war meine Aussage und bleibt es.
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