Forum: Mikrocontroller und Digitale Elektronik mit Arduino Due, DC-Motorstrom positionsabhängig erfassen und seriell ausgeben


von Carl-Josef S. (ernst-stavro)


Angehängte Dateien:

Lesenswert?

Hallo zusammen!
Ich bin neu hier und habe schon unzählige Forenbeiträge und Tutorials 
durchgelesen, aber noch keine Lösung für mein Problem gefunden...

Ich muss einen Prüfstand für eine Funktionseinheit realisieren, welche 
u.a. aus einem 24Volt DC-Motor mit Getriebe besteht, der eine Welle 
antreibt. Auf dieser Welle sind mehrere unterschiedliche Kurvenscheiben 
montiert, auf deren Außenkanten Kugellager mittels Stahlfedern gedrückt 
werden. Dreht sich nun die Welle mit den Kurvenscheiben, laufen die 
Kugellager auf der Kurvenscheibe entlang und betätigen dann irgendwelche 
Hebel. Die Welle macht pro Zyklus eine Umdrehung. Die Nullstellung der 
Welle wird über einen induktiven Initiator detektiert, welcher von einer 
Nockenscheibe betätigt wird, die sich ebenfalls auf der Welle befindet.
Der Motor wird je nach Stellung der Welle unterschiedlich 
belastet(aufgrund der unterschiedl. Kurvenscheiben).  Um nun 
herauszufinden, ob möglicherweise zu starke/zu schwache Federn montiert 
wurden, kann man ja über den Motorstrom eine Aussage über das Drehmoment 
treffen (Proportionalität).  Ich muss also den Motorstrom aufzeichnen 
und dann mit einer zuvor definierten Hüllkurve vergleichen.
Eckdaten:   24 Volt DC Motor, Dunker-BG65SI, eingebauter Speedcontroller 
mit spezieller Firmware  / Getriebe 19:1
Die Motor-Firmware wurde so konzipiert, dass der Motor über zwei 
digitale Ausgänge  zwei 24 Volt Hall Signale liefert, welche um 90° 
verschoben sind. Pro Motorumdrehung erhält man pro Hallspur 5 positive 
und 5 negative Flanken. Bei zwei Hallspuren macht das dann 20 
Flankenwechsel. In Verbindung mit dem Getriebe erhalte ich dann 19*20 = 
380 Signalwechsel pro Zyklus (Wellenumdrehung).
Diese 380 Signalwechsel kann ich in Verbindung mit dem 
Grundstellungsinitiator zählen und daraus die aktuelle Position der 
Welle ermitteln. Und zu jeder einzelnen Position muss ich einen 
dazugehörigen Motorstrom messen und aufzeichnen. Dazu benutze ich den 
Stromsensor LEM LTS 15-NP.
Vorgehen:  Mit Hilfe eines Arduino Due die Hallsignale, den 
Grundstellungsinitiator und den Motorstrom erfassen (mit zusätzlicher 
Vor-Beschaltung). Diese Werte an dem Serial Monitor ausgeben lassen.
Jetzt zu meinem Problem: Ein Zyklus dauert ca. eine Sekunde. Da die 
Übertragung der Daten vom Arduino mit 9600 Baud erfolgt, erhalte ich nur 
ca. 50 Wertepaare, welche überhaupt nicht brauchbar sind. Das Problem 
ist eben, dass ich die Daten direkt übertrage.
Plan: Bei jedem der 380 Flankenwechsel eine Interruptroutine ausführen, 
welche den dazugehörigen Stromwert detektiert und das ganze im RAM 
speichern. Erst nach einem kompletten Zyklus dann die 380 Wertepaare 
über die serielle Schnittstelle schicken.

Im  Anhang befindet sich der bisherige Quellcode und eine Excel Datei 
mit den erhaltenen Daten (die Skala des Motorstroms passt noch nicht, 
Initiator und Hallsignale sind binär). Außerdem noch der 
Motorstromverlauf, welcher mit einer Stromzange (Oszi) aufgenommen 
wurde. Wenn man beide Stromverläufe vergleicht, sieht man, dass die 
Messung über Stromzange(Oszi) um ein vielfaches genauer ist, als die 
Daten des Arduino. Ich benötige also einen Quellcode, mit welchem man 
eine ähnliche Genauigkeit erreicht als mit der Stromzange…

Leider habe ich keine Ahnung, wie ich das ganze umsetzen/ implementieren 
kann, weshalb ich mich an euch wende. Ich bin wirklich für jede Hilfe 
dankbar!

von Peter L. (luidoltp)


Lesenswert?

Hallo,

