Forum: Mikrocontroller und Digitale Elektronik Schrittmotoren stoppen kurz Arduino Nano


von Kenobi Wan O. (kenobiwan_o)


Lesenswert?

Hallo, ich benutze in meiner Schaltung zwei Nema17 Schrittmotoren, einen 
Arduino Nano und einen HC_SR04 Ultraschallsensor. Das Prinzip meiner 
Schaltung ist etwas gleichmäßig aufwickeln zu können. Das funktioniert 
auch sehr gut, bis auf ein kleines Problem. In meinem Programmcode im 
loop messe ich alle 5 Sekunden den Abstand zu meinem Objekt, um den 
Füllstand zu überprüfen. Diesen gemessenen Abstand rechne ich danach 
noch um und dann wird das Menü auf meinem LCD aktualisiert. Das Problem 
ist alle 5 Sekunden stoppen meine Schrittmotoren ganz kurz und laufen 
danach wieder normal weiter. Ich würde mich freuen wenn mir jemand 
helfen kann. Wenn ihr noch zusätzliche Informationen benötigt fragt 
gerne nach. Grüße.

von Mi N. (msx)


Lesenswert?

Kenobi Wan O. schrieb:
> Das Problem
> ist alle 5 Sekunden stoppen meine Schrittmotoren ganz kurz und laufen
> danach wieder normal weiter.

Mach mal ein Foto von den Motoren. Die sind sicherlich schon etwas älter 
und müssen alle 5 s Luft holen.

von Udo S. (urschmitt)


Lesenswert?

Kenobi Wan O. schrieb:
> In meinem Programmcode

liegt der Fehler.

von J. S. (jojos)


Lesenswert?

Und zwar in der Ultraschall Messung, die blockiert für einige zig 
Millisekunden. Messung und SM Ansteuerung müssen parallel laufen.

von Wastl (hartundweichware)


Lesenswert?

J. S. schrieb:
> Und zwar in der Ultraschall Messung

Das ist landläufig die Zeile 42 im Programm ....

von Wastl (hartundweichware)


Lesenswert?

Kenobi Wan O. schrieb:
> Wenn ihr noch zusätzliche Informationen benötigt fragt
> gerne nach.

Folgende Frage: ist der Programmcode geheim?

von Ralf X. (ralf0815)


Lesenswert?

Wenn sich der nano gerade mit etwas anderem beschäftigen muss, hat er 
für die  Motoren kurzfristig keine Zeit..

Beitrag #7773123 wurde vom Autor gelöscht.
von Kenobi Wan O. (kenobiwan_o)


Angehängte Dateien:

Lesenswert?

Das ist er.

von Joachim B. (jar)


Lesenswert?

Ralf X. schrieb:
> Wenn sich der nano gerade mit etwas anderem beschäftigen muss, hat er
> für die  Motoren kurzfristig keine Zeit.

ist ja nicht falsch, aber oft kann man es so programmieren das BEIDES 
klappt.

z.B. entprelle ich alle 10ms Tasten, dort setze ich sofort ein Flag: 
"bin_im_timer_IRQ", der gesamte Code dauert so um 4-10µs, d.h. ich bin 
danach wieder raus aus der Entprellung icncl. Flag wieder löschen, dann 
habe ich noch einen Interrupt für IRMP alle 64µs, bin ich im 10ms 
TIMER_IRQ  gebe ich den IRMP_Infrarot_IRQ frei und der wird im 10ms 
TIMER_IRQ mit bearbeitet.

Man braucht es nur geschickt schachteln und darauf achten das sie sich 
nicht gegenseitig blockieren.

Ich wüsste jetzt nicht warum das hier nicht auch klappen sollte, so eine 
PWM muß ja nicht mit MHz laufen und bei 5s sollte der Ultraschallsensor 
auch schnell abgearbeit sein, muß ja nicht blockierend sein.

von Rainer W. (rawi)


Lesenswert?

Kenobi Wan O. schrieb:
> Das Problem ist alle 5 Sekunden stoppen meine Schrittmotoren ganz kurz
> und laufen danach wieder normal weiter.

