Problem: Parallel angesteuerter Stepper verursacht zeitl. Verzug bei Sensorintervall

Hallo Zusammen!
Auch bei mir gilt die vielfach zitierte Einleitung: Ich bin ein Beginner...
Zu meinem Projekt:
Ich baue einen kleinen Prüfstand für einen Zugdruckversuch:
Ein Stepper (NEMA mit TB6600-Treiber) dient als Antriebsmotor und erzeugt mittels eines Exzenters eine translatorische Bewegung. An dieser ist eine Wägezelle (dymh-103) montiert, die mir den Zug- bzw. Druck misst.
Ich habe das ganze auch zum laufen gebracht. Code s.u.
Problem ist nun offensichtlich, dass immer wenn der Stepper angesteuert wird (Intervall 1000) ein Verzug bei der Sensormessung auftritt. Statt alle 90ms zu messen erfolgt dann die Messung mit ca. 270ms. Die "verlorene Zeit" wird dann durch zeitgleiche Ausgaben aufgeholt und pendelt sich dann wieder ein. Klingt bescheuert, daher habe ich einen Auszug des Exports vom seriellen Monitor als Bild angefügt.

Meine Frage ist nun: Kann ich das mit dem Code irgendwie beheben oder empfiehlt sich für eine solche genaue Messung (intervall max. 100ms) dann ggf. ein zweites Arduino (ich habe ein REV3) um getrennt den Motor und den Sensor anzusteuern?

Vielen lieben Dank an Alle, die mir dazu Tipps oder Hilfestellungen geben können!!

Ich habe mir viel Mühe gegeben es selbst zu lösen, komme aber nach einigen frustrierenden Nächten nicht mehr weiter.

NACHTRAG:

  1. Der Code ist das Resultat mehrerer Anläufe und enthält ein paar überflussige Variablendefinitionen etc. (Aber er funktioniert --> never change a running system)
  2. zur Ausgabe: Links ist die orig. Ausgabe mit Zeit und Druckmessung. Rechts davon extrahiert die Intervalle; als differenz und kumuliert.
#include "HX711.h"

// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = 2;
const int LOADCELL_SCK_PIN = 5;

// Belegung Steppermotoersteuerung
#define dirPin 4
#define stepPin 6
#define stepsPerRevolution 6400

const byte NoOfTimes = 3;
unsigned long beginToWait[NoOfTimes];
unsigned long previousMillis = 0;
const int wait1   =  90; // Intervall Sensor
const int wait2   =  1000;  // Intervall Stepper

int stepDelay=200; // Step timing
int n=1; //Loop count
unsigned long stepMicros; // looks after timing of steps
boolean nextStep; // keeps track of StepPin

unsigned long currentMicros; // the current time in microseconds
unsigned long currentMillis; // the current time in milliseconds

int stepCount; // keep of track of steps
int stepTarget = 6400; // nr of steps per rotation

int mode=1;
int mode2=1;
boolean TimeIsOver(int Index, unsigned long TimeToWait){
   if(millis()-beginToWait[Index] > TimeToWait) {
          return true;
   } else return false;
}  

HX711 scale;

void setup(){
  Serial.begin(57600);
  for (int i=0; i< NoOfTimes;i++) beginToWait[i] = 0;
  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
    // Declare pins as output:
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}

// JETZT GEHTS LOS :-)

void loop(){

 currentMicros=micros(); // get the current micros at the beginning of the loop
 currentMillis=millis(); // get current millis() to use anywhere in system

if (Serial.available() > 0)                             // Wenn der serielle Monitor 
                                                          // aufgerufen wird... 
  { 


  
    if (TimeIsOver(0, wait1)){       //Intervall Sensor
          // Do the Wägezelle / alle 90ms
            if (scale.is_ready()) {
            long reading = (((scale.read()* (0.01))-88)*0.8079847908745253);
            Serial.print("HX711 reading: ");
            Serial.println(reading);
            } 
     else {
    Serial.println("HX711 not found.");
    }
           beginToWait[0] = millis();
   } 

 if (TimeIsOver(1, wait2)){  //Intervall Steppermotor
  
 }
  if (stepCount != stepTarget) {  // check we haven'treached the target
    if (currentMicros-stepMicros >= stepDelay) {
      nextStep= !nextStep; // swap the next step state
      digitalWrite (stepPin, nextStep);
      stepCount++; // increment the step count
      stepMicros=currentMicros;
     }
  }else {stepCount=0;
          Serial.print ("Schleife:  ");
          Serial.print (n);
          Serial.print('\n');
          beginToWait[1] = millis();
          n++;
  }
}
}

Korrigiere mal die Code-Tags. Eben sah es anders aus.
Edit-Modus aktivieren
den Code markieren und dann den < code > -Button klicken
hach herrje jetzt fehlen wieder die Daten. Mach die Daten als Bild und als Code-Section