soweit ich weiß, kann man die Daten auch schneller aus dem Arduino 
herausbekommen. Bis 115200 baud wird direkt von der Arduino Library 
angegeben (http://arduino.cc/en/Serial/begin).
1
 Serial.begin(115200);

Angeblich kann man auch mehr herausholen.
http://forum.arduino.cc/index.php?topic=21497.0

Du musst natürlich die Gegenstelle (also den PC der die Daten empfängt) 
auch entsprechend umstellen.

Alternativ kannst du natürlich immer einfach vorher die Werte intern 
speichern und anschießend übertragen.

Quellcode nur exemplarisch (Quelle [1]):
1
unsigned long values[1000];
2
3
void loop() {  
4
  unsigned int i;
5
6
  // capture the values to memory
7
  for(i=0;i<1000;i++) {
8
    values[i] = analogRead(2);
9
  }
10
11
  // print out the results
12
  Serial.println("\n\n--- Results ---"); 
13
  for(i=0;i<1000;i++) {
14
    Serial.print(values[i]);
15
  }
16
}

Achtung: es könnte sein, dass der ADC die 1000 Werte deutlich schneller 
eingelesen hat als eine Umdrehung deiner Welle (von der du die Daten 
haben willst) dauert. Das solltest du aber anhand der anderen Signale 
gut sehen können.

Liebe Grüße,
Lui

[1] 
http://www.microsmart.co.za/technical/2014/03/01/advanced-arduino-adc/

von Albert M. (Firma: Bastler aus Mönchengladbach) (albertm) Benutzerseite


Lesenswert?

Carl-Josef S. schrieb:
> Da die
> Übertragung der Daten vom Arduino mit 9600 Baud erfolgt, erhalte ich nur
> ca. 50 Wertepaare, welche überhaupt nicht brauchbar sind.

Mit dem Arduino gehen locker 250.000 und auch 500.000 Baud, damit 
sollten mind. 10.000 Samples/s und weit mehr gehen. Ich habe mit einem 
Arduino Uno bei 500.000 Baud ca. 30.000 Samples/s (je 8bit binary) 
geschaft. Allerdings nicht mit den schnarchigen Arduino Libs, sonder mit 
LunaAvr. Mit Deinem Arduino Due müsste das trotz der langsamen Arduino 
Libs event. auch gehen.

An Deiner Stelle würde ich aber den Due entsorgen, einen Uno nehmen und 
dazu eine Programmiersprache, die alle Funktionen/Ports des MC sofort 
ansprechen kann, wie C, Luna, Bascom. Dann bist Du warscheinlich immer 
noch schneller als mit dem Due und den Arduino Libs.

: Bearbeitet durch User
von Albert M. (Firma: Bastler aus Mönchengladbach) (albertm) Benutzerseite


Lesenswert?

Peter Luidolt schrieb:
> Du musst natürlich die Gegenstelle (also den PC der die Daten empfängt)
> auch entsprechend umstellen.

Das ist Unsinn, an den ComPorts im PC muss man nichts umstellen, die 
Einstellungen sind absolut schnuppe. Ich wechsele die Baudraten vom MC 
beim Testen dauernd, ohne im PC-Gerätemanager die ComPort Baudraten 
umzustellen. Die stehen auf 9.600 Baud obwohl z.B. mit 500.000 Baud 
übertragen wird.
Da schaut man höchstens nach um die aktuell benutzte Port-Nummer zu 
sehen.

: Bearbeitet durch User
von avr (Gast)


Lesenswert?

Albert M. schrieb:
> Das ist Unsinn, an den ComPorts im PC muss man nichts umstellen, die
> Einstellungen sind absolut schnuppe.

Das ist überhaupt kein Unsinn. Du redest von Comports und da muss man 
die Baudrate definitiv umstellen. Wahrscheinlich meinst du virtuelle 
Comports (über USB). Bei denen funktioniert das so.

von Albert M. (Firma: Bastler aus Mönchengladbach) (albertm) Benutzerseite


Lesenswert?

avr schrieb:
> Das ist überhaupt kein Unsinn. Du redest von Comports und da muss man
> die Baudrate definitiv umstellen. Wahrscheinlich meinst du virtuelle
> Comports (über USB). Bei denen funktioniert das so.

Und was meinst Du welche Art von ComPorts von den Arduino Treibern 
generiert werden? Ja eben, virtuelle ComPorts, was sonst. Also ist Dein 
Gerede vom Umstellen müssen für den TO irrelevant.

: Bearbeitet durch User
von Carl-Josef S. (ernst-stavro)


Lesenswert?

Hallo!

Erstmal DANKE für die Antworten.

Ich werde als nächstes die geposteten URLs durchschauen und dann mal die 
Baudrate erhöhen und etwas rumprobieren. Werde dann wieder ein 
Bild(Excel) von den neuen Wertepaaren schicken.

>An Deiner Stelle würde ich aber den Due entsorgen, einen Uno nehmen...
Das verstehe ich nicht ganz. Hab mir extra noch einen Due zugelegt, da 
der ja viel bessere Leistungsdaten hat(Geschwindigkeit, RAM,...). Habe 
aber auch noch einen Uno und einen Mega zur Verfügung.

von Jürgen S. (jurs)


Lesenswert?

Carl-Josef S. schrieb:
> Flankenwechsel. In Verbindung mit dem Getriebe erhalte ich dann 19*20 =
> 380 Signalwechsel pro Zyklus (Wellenumdrehung).

Kannst Du irgendwas zu Ablaufgeschwindigkeit oder Drehzahl sagen?
In welcher Zeit kommen diese 380 Signalwechsel?

> Und zu jeder einzelnen Position muss ich einen
> dazugehörigen Motorstrom messen und aufzeichnen.

Wenn Du das musstt, solltest Du das auch machen.
Dein bisheriger Code macht das nicht. Insbesondere mißt und sendet Dein 
Code nicht beim Auftreten eines Flankenwechsels, sondern "mit maximaler 
Geschwindigkeit". Dadurch läuft Dir der serielle Sendepuffer zu und dann 
kannst Du alle gesendeten Werte vergessen.

Der erste Flaschenhals Deines Programms ist die serielle Schnittstelle. 
Die Anzahl der Zeichen, die Du pro Sekunde senden kannst, beträgt 
Baudrate geteilt durch 10. Bei 9600 Baud wären dass max. 960 Zeichen/s. 
Bei 115200 Baud (max. Baudrate des "Seriellen Monitor" von Arduino) 
wären es 11520 Zeichen/s, Bei 500000 als maximale Baudrate eines Arduino 
UNO (nur mit anderen Terminalprogrammen auf dem PC nutzbar) wären es 
50000 Zeichen/s.

Welches die maximale Baudrate eines DUE ist, weiß ich nicht.

> Im  Anhang befindet sich der bisherige Quellcode

Sende den Quellcode lieber zwischen Code-Tags oder als Dateianhang.

> mit den erhaltenen Daten (die Skala des Motorstroms passt noch nicht,
> Initiator und Hallsignale sind binär).

Wie gesagt: Solange Du versuchst, die serielle Schnittstelle zu 
überdrehen kannst Du alles vergessen.

Wenn Du die Signale immer zu dem Zeitpunkt benötigst, zu dem bei den 
Hallsignalen ein Flankenwechsel auftritt, solltest Du genau diese 
Flanken auswerten und beim Flankenwechsel den Stromsensor auslesen und 
den Wert senden. Das benötigt keine Interrupt-Routine.

von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

Hallo Jürgen,

> Carl-Josef S. schrieb:
>> Flankenwechsel. In Verbindung mit dem Getriebe erhalte ich dann 19*20 =
>> 380 Signalwechsel pro Zyklus (Wellenumdrehung).
>
> Kannst Du irgendwas zu Ablaufgeschwindigkeit oder Drehzahl sagen?
> In welcher Zeit kommen diese 380 Signalwechsel?

Das hat er irgendwo oben im Text versteckt, 1 U/s, also 380 Hz für die 
Messungen bzw. die Hallsignale. Dafür sind 9600 Baud klar zu wenig, 
sobald mehr als ein paar Byte pro Messung übertragen werden sollen.

Mit freundlichen Grüßen
Thorsten Ostermann

von Carl-Josef S. (ernst-stavro)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich habe nochmal ein Messversuch mit höherer Baudrate (115200) 
durchgeführt und das Resultat sieht schon besser aus (Anhang).
Jedoch hat Jürgen S recht, dass ich nicht die positionsbezogenen 
Motorströme erhalte, sondern einfach nur mit maximaler Taktung die Werte 
übertrage. Ich habe dann das Programm nach Vorlage von "Peter Luidolt 
(luidoltp)" umgeschrieben, aber das funktioniert noch nicht (Anhang). Da 
muss ich morgen noch etwas herumprobieren. Falls jemand weiß, wie ich 
das Programm verändern muss, wäre ich sehr dankbar. Im Moment bekomme 
ich zwar Werte über den "Serial Monitor" angezeigt, jedoch ändern sich 
diese nicht. Wenn ich die Zählvariable "i" auf 5 (statt auf 500) stelle, 
bekomme ich eben fünf mal die gleichen Wertepaare und das immer 
fortwährend. Bei i=500 kommen eben 500 mal die gleichen,unveränderten 
Werte und dann beginnt es wieder von vorne (mit "---Results---").( Motor 
wurde während der Messung angesteuert).

von Jürgen S. (jurs)


Lesenswert?

Carl-Josef S. schrieb:
> Ich habe nochmal ein Messversuch mit höherer Baudrate (115200)
> durchgeführt und das Resultat sieht schon besser aus (Anhang).
> Jedoch hat Jürgen S recht, dass ich nicht die positionsbezogenen
> Motorströme erhalte, sondern einfach nur mit maximaler Taktung die Werte
> übertrage.

Ich habe Dir mal ein neues Programm gemacht, das immer nur beim 
Flankenwechsel an den Drehgeberausgängen eine Messung macht.
1
const int analogInPin = A0;  // Analog input pin that the LEM LTS 15-NP is attached to
2
int IniB13 = 2;        //Grundstellung
3
int Hall1 = 3;        //Hallspur 1
4
int Hall2 = 4;        //Hallspur 2
5
6
7
void setup() {
8
  Serial.begin(115200);
9
  pinMode (IniB13, INPUT);
10
  pinMode (Hall1, INPUT);
11
  pinMode (Hall2, INPUT);
12
  analogReadResolution(12);      //Auflösung auf 12 Bit erhöhen
13
}
14
15
static boolean grundStellungsImpuls()
16
// Flankenwechselerkennung Grundstellung
17
{
18
  static byte lastStellung; // letzte Stellung in statischer Variablen merken
19
  boolean result;
20
  byte stellung=digitalRead(IniB13); // aktuelle Stellung auslesen
21
  if (stellung==HIGH && lastStellung==LOW) result=true; // Flankenwechsel auf HIGH?
22
  else result=false;
23
  lastStellung=stellung; // aktuell ausgelesene Stellung merken
24
  return result;
25
}
26
27
static boolean hallSensorImpuls()
28
// Flankenwechselerkennung an den Drehgeberausgängen
29
{
30
  static byte lastA, lastB;
31
  boolean result=false;
32
  byte nowA=digitalRead(Hall1);
33
  byte nowB=digitalRead(Hall2);
34
  if (nowA!=lastA || nowB!=lastB) result=true;
35
  lastA=nowA;
36
  lastB=nowB;
37
  return result;
38
}
39
40
41
int stepcounter=0;
42
43
void loop() {  
44
  if (grundStellungsImpuls()) stepcounter=0;
45
  if (hallSensorImpuls())
46
  {
47
    int strom = analogRead(analogInPin);    //Analogwert von Stromsensor
48
    stepcounter++;
49
    Serial.print(stepcounter);
50
    Serial.print("\t");
51
    Serial.print(strom);
52
    Serial.print('\n');
53
  }
54
}

Da pro Messung eine Zeile auf Serial mit der Drehstellung 
("stepcounter") und dem Messwert ausgegeben wird, entsprechend ca. 10 
Zeichen pro Messung, sollten bei 380 Impulsen pro Sekunde ca. 3800 
Zeichen pro Sekunde auf der seriellen Schnittstelle auszugeben sein. 
Wobei man bei 115200 Baud bis zu 11520 Zeichen ausgeben könnte. Passt 
also für Realtime-Ausgabe.

Beim Setzen der ADC-Auflösung mit "analogReadResolution(12);" bin ich 
mal davon ausgegangen, dass das nicht vor jeder Messung gemacht werden 
muss, und es daher in die setup-Funktion verschoben. Ich kenne mich mit 
dem DUE nicht aus, wenn nicht, schiebe die Zeile in die loop zurück.

Beim "grundStellungsImpuls()" habe ich eine Flankenerkennung gemacht, 
die vom Übergang Low-nach-High reagiert und dann den Schrittzähler 
zurücksetzt. Das kann man ggf. einfach auf die andere Flanke 
umprogrammieren. Etwas mehr Aufwand wäre es, wenn Schritt 1 irgendwo in 
der Mitte auftreten würde, aber auch das wäre machbar, die 
Schrittzählung auf einen anderen Nullpunkt zu setzen.

Kannst ja mal bei Bedarf damit testen. Falls Du dabei feststellen 
solltest, dass der Stepcounter höher als bis 380 läuft, dann prellen die 
Ausgänge Deiner Hallsensoren und die Schrittzählung ist nicht 
zuverlässig. In dem Fall müßte man statt der Flankenwechselerkeunnung 
eine richtige Drehgeberauswertung machen und die Impulse vor- und 
rückwärts zählen, um das Prellen aus den Signalen zu eliminieren.

von avr (Gast)


Lesenswert?

Albert M. schrieb:
> Und was meinst Du welche Art von ComPorts von den Arduino Treibern
> generiert werden? Ja eben, virtuelle ComPorts, was sonst. Also ist Dein
> Gerede vom Umstellen müssen für den TO irrelevant.

Hier geht es nicht nur um den TO, sondern auch um andere, die das später 
lesen. Und so wie dein Beitrag da steht ist er einfach inhaltlich 
falsch. Das kleine Wörtchen virtuell macht nämlich einen gewaltigen 
Unterschied aus.

von Carl-Josef S. (ernst-stavro)


Lesenswert?

Hallo!

Zu der "Diskussion" über ComPorts kann ich mich nicht wirklich 
beteiligen, davon verstehe ich zu wenig. Ich habe jedenfalls nur im 
Arduino-Sketch die Baudrate erhöht und bekam so eine bessere Auflösung 
der Messung. In der Systemsteuerung des PC habe ich nichts verändert.

@ Jürgen S: Vielen Dank für dein Programmcode. Habe ihn nur auf 
"Flankenwechsel auf LOW" ändern müssen. Das Problem ist jetzt nur, dass 
der Motor für eine Wellenumdrehung keine kontinuierliche Bewegung 
ausführt, sondern in fünf unterschiedlichen Positionen kurz anhält. Wenn 
er dann wieder anläuft aus der jeweiligen Position, bekomme ich einen 
relativ hohen und steilen Strompeak. Das kann man in dem Bild sehen, 
welches ich mit dem Oszi und der Stromzange (siehe Anfangsbeitrag, 
LeCroy.png)gepostet habe. Mit dem Programmcode von Jürgen S bekomme ich 
immer ein Stromwert geliefert, wenn sich eine der beiden Hallspuren 
ändert (=wenn sich der Motor bewegt). Die Peaks treten aber in dem 
Anlaufmoment auf, kurz bevor eine Motorbewegung stattfindet. Deshalb 
werden sie nicht (immer) in voller Höhe erfasst. Außerdem verharrt der 
Motor kurz in den fünf unterschiedlichen Positionen und während dieser 
Zeit wird auch kein Stromwert detektiert (weil kein Hall-wechsel). Es 
ist also nicht wirklich möglich (bzw.aussagekräftig), positionsbezogene 
Ströme zu erfassen und mit einer zuvor definierten Hüllkurve zu 
vergleichen.
Mir bleibt jetzt noch die Möglichkeit, den Bewegungsablauf so 
abzuändern, dass der Motor eine gleichmäßige Bewegung mit konstanter 
Geschwindigkeit ausführt. Dies entspricht zwar nicht dem späteren 
Bewegungsablauf, aber für den Prüfstand ist das erst mal egal. Hier geht 
es ja nur darum, eventuelle Montagefehler zu erkennen. Probleme könnten 
sich jetzt nur ergeben, dass ich keine 100%ig gleichmäßige 
Umdrehungsgeschwindigkeit realisieren kann, da der Motor ja 
unterschiedlich belastet wird-je nach Position der Welle aufgrund der 
unterschiedlichen Kurvenscheiben.
Möglichkeit 2: alle positiven Ströme einer Umdrehung addieren und der 
Gesamtwert muss dann in einem bestimmten Bereich liegen ( und das 
gleiche mit negativen Strömen auch machen). Sollte der Gesamtwert zu 
hoch sein, kann man davon ausgehen, dass etwas klemmt oder zu starke 
Federn montiert wurden. Ich weiß aber nicht, wie groß hier der 
Toleranzbereich gewählt werden muss.
...Ich habe also die nächsten Tage noch einiges an Messversuchen etc. 
vor mir. Werde euch auf dem Laufenden halten.
Falls jemand eine Idee hat, welche Möglichkeiten ich noch habe, den 
Motorstrom zu erfassen und v.a. auszuwerten- ich bin für jeden 
Tipp/Hilfe dankbar!

von Jürgen S. (jurs)


Lesenswert?

Carl-Josef S. schrieb:
> Das Problem ist jetzt nur, dass
> der Motor für eine Wellenumdrehung keine kontinuierliche Bewegung
> ausführt, sondern in fünf unterschiedlichen Positionen kurz anhält. Wenn
> er dann wieder anläuft aus der jeweiligen Position, bekomme ich einen
> relativ hohen und steilen Strompeak. Das kann man in dem Bild sehen,
> welches ich mit dem Oszi und der Stromzange (siehe Anfangsbeitrag,
> LeCroy.png)gepostet habe. Mit dem Programmcode von Jürgen S bekomme ich
> immer ein Stromwert geliefert, wenn sich eine der beiden Hallspuren
> ändert (=wenn sich der Motor bewegt). Die Peaks treten aber in dem
> Anlaufmoment auf, kurz bevor eine Motorbewegung stattfindet. Deshalb
> werden sie nicht (immer) in voller Höhe erfasst.

OK, Du brauchst also sehr viel mehr Samples mit sehr viel kürzeren 
Zeitabständen.

Um den Flaschenhals "Serial" zu umgehen, dann also doch wieder zurück zu 
Deiner ersten Idee: Erst schnell die Werte in den RAM-Speicher sampeln, 
und dann die Werte ausgeben. Du verwendest ja den DUE und der hat 
erhebliche Mengen RAM-Speicher, da sollte das kein Problem sein.


> Motor kurz in den fünf unterschiedlichen Positionen und während dieser
> Zeit wird auch kein Stromwert detektiert (weil kein Hall-wechsel). Es
> ist also nicht wirklich möglich (bzw.aussagekräftig), positionsbezogene
> Ströme zu erfassen und mit einer zuvor definierten Hüllkurve zu
> vergleichen.

OK, ich habe mal einen geänderten Sketch gemacht, der nicht 
positionsbezogen sampelt, sondern zeitbezogen, und zwar zunächst mal "so 
schnell wie möglich". Das Sampling wird getriggert durch:
- Erkennung des Impulses für die Grundstellung
- Auf einen frei wählbaren Step-Impuls der Hall-Sensoren

Das ist in der loop-Funktion diese Zeile:
1
 if (waitForStart && stepcounter==4)  // Triggern auf einen bestimmten Impuls

Falls nach diesem Triggerimpuls zunächst eine uninteressante Standzeit 
auftritt, kann dort ein optionales delay die Sampling-Aufzeichnung 
verzögert starten.

Und falls die Samplings zu schnell aufeinander folgen, kann in der 
recordSamples() Funktion ein kleines Mikrosekunden-delay in der 
Einleseschleife eingefügt werden, um die Aufzeichnungsdauer zu strecken.

Vollständiger Code:
1
const int analogInPin = A0;  // Analog input pin that the LEM LTS 15-NP is attached to
2
int IniB13 = 2;        //Grundstellung
3
int Hall1 = 3;        //Hallspur 1
4
int Hall2 = 4;        //Hallspur 2
5
6
struct sample_t{
7
  uint16_t time;      // Zeit in Mikrosekunden nach Startimpuls
8
  uint16_t stepcount; // Schritte vom Drehgeber
9
  int16_t strom;     // ADC-Messwert
10
};
11
12
#define NUMSAMPLES 5000
13
14
sample_t samples[NUMSAMPLES];
15
16
void setup() {
17
  Serial.begin(115200);
18
  pinMode (IniB13, INPUT);
19
  pinMode (Hall1, INPUT);
20
  pinMode (Hall2, INPUT);
21
  analogReadResolution(12);      //Auflösung auf 12 Bit erhöhen
22
}
23
24
static boolean grundStellungsImpuls()
25
// Flankenwechselerkennung Grundstellung
26
{
27
  static byte lastStellung; // letzte Stellung in statischer Variablen merken
28
  boolean result;
29
  byte stellung=digitalRead(IniB13); // aktuelle Stellung auslesen
30
  if (stellung==LOW && lastStellung==HIGH) result=true; // Flankenwechsel auf LOW?
31
  else result=false;
32
  lastStellung=stellung; // aktuell ausgelesene Stellung merken
33
  return result;
34
}
35
36
static boolean hallSensorImpuls()
37
// Flankenwechselerkennung an den Drehgeberausgängen
38
{
39
  static byte lastA, lastB;
40
  boolean result=false;
41
  byte nowA=digitalRead(Hall1);
42
  byte nowB=digitalRead(Hall2);
43
  if (nowA!=lastA || nowB!=lastB) result=true;
44
  lastA=nowA;
45
  lastB=nowB;
46
  return result;
47
}
48
49
void recordSamples(int &stepcounter)
50
{
51
  int i;
52
  unsigned long startZeit=micros();
53
  for (i=0;i<NUMSAMPLES;i++)
54
  {  
55
    samples[i].time=micros()-startZeit;
56
    samples[i].strom= analogRead(analogInPin);    //Analogwert von Stromsensor
57
    samples[i].stepcount=stepcounter;
58
    if (hallSensorImpuls()) stepcounter++;
59
//    delayMicroseconds(100);
60
  }
61
}
62
63
64
void showSamples()
65
{
66
  int i;
67
  int timeOverflow=0;
68
  float ftime;
69
  for (i=0;i<NUMSAMPLES;i++)
70
  { 
71
    if (i>0 && samples[i].time<samples[i-1].time) timeOverflow++;
72
    ftime=samples[i].time/1000000.0+timeOverflow*65536.0/1000000.0;
73
    Serial.print(i+1);
74
    Serial.print("\t");
75
    Serial.print(ftime,6);
76
    Serial.print("\t");
77
    Serial.print(samples[i].stepcount);
78
    Serial.print("\t");
79
    Serial.print(samples[i].strom);
80
    Serial.print('\n');
81
  }
82
  Serial.flush();
83
}
84
85
86
87
int stepcounter=0;
88
boolean waitForStart=false;
89
90
void loop() {  
91
  if (grundStellungsImpuls())
92
  {
93
    stepcounter=0;
94
    waitForStart=true;
95
  }
96
  if (waitForStart && stepcounter==4)  // Triggern auf einen bestimmten Impuls
97
  {
98
//  delay(10); // Optional ein delay zur Überbrückung einer uninteressanten Standzeit
99
    recordSamples(stepcounter);
100
    showSamples();
101
    waitForStart=false;
102
  }
103
  if (hallSensorImpuls()) stepcounter++;
104
}

Ich habe die Anzahl der Samples mal auf 5000 gesetzt, und da jedes 
Sample 6 Bytes belegt, sollten die Samples im Array ca. 30 KB RAM 
benötigen, was auf einem DUE ja locker möglich ist.

> Falls jemand eine Idee hat, welche Möglichkeiten ich noch habe, den
> Motorstrom zu erfassen und v.a. auszuwerten- ich bin für jeden
> Tipp/Hilfe dankbar!

Probier's mal aus mit den schnellen Samplings ab einem bestimmten 
Schritt! Wie gesagt, nach Starten des Sketches muß einmal der 
grundStellungsImpuls() erfolgen, und dann wird das Sampling für die 
Anzahl der definierten Samples gestartet, sobald die Hallsensoren den 
gewünschten Schritt erreicht haben. Nach dem Sampeln werden die Daten 
sofort auf Serial ausgegeben.

Der Zeitstempel läuft in dem Sketch ab Start der Aufzeichnung und wird 
zur Ausgabe auf Serial in Sekunden mit sechs Nachkommastellen 
(Mikrosekunden) umgerechnet.

Falls Du irgendwelche Fragen hast, einfach fragen.

von Carl-Josef S. (ernst-stavro)


Angehängte Dateien:

Lesenswert?

Hallo!

Erstmal wieder ein großes DANKE an Jürgen.

Ich habe den neuen Quellcode ausprobiert und den Trigger auf 
stepcounter==40 gesetzt. Ich bekomme dann ab dem 40. Hallwechsel 5000 
Samples ausgegeben. Das Problem ist jetzt nur, dass die 5000 Samples nur 
von stepcounter==40 bis stepcounter = 79 reichen(Anhang). Das heißt, 
dass  39 Hallwechsel auf 5000 Wertepaare aufgelöst werden.
Ich habe dann mal die Samples erhöht, aber mehr als 10000 Samples ist 
nicht möglich. Ab ca. 11000 Samples bekomme ich eine Fehlermeldung, dass 
irgendwas außerhalb des RAM liegt. Des Weiteren bekomme ich bei 10000 
Samples nur 83 Hallwechsel. Das liegt daran, weil bei stepcounter = 82 
der Motor kurz anhält (insgesamt 0,029062 Sekunden) und ich aber 
(zeitabhängig) insgesamt 3720 Samples für diesen Zeitraum 
bekomme(Anhang).
Ich habe mich außerdem beim Startbeitrag leicht geirrt. Das Getriebe ist 
kein 19:1 sondern ein 34:1. Das heißt, dass ich 680 Hallsignalwechsel 
pro Wellen-Umdrehung erhalte.
...
Ich bin zu dem vorläufigen Ergebnis gekommen, dass es wahrscheinlich das 
Beste wäre, den Motor mit gleichbleibender Geschwindigkeit anzusteuern 
und dann zeitabhängig z.B. alle 1ms eine Messung zu machen. Wenn ich 
also die Drehzahl verringere, dass eine Wellenumdrehung ca. zwei bis 
drei Sekunden dauert (und das ganze bei einer konstanten 
Geschwindigkeit), erhalte ich pro Wellenumdrehung 3000 Werte (bei 1ms 
Abtastrate). Es sollte also möglich sein, den Motor kontinuierlich 
laufen zu lassen, und erst ab der (z.B.) dritten oder vierten 
Wellenumdrehung (dem dritten/vierten Flankenwechsel des 
Grundstellungsinis von HIGH auf LOW) eine Messung von drei weiteren 
Wellenumdrehungen aufzuzeichnen mit einer festen Abtastrate von 1ms.
Das bisherige Problem wird dadurch hoffentlich etwas entschärft, dass 
ich relativ steile und gleichzeitig sehr schmale Strompeaks erfassen 
muss. Durch eine zeitgetriggerte Abtastung kann es zwar immer noch 
passieren, dass ich nicht die Spitze des Peaks erfasse (sondern kurz 
davor messe und dann wieder kurz danach), aber eine andere(bessere) 
Möglichkeit fällt mir gerade nicht ein. Durch die langsamere und v.a. 
gleichmäßige Drehzahl hoffe ich, dass die Peaks nicht mehr so steil 
sind, da der Motor ja nicht mehr aus der Ruhelage beschleunigen/bremsen 
muss. Eine 100%ig gleichmäßige Geschwindigkeit wird nicht realisierbar 
sein, da der Motor durch die unterschiedlichen Kurvenscheiben nicht 
konstant belastet wird, aber einigermaßen konstant sollte klappen. Ich 
habe mir zu diesem Zweck eine SPS besorgt, bei der ich mithilfe eines 
Poti ein Analogwert von 0-10 Volt ausgeben lassen kann. Dieser 
Analogwert steuert dann die Drehzahl des Motors. Werde aber frühestens 
morgen dazu kommen, das ganze zu verdrahten und dann auszuprobieren.
Sollte jemand noch eine andere Möglichkeit einfallen, ich bin für jede 
Inspiration dankbar.
>Falls Du irgendwelche Fragen hast, einfach fragen.
Wenn du Zeit und Lust hast, würdest du mir wieder helfen beim Quellcode 
zur zeitabhängigen Abtastung der Stromwerte? Wäre dir wirklich sehr 
dankbar...

von Jürgen S. (jurs)


Lesenswert?

Carl-Josef S. schrieb:
> stepcounter==40 gesetzt. Ich bekomme dann ab dem 40. Hallwechsel 5000
> Samples ausgegeben. Das Problem ist jetzt nur, dass die 5000 Samples nur
> von stepcounter==40 bis stepcounter = 79 reichen(Anhang). Das heißt,
> dass  39 Hallwechsel auf 5000 Wertepaare aufgelöst werden.
> Ich habe dann mal die Samples erhöht, aber mehr als 10000 Samples ist
> nicht möglich.

Irgendwann sind auch die 96 KB RAM eines Arduino DUE aufgebraucht. An 
RAM benötigen wie gesagt 5000 Samples ca. 30 KB, d.h. 10000 Samples ca. 
60 KB RAM.

> Ab ca. 11000 Samples bekomme ich eine Fehlermeldung, dass
> irgendwas außerhalb des RAM liegt. Des Weiteren bekomme ich bei 10000
> Samples nur 83 Hallwechsel.

Ich habe den Sketch ja erstmal auf möglichst schnelles Sampling 
gestellt. Wie lange dauern denn die 10000 Samples? Zeit in Sekunden wäre 
in der ersten Spalte der Serial-Ausgabe? Ich habe keinen DUE und weiß 
daher nicht, wie schnell die sind.

> Ich bin zu dem vorläufigen Ergebnis gekommen, dass es wahrscheinlich das
> Beste wäre, den Motor mit gleichbleibender Geschwindigkeit anzusteuern
> und dann zeitabhängig z.B. alle 1ms eine Messung zu machen.

Bei meinem zuletzt geposteten Sketch hatte ich die Stelle schon 
auskommentiert gepostet, wo Du das Sampling langsamer einstellen kannst, 
beim Einlesen der Samples:
1
//    delayMicroseconds(100);

Wenn Du hier die Kommentarstriche entfernst, bekommt jedes Sample ein 
delay von 100 Mikrosekunden, mal 10000 Samples sind das 1 Mio 
Mikrosekunden oder 1 Sekunde. D.h. mit diesem delay kannst Du es 
steuern, in welcher Zeit die 10000 Samples gemacht werden. Mit 100µs 
extra delay pro Sample wird auf jeden Fall länger als eine Sekunde nach 
dem Triggern gesampelt. Kürzeres oder kein delay ==> 10000 Samples sind 
schnell voll. Längeres delay ==> 10000 Samples dauern länger.

> Möglichkeit fällt mir gerade nicht ein.

Außerdem habe ich ja vorgegeben, dass Du das Sampeln bei einem 
beliebigen "Stepcounter" beginnen lassen kannst. Dadurch kannst Du Dir 
über verschiedene Vorgaben für den Trigger-Startwert in mehreren 
Umläufen auch einen Gesamtumlauf zusammenstellen. Einmal mit 
stepcounter==40 triggern, einmal mit stepcounter==80 triggern, einmal 
mit stepcounter=120 triggern, und dann kopierst Du Dir die Daten manuell 
zu einem vollen Umlauf zusammen.

von Carl-Josef S. (ernst-stavro)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich habe jetzt zwei Tage verschiedene Messversuche gemacht...
Um die Strompeaks in den Griff zu bekommen, werde ich dem Motor einen 
konstanten Analogwert vorgeben(3,3Volt des Arduinos). Mit diesem Wert 
erreiche ich ziemlich genau eine Wellenumdrehung des 34:1 Getriebes pro 
Sekunde (bei konstanter Geschwindigkeit).
Als Prüfablauf habe ich mir folgendes vorgestellt: Ich steuere den Motor 
an, dass er im Dauerbetrieb läuft. Nach einer bestimmten Anzahl 
Umdrehungen ohne Messung (z.B. fünf) möchte ich dann von den drei 
darauffolgenden Umdrehungen den Strom messen (Motor läuft die ganze Zeit 
über im Dauerbetrieb). Erst nach Vollendung dieser drei Umdrehungen 
werden die Werte seriell übermittelt. Sollte der Motor irgendwann mal 
zwischen/während Startzeitunkt (den Umdrehungen ohne Messung) und dem 
Ende der Messung (nach den Umdrehungen ohne Messung UND den gemessenen 
Umdrehungen) kurz zum Stillstand kommen (zu große Zeitspanne zwischen 
zwei Hallwechsel), ist die Messung wertlos. In diesem Fall sollte eine 
Fehlermeldung ausgegeben werden, die Messwerte verworfen werden und das 
Programm bereit sein, für eine neue Messung. Wenn die eingestellten 
10000 Samples nicht genügen sollten, um die Werte von drei kompletten 
Umdrehungen speichern zu können, d.h. die 10000 Samples sind nach 2,5 
Umdrehungen schon fertig, soll ebenfalls eine Fehlermeldung kommen. Dann 
weiß ich, dass ich das delay etwas erhöhen muss. Wenn für drei 
Umdrehungen nur ca. 9300 Samples benötigt werden, sollen auch nur 9300 
Samples übertragen werden. (Um eine aussagekräftige Auswertung 
durchführen zu können, benötige ich die Stromwerte von drei kompletten 
Umdrehungen, welche mit konstanter Geschwindigkeit ausgeführt wurden.)
Wenn der Motor nach erfolgreich übermittelter Messung immer noch weiter 
läuft, soll das keine Auswirkung haben. Sobald er dann irgendwann 
stoppt, sollte das Programm nach einem delay von ca. 5 Sekunden wieder 
bereit sein, für eine neue Messung. Diese Zeit wird für die Übertragung 
der Daten benötigt.
Zusammenfassung:
Möglichkeit 1: Motor wird angesteuert und läuft mit 
(annähernd)konstanter Geschwindigkeit. Nach vier Umdrehungen stoppt der 
Motor kurz. =>Meldung "Messung fehlgeschlagen" =>Programm für neuen 
Prüfablauf bereit
Möglichkeit 2:  Motor wird angesteuert und läuft mit 
(annähernd)konstanter Geschwindigkeit. Nach sechs Umdrehungen stoppt der 
Motor kurz. Das heißt, er hat fünf Umdrehungen ohne Messung und eine 
Umdrehung mit Messung=>Meldung "Messung fehlgeschlagen" =>keine Daten 
seriell übertragen/Daten verwerfen =>Programm für neuen Prüfablauf 
bereit
Möglichkeit 3: Motor wird angesteuert und läuft mit 
(annähernd)konstanter Geschwindigkeit. Nach (mehr als) acht Umdrehungen 
stoppt der Motor kurz. Das heißt, er hat fünf Umdrehungen ohne Messung 
und drei Umdrehung mit Messung=>Meldung "Messung erfolgreich" => Daten 
seriell übertragen=>Programm nach fünf Sekunden für neuen Prüfablauf 
bereit.

Ich habe versucht,den Code von Jürgen auf den gewünschten Prüfablauf 
anzupassen, aber irgendwie bekomm ichs nicht hin. Im Moment werden nach 
dem fünften Flankenwechsel (von HIGH auf LOW) des Grundstellungsinis 
10000 Samples aufgenommen und übertragen. Da ich ein delay von 200us 
eingestellt habe, bekomme ich also die Stromwerte der darauffolgenden 
zwei Sekunden. Wenn während der ersten fünf Umdrehungen der Motor 
(mehrmals) stoppt, werden trotzdem nach fünf Umdrehungen die Werte der 
darauffolgenden zwei Sekunden übertragen(es soll aber das passieren, was 
in Möglichkeit 1 beschrieben wurde). Wenn während der zwei Sekunden der 
Motor stoppt, werden trotzdem die Samples übertragen(es soll aber das 
passieren, was in Möglichkeit 2 beschrieben wurde). Irgendwie bekomm ich 
es nicht hin, den Motor zu überwachen, dass er sich mit konstanter 
Geschwindigkeit bewegt um dann damit die Freigabe für die Messung 
korrekt zu erteilen...

Im Anhang befindet sich der derzeitige Code. Falls jemand eine Idee hat, 
wie ich die gewünschten Funktionen implementieren kann, wäre ich sehr 
dankbar.

von Miss Franken (Gast)


Lesenswert?

Hallo allerseits,

ich hatte auch schon das Problem (Ausgabe von uController-internen 
Mess-/Rechen-Zustandsgrößen).
Die Serielle Schnittstelle ist zu langsam und vermutlich auch nicht 
rückwirkungsfrei (frißt Rechenzeit, was bei interruptgesteuerten 
Vorgängen das eigentliche Hauptprogramm komplett in die Knie zwingt).

Als work-around hatte ich in meiner Anwendung (DC-Motor-Drehzahlregelung 
mit PID-Regler) zur Kontrolle alle relevanten Daten über die 
DA_Wandler-Kanäle ausgegeben. Der UNO gibt nur PWM-Muster aus, muß also 
somit mit einem RC-Glied noch befiltert werden.

Vorteil:
* lief mit Oszi-Auflösung bis 200ms / DIV relativ glatt durch (sollte 
also bei Deiner Motor-Applikation gut funktionieren)
* visualisiert die Daten im Zeitbereich
* erschiene mir - rein subjektiv- schneller als die serielle 
Schnittstelle

Das ist sicherleich auch nicht die beste Lösung, aber vielleicht hat ja 
jemand noch eine bessere Idee.

Miss Franken

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.