Das ist doch ein perfekter Ansatzpunkt. Überlege dir, welche Routine 
alle 5s die Aktualisierung der Schrittmotoren blockiert. Du möchtest 
mehrere Dinge quasi gleichzeitig tun, also musst du verhindern, dass sie 
sich zu lange gegenseitig blockieren.

von Mi N. (msx)


Lesenswert?

Joachim B. schrieb:
> Ich wüsste jetzt nicht warum das hier nicht auch klappen sollte,

Weil bei Arduino-Code meistens nichts parallel ablaufen kann. Alles 
schön sequentiell ohne Interrupts und meist auch nur zusammengeklickt.

von Ralf X. (ralf0815)


Lesenswert?

Joachim B. schrieb:
> Ralf X. schrieb:
>> Wenn sich der nano gerade mit etwas anderem beschäftigen muss, hat er
>> für die  Motoren kurzfristig keine Zeit.
>
> ist ja nicht falsch, aber oft kann man es so programmieren das BEIDES
> klappt.

Ich sehe mich in dem Bereich noch als "Anfänger", aber weiss auch, dass 
unausgereifter Code eben ungewollte Auswirkungen haben kann.
Hätte ich so einen Effekt wie Kenobi und sehe den Fehler im Code nicht, 
würde ich als ersten mal schauen, was der serielle Monitor da (mit 
timestemp) anzeigt.

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Nema17 ist übrigens keine Bezeichnung für einen konkreten Motor, sondern 
für dessen Befestigung. So wie die E27 Glühbirne.

von Andras H. (andras_h)


Lesenswert?

// Messung durchführen (nicht blockierend)
  unsigned int distanceInCm = sonar.ping_cm();  // Messung in cm


Sicher nicht blockierend?


Sonst im Code alle Delays entfernen und mit state machines ersetzen. Bzw 
durch interrupts.

von Rainer W. (rawi)


Lesenswert?

Manchmal bringt schon ein Aufruf von yield() die Dinge voran. Wenn alle 
kooperieren, klappt es auch mit den parallelen Abläufen.

von Stephan (stephan_h623)


Lesenswert?

Andras H. schrieb:
> // Messung durchführen (nicht blockierend)
>   unsigned int distanceInCm = sonar.ping_cm();  // Messung in cm
>
> Sicher nicht blockierend?

Sicher blockierend ...

Andras H. schrieb:
> Sonst im Code alle Delays entfernen und mit state machines ersetzen. Bzw
> durch interrupts.

Ja.
Und den Schrittmotor per Hardware-PWM takten.

Wäre ein Wunder wenn der Code nicht stottert.

von Falk B. (falk)


Lesenswert?

Kenobi Wan O. schrieb:
> Das ist er.

Naja. Der Ansatz für Multitasking ist ja schon da, zumindest in der 
loop(). Aber da geht es schon los!

m_previousMillis wird in measuring() geschrieben, das ist Unfug. Das 
gehört in loop(). Vor allem, weil measuring noch mehrfach woanders 
aufgerufen wird!
Die Funktionen measuring(), calculations() und drawMenu() sind OK, die 
laufen durch ohne zu warten. windingcontrol() auch. Dort ist auch die 
Handhabung previousSec1 = currentSec1 korrekt. Du hast mehrfach delay(1) 
im Programm, das ist eher unkritisch, denn das ist nur 1ms. Allerdings 
sind deine Funktionen readRotaryEncoder() und encoderChanged() 
vollkommen überladen und machen nicht das, was der Name sagt! Schlechter 
Stil!

Strukturierte Programmierung auf Mikrocontrollern

Auf die Schnelle sehe ich keinen gravierenden Fehler und die Ursache der 
Aussetzer. 8-0

von Jochen (hermann_kokoschka)


Lesenswert?

Kenobi Wan O. schrieb:
> In meinem Programmcode
> messe ich alle 5 Sekunden den Abstand zu meinem Objekt..
> alle 5 Sekunden stoppen meine Schrittmotoren ganz kurz...

