Forum: Mikrocontroller und Digitale Elektronik ESP Zeit messen, immer wieder Ausreißer


von Kolja L. (kolja82)


Lesenswert?

Hallo

An einem Getriebemotor ist ein endlos drehbares Poti angeschlossen.
Über den analogen Eingand wird die Spannung gemessen und immer wenn 
diese plötzlich abfällt eine Runde gezählt.
Strom bekommt der Motor immer in kurzen Impulsen, so lange wie der ESP 
für 50 analoge Messungen benötigt, dann pausiert er für 100ms.

Ausgeben lasse ich mir die Rundenzeit und die Anzahl der Schritte die 
für eine Runde notwendig waren.

Eigentlich ganz einfach, aber die Werte haben komische Ausreißer:
1
ȤlìÉã¬l,øi:ðøready!
2
Rundenzeit: 24340
3
Schritte: 217
4
Rundenzeit: 47594
5
Schritte: 429
6
Rundenzeit: 71934
7
Schritte: 413
8
Rundenzeit: 45923
9
Schritte: 45923
10
Rundenzeit: 45278
11
Schritte: 408
12
Rundenzeit: 627097712
13
Schritte: 416
14
Rundenzeit: 46277
15
Schritte: 417
16
Rundenzeit: 45814
17
Schritte: 413

Und hier mal der Code:
1
int servo = D2;
2
int power = D1;
3
int readpin = A0;
4
int marker = 0;
5
int runde = 0;
6
int steps = 0;
7
int step_ist = 1;
8
unsigned long zeit_0 = 0;
9
unsigned long zeit_2 = 0;
10
unsigned long zeit_1 = 0;
11
int rundenzahl = 0;
12
int runden_zeit = 0;
13
int wert1 = 0;
14
int wert2 = 0;
15
int rundenzeiten[3];
16
int j;
17
void setup()
18
{
19
  //  ESP.wdtDisable();
20
  Serial.begin(9600);
21
  pinMode(servo, OUTPUT);
22
  pinMode(power, OUTPUT);
23
  digitalWrite(power, HIGH);
24
  pinMode(readpin, INPUT);
25
  Serial.setDebugOutput(true);
26
  Serial.println("ready!");
27
}
28
29
void loop()
30
{
31
  digitalWrite(servo, HIGH);
32
33
34
35
  for (int i = 0; i <= 50; i++)
36
  {
37
    if (analogRead(A0) > 1000)
38
    {
39
      marker = 10;
40
    }
41
    if (analogRead(A0) < 1000 && marker == 10)
42
    {
43
      j++;
44
      rundenzeiten[j]=(millis() - zeit_0);
45
      Serial.print("Rundenzeit: ");
46
      Serial.println(millis() - zeit_0);
47
      Serial.print("Schritte: ");
48
      Serial.println(steps);
49
      zeit_0 = millis();
50
      marker = 0;
51
      steps = 0;
52
    }
53
  }
54
  digitalWrite(servo, LOW);
55
  delay(100);
56
  steps++;
57
58
59
60
61
}

von Wolfgang (Gast)


Lesenswert?

Kolja L. schrieb:
> Ausgeben lasse ich mir die Rundenzeit und die Anzahl der Schritte die
> für eine Runde notwendig waren.

Dann lass dir doch mal zeit_0 und alle drei Zeiten ausgeben, die du für 
deine Rundenzeitberechnung verwendest, also die Ergebnisse aller drei 
Abfragen von millis(), die du jede Runde machst. Damit hast du eine gute 
Chance, rauszufinden, was da schief läuft. Und denke dran: millis() 
liefert einen unsigned long Wert.

von Wolfgang (Gast)


Lesenswert?

p.s.
Den Wert von j solltest du bei der Gelegenheit zur Kontrolle gleich mit 
ausgeben lassen ;-)

von Frank (Gast)


Lesenswert?