Um genauer dahinter zu kommen:

baudrate auf 115200 setzen.
zusätzlich ausgeben lassen der wie vielte Durchlauf das jeweils ist.

Oder noch besser für die Schrittausgabe die MobaTools verwenden.
Dann werden die Schritte im Hintergrund von einem Timer-Interrupt erzeugt.
Ganz unabängig was der sonstige Code-macht.

Beschreibe mal den Gesamtablauf.

Irgendwie spielt da noch die serielle Schnittstelle mit rein?
Was macht die genau?
Sendest du da im 50 Millisekundenabstand irgendwas über die serielle Schnittstelle?

Das ging ja schnell. Danke Stefan!

Die Serielle Schnittstelle kommt ins Spiel weil ich das programm erst starten lassen möchte, nachdem ich die Enter-Taste gedrückt habe.
Der Code dazu ist sicherlich absoluter Mist; aber zumindest der Start funktioniert. Das Stoppen habe ich ohne die While-Schleife nicht hinbekommen.

Also gewünscht ist:
Nach Öffnen der seriellen Schnittstelle und Drücken der Eingabetast beginnt das Programm.
Dadurch sollen gleichzeitig Stepper und Sensor gestartet werden. Der Sensor wird alle 90ms angesprochen und der Stepper alle 1000ms.

Die Wägezelle solle alle 90ms die Kraft messen und anzeigen. Zusätzlich soll nach jeder erfolgten Umdrehung des Steppers die Anzahl der Umdrehungen ausgegeben werden.

Ich werde später wie vorgeschlagen die Baudrate erhöhen und den Durchlauf zusätzlich ausgeben und das Ergebnis anschließend posten.

Da musste mal noch genauer beschreiben was "stepper alle 1000 ms ansprechen" heißt

Soll da alle 1000 Millisekunden ein einzelner Schritt ausgegeben werden?
Soll der Stepper jede Sekunde eine Umdrehung machen?
Wie viel Schritte soll der Stepper "am Stück" machen?
Wie lange dauert es bis de Stepper eine Umdrehung gemacht hat?
bzw. die Anzahl Schritte ausgegeben hat?

Soll die Wägezelle "irgendwie ausgelesen werden
oder
synchonisiert mit der stepper-bewegung?
genau während der stepper-bewegung?
genau dann wenn die stepper-bewegung zu ende ist?

Da wird was auf Zug / Druck belastet. Was ist das was da auf Zug/Druck belastet wird?

da ist dir ein Bildlink reingerutscht

Anbei 2 Bilder zum Versuchsaufbau. Ein Prüfling wird auf zug/druck geprüft um die Festigkeit zu analysieren.
An der Zug/Druckstange ist die Wägezelle integriert.

Der Sensor soll nun durchgehend in möglichst kurzen intervallen (aktuell 90ms; sonst krieg ich lauter fehlermeldungen) den Zug/Druck messen.

Der Motor soll ca 10Umdrehungen in der Minute machen. Das ist mein Ziel.
Dazu habe ich als Basis den Code wie folgt verwendet. Der scheint Standard zu sein; und er verwendet immer eine delay(1000) Verzögerung. Ich habe das nicht hinterfragt sondern als gegeben akzeptiert.

Schrittmotor ansteuern mit Arduino + TB6600 (arduino-projekte.info)


Pruefstand 2
Ich steuere die Geschw. in dem ich 6400 schritte pro Umdrehung vorgebe und dann mit der Variable stepDelay arbeite, um die 10 Umdrehungen hinzubekommen. (Die Rotationsgeschwindigkeit muss nicht so genau sein).

delay(1000) macht:

friere den microcontroller 1 Sekunde lang ein. Stoppe das komplette Programm für eine Sekunde.

Bist du dir sicher das der Motor jeweils eine Sekunde lang absolut still stehen
und auch ansonsten nichts passieren soll?

Ich vermute mal eher der Schrittmotor soll sich kontinuierlich bewegen.
Das musst du einfach mal sehr detailliert beschreiben.
Wie viele Nachfrage-Postings willste denn noch bekommen?
10 pro Minute?

Das ganze scheint ein wissenschaftlicher Versuch zu sein.
Kannste da 100 Euro extra ausgeben und einen extrem schnellen Microcontroller (Teensy 4.1) der direkt an einem Highspeed-AD-Wandler hängt und 500 kByte daten zunächst in seinen RAM-Speicher schreibt oder mit 1 Megabaud auf der seriellen Schnittstelle ausgibt?

#include "HX711.h"

// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = 2;
const int LOADCELL_SCK_PIN = 5;

// Belegung Steppermotoersteuerung
#define dirPin 4
#define stepPin 6

const int wait1   =  90; // Intervall Sensor
const int stepDelay = 200; // Step timing

HX711 scale;