Sieht jemand irgendeinen Zusammenhang..?

von Falk B. (falk)


Lesenswert?

Stephan schrieb:
> Andras H. schrieb:
>> // Messung durchführen (nicht blockierend)
>>   unsigned int distanceInCm = sonar.ping_cm();  // Messung in cm
>>
>> Sicher nicht blockierend?
>
> Sicher blockierend ...

Aber wie lange? Das ist ein Ultraschallsensor
1
// ---------------------------------------------------------------------------
2
// Standard ping methods
3
// ---------------------------------------------------------------------------
4
5
unsigned int NewPing::ping(unsigned int max_cm_distance) {
6
  if (max_cm_distance > 0) set_max_distance(max_cm_distance); // Call function to set a new max sensor distance.
7
8
  if (!ping_trigger()) return NO_ECHO; // Trigger a ping, if it returns false, return NO_ECHO to the calling function.
9
10
#if URM37_ENABLED == true
11
  #if DO_BITWISE == true
12
    while (!(*_echoInput & _echoBit)) // Wait for the ping echo.
13
  #else
14
    while (!digitalRead(_echoPin))    // Wait for the ping echo.
15
  #endif
16
      if (micros() > _max_time) return NO_ECHO; // Stop the loop and return NO_ECHO (false) if we're beyond the set maximum distance.
17
#else
18
  #if DO_BITWISE == true
19
    while (*_echoInput & _echoBit)    // Wait for the ping echo.
20
  #else
21
    while (digitalRead(_echoPin))     // Wait for the ping echo.
22
  #endif
23
      if (micros() > _max_time) return NO_ECHO; // Stop the loop and return NO_ECHO (false) if we're beyond the set maximum distance.
24
#endif
25
26
  return (micros() - (_max_time - _maxEchoTime) - PING_OVERHEAD); // Calculate ping time, include overhead.
27
}

>
> Andras H. schrieb:
>> Sonst im Code alle Delays entfernen und mit state machines ersetzen. Bzw
>> durch interrupts.
>
> Ja.
> Und den Schrittmotor per Hardware-PWM takten.

Ist nebensächlich. Die Delays sind sehr kurz, 1ms und nicht für die PWM 
sondern die Schrittsteuerung!

> Wäre ein Wunder wenn der Code nicht stottert.

von Falk B. (falk)


Lesenswert?


von Norbert (der_norbert)


Lesenswert?

Falk B. schrieb:
> Ist nebensächlich. Die Delays sind sehr kurz, 1ms und nicht für die PWM
> sondern die Schrittsteuerung!

Ist denn für jede Messung ein Treffer garantiert?
Innerhalb von so ca. (Schätzung aus dem Arm geschüttelt) 2ms pro 30cm?
Oder gibt's bei Fehlmessungen auch mal ein Timeout?

von Rainer W. (rawi)


Lesenswert?

Kenobi Wan O. schrieb:
> Ich würde mich freuen wenn mir jemand helfen kann.

Bist du stolzer Besitzer eines Logikanalysators (< 10€ reicht) oder 
eines Oszilloskops?

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

unsigned int distanceInCm = sonar.ping_cm();  // Messung in cm

Das funktioniert so? Da fehlt der Parameter für die max. Distanz in cm.

von Falk B. (falk)


Lesenswert?

Norbert schrieb:
> Ist denn für jede Messung ein Treffer garantiert?
> Innerhalb von so ca. (Schätzung aus dem Arm geschüttelt) 2ms pro 30cm?

Schallgeschwindigkeit ist 330m/s = 330mm/ms. Für Hin und zurück stimmt 
es.

> Oder gibt's bei Fehlmessungen auch mal ein Timeout?

Die werden über eine maximale Distanz abgefangen.

von Falk B. (falk)


Lesenswert?

Das Auswerten des Drehgebers ist auch Unfug.

https://docs.wokwi.com/parts/wokwi-ky-040/

Nein, so nicht. Siehe Drehgeber. Das geht auch mit Arduino, wenn man 
es oft genug aufruft bzw. gleich einen Interrupt nutzt.