Kann man so machen, würde ich aber nicht.
Bilde doch in deiner Mess-Schleife eine Pseudogeschwindigkeit.
Immer beim Übergang des Potis von Max zu Min gibt es dann einen großen 
Sprung.
Dann weist Du dass es eine neue Umdrehung war.
Ausgaben in zeitkritischen Stellen ist auch immer ziemlich schlecht.
1
void loop()
2
{
3
  abbort = false;
4
  
5
  digitalWrite(servo, HIGH);
6
  oldX    = analogRead(A0); //Damit beim ersten Diff annaehernd 0 rauskommt
7
  oldTime = millis();       //Zeit beim Start merken
8
  
9
  while(!abbort)
10
  {
11
    newX  = analogRead(A0); //Neuen Wert vom ADC holen (Position 1)
12
    diffX = newX - oldX;    //Pseudogeschwindigkeit bilden (deltaWeg/deltaZeit) fuer deltaZeit=1 Schleifendurchlauf
13
    oldX  = newX;
14
    newTime = millis();     //Aktuelle Zeit holen
15
    steps++;                //Schleifenzaehler
16
    
17
    if (diffADC > MAXVELOCITY)  //evtl Betrag bilden fuer Links/Rechtslauf
18
    {
19
        //Neue Runde detektiert
20
        //Motor ausschalten
21
        digitalWrite(servo, LOW);
22
        abbort = true;
23
        Serial.print("Rundenzeit: ");
24
        Serial.println(newTime - oldTime);      
25
        Serial.print("Schritte: ");
26
        Serial.println(steps);
27
    }
28
    else if( (steps > MAXSTEPS) || ((newTime - oldTime) > MAXTIME) )
29
    {
30
        //Motor ausschalten
31
        digitalWrite(servo, LOW);
32
        //Timeout oder bzw. Anzahl Steps (fast das gleiche) ueberschritten
33
        Serial.print("TIMEOUTERROR!!!");
34
        while(1)
35
        {
36
        //Tu was Sinnvolles
37
        }
38
    }
39
    
40
  }
41
//Theoretisch wuerde ich noch die Ausgabe aus
42
//der Schleife ziehen und außerhalb durch einen Status
43
//o.ä. die Ausgabe machen.
44
//Dann kannst Du hier noch wenn Du willst eine Differenation und
45
//Normierung machen und die Geschwindikeit in RPM ausrechnen.
46
  delay(100);
47
}

von Kolja L. (kolja82)


Angehängte Dateien:

Lesenswert?

Nabend

Mein Rechner spinnt gerade total, ich muss da leider erst dran...

Danke für dein Codebeispiel.
So ganz habe ich es noch nicht verstanden und auch noch nicht getestet.
Aber das mit der Ausgabe in den zeitkritischen Bereichen kann ich 
nachvollziehen.

Im Anhang mal ein Bild von zwei Runden des Motors.
Also nur den A0 ausgelesen.

Ziel ist eine relativ genaue Positionierung des Motors.
Im eigentlichen Bereich des Potis (Steigung) ist es ja kein Problem.
Wenn eine Position außerhalb angesteuert werden soll, sollte es wie 
folgt laufen:

Der Motor dreht sich 2 volle Umdrehungen und misst die Rundenzeit.
Daraus errechnet der µC sich die Zeit von einer markanten Stelle 
(Senkrechte)
bis zur Soll-Position.
Die Steps in dem o.g. Code habe ich eingeführt,
um den Bremsweg herauszunehmen und um dem Weg zu einer Position einfach 
Schritte zuordnen zu können.

Aber vielleicht gibt es ja andere / bessere Wege?

Danke und Gruß

Kolja

von Frank (Gast)


Lesenswert?

War das mit der Hand gedreht?
Oder mit einer konstanten Drehzahl?

Wenn das nämlich mit konstanter Drehzahl gedreht war, werden dir die 2 
Stellen wo sich nichts ändert die meisten Probleme machen.