void setup() {
  Serial.begin(115200);
  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
  // Declare pins as output:
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}

void loop() {
  static unsigned long MesOldMills = millis();
  static unsigned long stepMicros = 0xFFFFFFFFUL;

  if (millis() - MesOldMills >= wait1)) {     //Intervall Sensor
    MesOldMills += wait1;
    // Do the Wägezelle / alle 90ms
    if (scale.is_ready()) {
      long reading = (scale.read()  - 8800) * 0.008079847908745253;
      Serial.println(reading);
    }
    else Serial.println("nA");
  }

  if(Serial.available>0){Serial.read();Serial.read();stepMicros =micros();}
  if (micros() - stepMicros >= stepDelay) {
      stepMicros += stepDelay;
      bool SS = digitalRead(stepPin);
      digitalWrite (stepPin, !SS);
  }
}
1 Like

Hi Stefan, mit diesem Code dreht der Motor kontinuierlich. Es gibt keine Unterbrechung.
Wie gesagt, ich hab es als gegeben genommen. Richtig verstanden hab ich diesen Punkt nicht.

wie startest du eigentlich den Motor? bei dir startet er sobald etwas im Serial zu lesen ist, wird aber nie gelesen, d.h. Motor läuft immer und immer wieder

Programmstart:
Öffnen des Seriellen Monitors und dann Drücken der Enter-Taste.
Danach fängt der Motor an zu Drehen. Und er soll sich durchgehend drehen, da ich mehrere tausend umdrehungen machen möchte (konkrete mehrere tausend dehnungen und stauchungen am Prüfling) und dabei die auftretenden Kräfte dokumentieren will.

eigentlich man kann einfach PWM Frequenz so einstellen dass es 10RPM gibt.
das befreit Prozessor.
wie viel Schritten pro Umdrehung hast du im Treiber eingestellt?

Es war die sch.... Baudrate.
So einfach die Lösung!
Mit 115200 schon deutlich besser und mit 230400 keine Probleme mehr.

Viiiiiiieeeeellen Danke Stefan. Ich stoße auf dich an! Prost.

Eine wohl einfache Frage an euch noch. Habt ihr für mich die passenden Zeilen, damit ich das Programm im seriellen Monitor mit Enter starte und durch erneutes drücken wieder beenden kann?
DANKE :slight_smile:

#include "HX711.h"

// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = 2;
const int LOADCELL_SCK_PIN = 5;

// Belegung Steppermotoersteuerung
#define dirPin 4
#define stepPin 6

const int wait1   =  90; // Intervall Sensor

HX711 scale;

void setup() {
  Serial.begin(115200);
  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
  // Declare pins as output:
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}

void loop() {
  static unsigned long MesOldMills = millis();
  static bool isRun = false;

  if (Serial.available() > 0) {
    while (Serial.available() > 0)Serial.read();
    isRun = !isRun ;
    analogWrite(stepPin, isRun ? 127 : 0);
  }

  if (millis() - MesOldMills >= wait1)) {     //Intervall Sensor
    MesOldMills += wait1;
    // Do the Wägezelle / alle 90ms
    if (scale.is_ready()) {
      long reading = (scale.read()  - 8800) * 0.008079847908745253;
      Serial.println(reading);
    }
    else Serial.println("nA");
  }
}

korrigiert

Dein Code schaut super aus kolaha!

Will ihn gerne gleich ausprobieren. in der Zeile mit dem While-Befehl kommt die Fehlermeldung : invalid use of member function 'virtual int HardwareSerial::available()' (did you forget the '()' ?)

Ich sehe aber den Fehler nicht.

Ja, available ist eine Methode, da fehlen die (), also Serial.available()
Der Fehler tritt mehrfach auf.

Gruß Tommy

korrigiert. nach Berechnung soll RPM 18.375 sein. wenn du Step Pin auf Pins 3, 9, 10, 11 verlegen könntest würde es 9.1875 RPM sein.

1 Like

Danke Dir Tommy. Alles erledigt.
@ kolaha: Code funktioniert schon einwandfrei

Ich freu mich grad riesig. Danke Euch allen für die Hilfsbereitschaft! Tolles Forum! Gemeinsam geht was voran!

Hi Kolaha!

Danke für den Top-Code! Bin gleich darauf übergegangen.
Kannst du mir kurz noch den von dir gemachten analogwrite Befehl erklären?
ich komm aus der Internetrecherche noch nicht dahinter, was das Fragezeichen und ": 0") bedeutet (analogwrite (pin, bool ? 127 : 0)
Die Rechnung zu den Umdrehungen habe ich mit 976Hz /2 *60/6400 verstanden. Wie ermittelst du die 18,375?
Ich nehme an, dass ich die Geschwindigkeit mit dieser Variante nur durch die Verwendung der Pins und durch die Festlegung der Schritte pro Umdrehung regeln kann.
Stimmt das?