Beitrag "Drehgeber und Tastenentprellung für Arduino"

von Falk B. (falk)


Lesenswert?

Zum eigentlichen Problem. Wenn all 5s was gemessen wird und alle 5s der 
Motoren kurz stoppen, wird es wohl damit zusammen hängen. Mein heißester 
Kandidat ist die sonar-Messung, bei welcher der Parameter der 
Maximaldistanz fehlt. Es kann aber auch die unsinnige Zuweisung von

m_previousMillis = m_currentMillis;

in measuring() sein.

Das alles kann man einfach testen.

1. measuring() einfach mal in loop() auskommentieren.
2. Die Zuweisung von m_previousMillis in loop machen.
1
    if (m_currentMillis - m_previousMillis >= 10000) {
2
      m_previousMillis = m_currentMillis;
3
      measuring(); //Methode für das Ausmessen der Entfernung zur Spule
4
      calculations(); //Methode zum Umrechnen der Entfernung zum Durchmesser
5
      drawMenu(); //Methode zum Aufrufen des Menüinhalts
6
    }

von Norbert (der_norbert)


Lesenswert?

Falk B. schrieb:
> Die werden über eine maximale Distanz abgefangen.

Bei 4 Metern (war der Wert den ich so auf die Schnelle gefunden habe) 
kämen da aber ordentlich Millisekunden zusammen.
Und wenn's dann noch kalt und trocken ist… ;-)

von J. S. (jojos)


Lesenswert?

man könnte die Zeit die in sonar verbracht wird auch einfach messen 
anstatt zu vermuten...

von Norbert (der_norbert)


Lesenswert?

J. S. schrieb:
> man könnte die Zeit die in sonar verbracht wird auch einfach
> messen
> anstatt zu vermuten...

Wenn man das könnte, hätte die Eingangsfrage nicht gestellt werden 
müssen!

von Kenobi Wan O. (kenobiwan_o)


Lesenswert?

Falk B. schrieb:
> Zum eigentlichen Problem. Wenn all 5s was gemessen wird und alle
> 5s der
> Motoren kurz stoppen, wird es wohl damit zusammen hängen. Mein heißester
> Kandidat ist die sonar-Messung,
Ich habe im Internet gesehen, dass ich mit der NewPing Libary da was 
machen kann, jedoch ist mir diese noch etwas fremd weshalb das ein 
Fehler sein kann. Sobald ich es ausprobieren kann schaue ich mal.

bei welcher der Parameter der
> Maximaldistanz fehlt. Es kann aber auch die unsinnige Zuweisung von
>
> m_previousMillis = m_currentMillis;
>
> in measuring() sein.
Ich habe schon viel ausprobiert und du hast völlig recht, dass gehört da 
nicht hin. Löst das Problem aber auch nicht leider.
> Das alles kann man einfach testen.
>
> 1. measuring() einfach mal in loop() auskommentieren.
> 2. Die Zuweisung von m_previousMillis in loop machen.
>     if (m_currentMillis - m_previousMillis >= 10000) {
>       m_previousMillis = m_currentMillis;
>       measuring(); //Methode für das Ausmessen der Entfernung zur Spule
>       calculations(); //Methode zum Umrechnen der Entfernung zum
> Durchmesser
>       drawMenu(); //Methode zum Aufrufen des Menüinhalts
>     }
Danke für deine Ideen.

von Kenobi Wan O. (kenobiwan_o)


Lesenswert?