Wenn du hingegen einen annähernd sauberen Sägezahn pro Motorumdrehung 
raus bekommst, hast du ja einen linearen Zusammenhang zwischen 
Motorposition und Spannung am ADC.

von Stefan F. (Gast)


Lesenswert?

> Aber vielleicht gibt es ja andere / bessere Wege?

Einen vernünftigen Sensor nehmen, zum Beispiel optisch wie beim Asuro 
http://www.cs.hs-rm.de/~linn/vpdv07/asuro3/asuro-website/images/rad_asuro.JPG 
oder mit einem Hall-Sensor.

Es hindert dich ja auch niemand daran, zwei Sensoren zu verwenden. Einen 
für die kleinen Teilschritte und einen, um die Ausgangslage zu 
markieren. Die meisten Tintenstrahldrucker und Aufzugtüren machen das 
auch so - kann also keine schlechte Idee sein.

Dein Poti wird ohnehin nach einigen tausend Umdrehungen kaputt gehen, 
aber das hatten Wir dir ja schon vor ein paar Wochen erklärt.

von Kolja L. (kolja82)


Lesenswert?

Nicht mit der Hand, sondern durch den Getriebemotor.
Völlig konstant ist die Winkelgeschwindgkeit wohl nicht,
aber das gilt es jetzt herauszufinden.

Und ja, die 3(!) Ebenen machen mir ja die Sorgen.
Im ersten Teil sind es einmal Werte um 5 und dann Werte um 10.
(So in etwa...)
Jeder Wechsel von 5 auf 10 auf Steigung auf 1000 auf 5 kann ja als 
Marker genutzt werden.

Mir geht es endgültig nicht darum die Anzahl der Runden zu zählen,
sondern eine Position zwischen 0° und 359° anzufahren.

von Kolja L. (kolja82)


Lesenswert?

@Stefan
Auch hatte ich schon mal gesagt, dass leider kein Platz für einen 
weiteren Sensor vorhanden ist.
Das Poti gegen eine Drehencoder tauschen würde gehen, aber die gibt es 
ja nicht mit <100 Steps.

von Frank (Gast)


Lesenswert?

Kolja L. schrieb:
> Das Poti gegen eine Drehencoder tauschen würde gehen, aber die gibt es
> ja nicht mit <100 Steps.

Gibt es schon:
http://roboter-teile.shopgate.com/item/454d473330
Wenn du da nur die positive Flanke einer Spur nimmst, hast du 360/4 = 90 
Striche pro mech. Umdrehung.

Auf Dauer ist das wie schon gesagt nichts mit dem Poti. Der geht 
wahrscheinlich ziemlich schnell hinüber und/oder ändert seine Funktion 
abhängig vom Abnutzungsgrad.

Für was willst du denn den Motor positionieren können?
Sprich, was für eine Anwendung steckt dahinter?

von Frank (Gast)


Lesenswert?

Bei dem angegebenen Encoder musst du halt auf null referenzieren. Bist 
also nur relativ. Nicht absolut.

von Kolja L. (kolja82)


Lesenswert?

Der Verlinkte Motor ist etwas zu schwach.
Wir haben hier Modellbauservos mit ca 10kgcm.

Daher darf ein möglicher Encoder auch nicht so groß sein.
Ein Mehrgangpoti mit knapp 200 Durchmesser passt definitiv nicht...

Die Anwendung ist eine Ventilsteuerung.
Auf das Servohorn kommt eine Nuss (13mm) und dann wird es anstatt dem 
Hahn auf das Ventil montiert.

Gruß Kolja

von Kolja L. (kolja82)


Lesenswert?

Relativ reicht, da wir die Absolute Position gar nicht wirklich 
benötigen.

von Frank (Gast)


Lesenswert?

Kolja L. schrieb:
> Relativ reicht, da wir die Absolute Position gar nicht wirklich
> benötigen.

Also auch nicht Singleturn absolut?
Wie genau musst du denn eine Umdrehung auflösen können?

von Kolja L. (kolja82)


Lesenswert?

Für meine Begriffe, ist singelturn absolut doch relativ,
oder wie definierst du das?

Als Auflösung wären 5° schon toll.
Im o.g. Serial Output sind es ca 400 Schritte pro Umdrehung,
so viel muss nicht.

Kannst du deine Idee mit der Pseudogeschwindikeit noch mal erläutern?
Oder Passt das nicht wegen den waagerechten Bereichen?

Danke und Gruß

von Frank (Gast)


Lesenswert?

Kolja L. schrieb:
> Für meine Begriffe, ist singelturn absolut doch relativ,
> oder wie definierst du das?

Es gibt inkrementelle Geber. Wie der von mir oben verlinkte.
Die auswertende Elektronik wacht auf und weis erst mal nicht wo sie 
überhaupt steht. Sie hat keine absolute Winkelposition pro 
Motorumdrehung.
Deshalb muss der Motor erst gegen einen Referenzpunkt fahren. Jetzt weis 
die auswertende Elektronik, dass sie bei der mechanischen Position 0° 
ist und kann über das Zählen der Impulse relativ verfahren. Schaltet man 
die Elektronik ab, fängt das Szenario mit der Referenzierung wieder 
komplett von vorne an.

Dann gibt es Singelturn Absolut Geber. Wie z.B. ein Resolver. Mit ihm 
kann man (wenn er mechanisch einmalig richtig eingestellt wurde) die 
Motorposition innerhalb einer Motorumdrehung absolut bestimmt werden. 
Die auswertende Elektronik kann die Überläufe der mechanischen Umdrehung 
mitzählen und somit auch auf mehrer Umdrehungen genau die Position 
bestimmen. Schaltet man allerdings die Elektronik ab und verdreht den 
Motor, weis die Elektronik nur die Motorlage. Nicht aber die 
Multiturninformation Der Motor kann ja während dem Ausschalten verdreht 
werden ohne dass es die Elektronik mitbekommt.

Dann gibt es noch die Multiturn Geber. Sie haben meist noch ein internes 
Getriebe und können nach dem Aufwachen sofort die Multiturninformationen 
liefern (innerhalb eines Gewissen Wertebereichs).

Das was Du also scheinbar benötigst ist entweder einen Inkrementalgeber 
mit einem Referenzpunkt, oder einen Singelturn Absolutwertgeber.

von Kolja L. (kolja82)


Lesenswert?

Also mir reicht es, wenn ich immer einen definierten Schritt vorwärts 
drehen kann und es möglich ist den letzten Wert auch wieder anzufahren.
Das wäre am einfachsten zu erreichen, wenn der Motor rückwärts laufen 
würde,
aber dann brauche ich einen Motortreiber.
Außerdem ist ein Linkslauf wegen der Montage auf dem Ventil ungünstig, 
da diese sich dann lösen könnte.
Daher ist mein Schritt zurück, alle Schritte - einer vorwärts.

von Frank (Gast)


Angehängte Dateien:

Lesenswert?

Kolja L. schrieb:
> Kannst du deine Idee mit der Pseudogeschwindikeit noch mal erläutern?

Ich dachte Du willst nur ganze Umdrehungen zählen. Dann hätte es bei 
absichtlich falsch angewandter Subtraktion immer einen schönen Pikser 
bei jeder Umdrehung in der Geschwindigkeit gegeben (siehe Anhang 
Optimal.png).

Im gleichen Bild sieht man auch, wie das Signal optimaler Weise aussehen 
würde. Ein schöner Sägezahn. So hättest Du dann jeder Spannung einen 
Winkel zuordnen können:
0V = 0°
1V = 359°