Rainer W. schrieb:
> Kenobi Wan O. schrieb:
>> Ich würde mich freuen wenn mir jemand helfen kann.
>
> Bist du stolzer Besitzer eines Logikanalysators (< 10€ reicht) oder
> eines Oszilloskops?
Ja aber nicht zuhause. Ich könnte erst im laufe der nächsten Woche dasd 
Oszilloskop anschließen :(

von Rainer W. (rawi)


Lesenswert?

Kenobi Wan O. schrieb:
>> Bist du stolzer Besitzer eines Logikanalysators (< 10€ reicht) oder
>> eines Oszilloskops?
> Ja aber nicht zuhause.

Bis du da wieder ran kommst, könntest du in eigenes Werkzeug 
investieren,
z.B. https://www.ebay.de/itm/126321121803

von Falk B. (falk)


Lesenswert?

Ich glaube das Problem liegt in windingcontrol(). Dort wird ja, recht 
Arduino und Multitasking gerecht, im festen Zeitraster der 
Schrittmotor mit Pulsen versorgt.
1
//Festlegung der Taktzeit für den Schrittmotor der Spule
2
    if (currentSec2 - previousSec2 >= pulsetime_reel) {
3
      previousSec2 = currentSec2;
4
      stepper2state = HIGH;
5
      //Serial.print("pulsetime_reel: ");
6
      //Serial.println(pulsetime_reel);
7
    }

Wenn dann alle 5s die Ultraschallmessung mit relativ hohem Zeitbedarf da 
reinhaut, stottert der Motor natürlich kurz. Dagegen gibt es mehrere 
Maßnahmen.

a) Schrittmotorpulse in einem Interrupt erzeugen, der kann die 
Ultraschallmessung unterbrechen, was aber zu Meßfehlern führt.
b) Die Ultraschallmessung mit der Schritterzeugung synchronisieren. 
Sprich, mittels Signal (Variable) markieren, wann gerade ein Schritt 
erzeugt wurde. Wenn denn die Ultraschallmessung erfolgen soll, nur dann 
messen, wenn kurz vorher der Schritt gemcht wurde. Dann dann hat man für 
die Messung ein Zeitfenster bis zum nächsten Schritt. Das setzt aber 
voraus, daß die Messung immer kurz genug ist, um in das Fenster zu 
passen.
c) Die Pulse für den Schrittmotor werden per PWM in Hardware erzeugt. 
Das läuft parallel zum Programmablauf und wird durch die 
Ultraschallmessung nicht gestört. Das meinte oben schon mal Stefan ich 
hab es wohl falsch verstanden. Er hatte wohl Recht.

Beitrag "Re: Schrittmotoren stoppen kurz Arduino Nano"

: Bearbeitet durch User
von Wastl (hartundweichware)


Lesenswert?

Wastl schrieb:
> Folgende Frage: ist der Programmcode geheim?

Kenobi Wan O. schrieb:
> Das ist er.

SCNR

von Mike J. (linuxmint_user)


Angehängte Dateien:

Lesenswert?

Kenobi Wan O. schrieb:
> HC_SR04 Ultraschallsensor

Ich nutze den JSN-SR04T Ultraschallsensor (wasserdicht für 2,50€), der 
ist zwar die ersten etwa 20cm blind, aber wenn man R19 mit 47kOhm 
bestückt, dann sendet er die Entfernungsdaten über UART in Millimeter 
und das kann man per Interrupt erledigen. So braucht man nicht aktiv zu 
warten.

JSN-SR04T Modul
Modus bei Widerstandswert R19:
- offen = Impuls / Echo (wie bei HC-SR04)
- geschlossen => Text mit z.B. "Gap=1638mm" wird kontinuierlich gesendet

// UART 9600 Baud 8 Datenbits, 1 Stoppbit , keine Parität ------
- einzelner Messwert: 27kOhm bis 85kOhm (47kOhm)
Um die Messung auszulösen muss man zum Modul einfach irgend ein Zeichen 
senden.
Resultat: FF 04 D4 D7
0xFF = Startzeichen
0x04D4 = 1236mm
D7 = Summe

- Kontinuierliche Messwerte: 85kOhm bis 172kOhm (120kOhm)

von Rainer W. (rawi)


Lesenswert?

Falk B. schrieb:
> Dagegen gibt es mehrere Maßnahmen.

Und natürlich gibt es noch mehr:
Die Pulsdauer von der US-Entfernungsmessung kann per Capture-Funktion 
vom Timer erfasst werden, ganz unabhängig von der Software und ohne 
irgendwen zu stören.

: Bearbeitet durch User
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.