Durch die Stellen wo Du aber keine Steigung hast (siehe rote 
Markierungen in Bild ServoPoti.jpg) bekommst Du keine weiteren 
Informationen. Sprich, es gibt Bereiche die Dein Motor durchfährt, indem 
Du keinen aktuellen Winkel feststellen kannst. Im Prinzip ist an der 
Stelle Deine Regelung blind.
Wenn Du nun genau in so einen Bereich positionieren willst, wird dein 
Regler immer zwischen diesen Stellen toggeln. Er versucht die Position 
zu erreichen. Fährt hinein, die Position ändert sich aber nicht. 
Irgendwann kommt wieder eine Position, aber zu groß. Scheiße, der Regler 
denkt sich wieder da drehe ich mal um. Dann fährt er wieder in die 
andere Richtung, bekommt aber wieder keine aktuelle Position...usw. usw.

von Kolja L. (kolja82)


Lesenswert?

Danke für die ausführliche Hilfestellung!

Das Sketch soll erst drei Runden fahren.
Eine Runde bedeutet das überschreiten eines eindeutigen Punktes.
ich habe es mit dem Marker gemacht (wenn größer 1000 wird er gesetzt und 
wenn der Wert dann wieder unter 1000 fällt, ist der eindeutige Punkt 
gefunden.)
Du machst das über die Pseudogeschwindigkeit (hab ich jetzt verstanden, 
gute Idee)
Da die erste Runde keine vollständige ist (meistens jedenfalls) wird 
diese vernachlässigt und nur aus den benötigten Schritten von Runde 2 
und 3 der Mittelwert gebildet.

Dann wollte ich schauen, wie gut ich damit einzelne Positionen anfahren 
kann.

Wenn das reicht (wovon ich nicht ausgehe) ist gut,
wenn nicht, muss ich mir weitere eindeutige Punkte suchen.
Vielleicht finde ich die ja auch über die Pseudogeschwindigkeit,
was ja eigentlich die Steigung ist.

Dann könnte man immer von dem letzten überfahrenden Punkt anfangen die 
Steps zu zählen.

Ein Poti, welches ein so schönes Bild macht, wie du in deinem Zweiten 
dargestellt hast,
kann es mechanisch leider nicht geben.
Einen kleinen Totbereich gibt es immer...

von Kolja L. (kolja82)


Lesenswert?

Steigung ist natürlich nicht richtig, da subtrahiert und nicht dividiert 
wird...

Lieder habe ich jetzt wieder Probleme mit
1
Soft WDT reset
2
3
ctx: cont 
4
sp: 3ffef980 end: 3ffefb80 offset: 01b0
5
6
>>>stack>>>
7
3ffefb30:  3ffe83c8 3ffeea58 00000000 40202548  
8
3ffefb40:  3ffeea54 feefeffe 3ffeeb34 40202fcc  
9
3ffefb50:  3fffdad0 3ffe8374 3ffeeb34 3ffeeb58  
10
3ffefb60:  3fffdad0 00000000 3ffeeb51 402028a0  
11
3ffefb70:  feefeffe feefeffe 3ffeeb60 40100114  
12
<<<stack<<<

und muss erts das lösen...

von Frank (Gast)


Lesenswert?

Kolja L. schrieb:
> Vielleicht finde ich die ja auch über die Pseudogeschwindigkeit,
> was ja eigentlich die Steigung ist.

Kolja L. schrieb:
> Steigung ist natürlich nicht richtig, da subtrahiert und nicht dividiert
> wird...

Steigung und Geschwindigkeit ist beides richtig.
Die Differenziation bzw. "Steigung" der Position bezogen auf die Zeit 
ist ja gerade die Geschwindigkeit.

Ich hatte nur, um nicht dividieren zu müssen, auf die Zeitdifferenz 1 
normiert.

von Kolja L. (kolja82)


Lesenswert?

Jup, Ableitung des Weges nach der Zeit, so hieß dass doch damals.
Das /1 hatte ich übersehen.

von Frank (Gast)


Lesenswert?

Ein "ä" mag er natürlich nicht:

von Kolja L. (kolja82)


Lesenswert?

Der ist aber auch zimperlich beim interpretieren ;-)

Ich glaub mein Rechner stürzte wegen des defekten BT Modules immer ab.
Jetzt ist es raus :-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.