Problem mit Schrittmotor Steuerung / MobaTools

Ich arbeite immer noch an der Steuerung eines Kreuztisches mit den Daten von der SD-Karte.
Ich hatte Probleme mit den Schrittdaten. Wenn ich mit dem Tisch z.B. 77mm weit fahren musste, waren das 30800 Schritte. Die wurden übergeben und der Tisch ist die Strecke Anstandslos gefahren. Dann habe ich mal 120mm Fahrweg auf der Karte eingeben, und es wurden nicht 48000 Schritte an die MobaTools übergeben sondern irgend ein Schwachsinn mit -7........... ich hab es mir nicht gemerkt. Also dachte ich, ich nehme bei nicht die Schritte von der Karte, sondern die mm und rechne mit die Schritte einfach aus. Ja, gesagt = getan, aber das gab neue Probleme. Da hatte ich dann plötzlich immer Probleme egal ob hohe oder niedrige Zahlen.
Ich habe jetzt zur leichteren Kontrolle auf der Karte immer als Weg 16mm eingegeben. Also recht überschaubar. Der Tisch macht bei einer Umdrehung 4mm, das heißt bei 16mm Fahren, ich muss genau 4 Umdrehungen machen. Das Programm mache aus den 16 mm 6400 Schritte, 1600 je Umdrehung, macht bei 4 Umdrehungen 6400 Schritte macht 16mm. OK.

Ich übergebe also diesen Wert im Programm an MotoStepper. Das schaut so aus:

 if (motor == 1)
    {
      if (richtung == 1)
      {
        myStepperX.doSteps(schritte);
      }
      if (richtung == 2)
      {
        myStepperX.doSteps(-schritte);
      }
      lcd.setCursor (0, 3);
      lcd.print("                  ");
      lcd.setCursor (0, 3);
      lcd.print(schritte);
      lcd.print("-");
      lcd.print(motor);
      motor = 0;
      richtung = 0;
      schritte = 0;

Die übergebenen Schritte lasse ich direkt bei der Übergabe, wie hier zu sehen, anzeigen. Der übergebene "schritte" Wert ist wie gesagt "6400". Das bekomme ich auch im Display, Ausserdem bekomme ich die mm angezeigt, aus dem die 6400 Schritte berechnet wurden. Und zwar fahre ich diese 6400 Schritte einmal in Richtung "1" und danach in Richtug "2".
In Richtung 1 macht der Motor aber dann bischen über 37!! Umdrehungen, also mehr als 59200 Schritte :astonished:
In Richtung 2 macht der Motor die richtigen 4 Umdrehungen. Aber bei beiden fahrten werden 6400 Schritte direkt bei der Übergabe der Schritte am MobaTools übergeben. Im Display habe ich in beiden Richtungen als Fahrdaten 16mm / 6400 Schritte.

Die Rechung mit der ich aus dem mm die Schritte rechne ist
"schritte = (mm / 25) * teiler;"
der teiler = "10000"
Die eigentlich Rechnung ist mm / 0,0025, weil ein Schritt 0,0025mm beträgt.

Es muß an der Umrechnung liegen, weil es geklappt hat, als ich die Schritte von der SD-Karte verwedet habe. Aber das waren die selben 6400 Schritte. Da bekam ich erst Probleme wenn die Schritte irgendwo größer 40000 Schritte waren, also z.B. 48000 Schritte. Deshalb will ich mir die Schritte einfach selber ausrechnen. Aber da geht auch wieder was schief. :roll_eyes: Ich komm nur nicht drauf, wo es hängt.

Franz

Die Lösung findet sich vermutlich in Zeile 42.

1 Like

Ja ich weiß. Hilf nur nix wenn ich hier alles reinhänge. Aber wenn du meinst.

/*
  ################################################################################################################
  Kreuztisch Steuerung mit Schrittmototoren erstellt mit der Mobatools Lib. die ich sehr empfehlen kann.
  Die Fahrdaten werden mit Excel eingegeben, auf eine SD-Karte mit Trennung durch Semikolon exportiert,
  und vom Arduino wieder ausgelesen.
  Die beötigten Daten in einer Fahrdaten Zeile sind:
  Position 1: Motor / Achse 1 - 3 für X, Y, Z
  Position 2: Fahren ja / nein. Im Moment immer 1
  Position 3: Dir, also rechts / links = 1 - 2
  Position 4: Tempo 1 - 1000
  Position 5: Schritte 1 - 250000
  Das ist die Version 3.2 als erster Lauffähiger Code.
  Die Pins des Kartenlesers sind beim Arduino Mega:
  Miso Pin 50
  Mosi Pin 51
  SCK Pin 52
  CS Pin 53
  GND und VCC 5 Volt natürlich auch noch.
  Der Kartenleser macht Karten bis 32GB
  Mit FAT16/FAT32-Partition
  Wenn die Fahrgeschwindigkeit zu gering ist, kann man in der Lib.Datei "MobaTools.h"
  "#define CYCLETIME       200" ändern auf "#define CYCLETIME       100"
  Dann das Programm nochmal neu auf den Arduino übertragen.
  !!!Achtung!!! die Mobatools.d ist dann für dieses Programm i.O.
  aber muss danach wieder in den ursprünglichen Zustand versetzt werden !!
  Wir belegen mit SPI und I2C mindestens 27-30 Pin´s also fallen kleinere Arduinos aus.
  Im Moment sind es nur 23 Pin´s aber für Spindel ein/aus, Kühlung, Absaugung,
  sollte man sich die Möglichkeit offen halten. Also lieber mit 30 rechnen!!!
  Ich habe immer gerne Luft nach oben, wenn ich was baue.
  ###############################################################################################################
*/
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
//---SD Kartenleser-------------------------------
#include <SPI.h>
#include <SD.h>
File myFile;

byte gelesen = 0;
const byte chipSelectPin = 53;
const String filename = "Mappe1.csv";
char zeilenBuffer[30];
char auswerteBuffer[6][8];
byte automatik = 0;
//----------------Sonderzeichen-------------------
#define OHM   "\xF4"    // Zeichen für Ohm
#define AE    "\xE1"    // Zeichen für "ä"
#define OE    "\xEF"    // Zeichen für "ö"
#define SS    "\xE2"    // Zeichen für "ß"
#define OBEN    "\x5E"    // Zeichen für "hoch"
#define RECHTS   "\176" // Pfeil nach rechts
#define LINKS   "\177"  // Pfeil nach links
#define UE  "\365"      // Zeichen für "ü"
#define GRAD  "\337C"   // Zeichen für "Grad" Celsius
//------------------------------------------------
#define MAX8BUTTONS // spart Speicher, da nur 8 Taster benötigt werden (saves RAM)
#include <MobaTools.h>
// Pindefinitions - change to your needs
//----------Motor 1-------------------------------
const byte dirPin1       = 5;
const byte stepPin1      = 4;
const byte enaPin1       = 6;
//----------Motor 2-------------------------------
const byte dirPin2       = 9;
const byte stepPin2      = 8;
const byte enaPin2       = 10;
//----------Motor 3-------------------------------
const byte dirPin3       = 44;
const byte stepPin3      = 43;
const byte enaPin3       = 45;
//----------Taster--------------------------------
const byte button1Pin   = A1; //---Motor1 links---
const byte button2Pin   = A2; //---Motor1 rechts--
const byte button3Pin   = A3; //---Motor2 links---
const byte button4Pin   = A4; //---Motor2 rechts--
const byte button5Pin   = A5; //---Motor3 links---
const byte button6Pin   = A6; //---Motor3 rechts--
const byte button7Pin   = A7; //---Fräsen Start Bedienteil---
const byte button8Pin   = A8; //---Fräsen Start Station------
//--------------Taste zum Entsperren, wenn Stopp durch fahren==0
const byte entsperrtaste = A9; // Taste die nicht im MoToButton integriert ist
//----------Tempo_Poti---------------------------------------------------------------
const byte potPin       = A0;   // Poti muss ein analoger Eingang sein
const int STEPS_REVOLUTION = 1600;
unsigned long Sekundenablauf01 = 0; // Tastenabfrage von Taster02 300ms aussetzen
const unsigned long Pausezeit01 = 1000;
//--------Fahrdaten------------------------------------------------------------------
byte motor = 0;               // Achsenauswahl 1-2-3 ist X-Y-Z
byte fahren = 1;              // Motoren bewegen
byte richtung = 0;            // Richtung der Bewegung 1 oder 2
int tempo1 = 0;               // Tempo für Handsteuerung, wird vom Poti eingestellt
int tempo2 = 0;               // Tempo zum Fräsen
int tempo = 0;                // Wird vom Programm zur übergabe benutzt
float mm = 0;
float multiplikator = 25;
float teiler = 10000;
unsigned int schritte = 0;   // Schritte die der Motor fahren soll
//-----------------------------------------------------------------------------------
//Stepper einrichten ( 1600 Schritte / Umdrehung - 1/4 Microstep )
MoToStepper myStepperX( STEPS_REVOLUTION, STEPDIR );  // 1600 Steps/ Umdrehung
MoToStepper myStepperY( STEPS_REVOLUTION, STEPDIR );  // 1600 Steps/ Umdrehung
MoToStepper myStepperZ( STEPS_REVOLUTION, STEPDIR );  // 1600 Steps/ Umdrehung
// Taster einrichten
// Den Tasternamen die Indizes 0...7 zuordnen
enum { Button1 = 0, Button2, Button3, Button4, Button5, Button6, Button7, Button8 };
// muss als byte definiert sein, damit ein enfaches sizeof funktioniert
const byte buttonPins[] = { button1Pin, button2Pin, button3Pin, button4Pin, button5Pin, button6Pin, button7Pin, button8Pin};
MoToButtons button( buttonPins, sizeof(buttonPins), 20, 500 );

MoToTimebase speedIntervall;    // Zeitinterval zum Auslesen des Speedpotentiometers
// the speed pot ist read only every 'speedintervall' ms

int vspeed = 0;                 //Steppergeschwindigkeit in U/min*10
//==============================================================================================================
void setup()
{
  lcd.begin();
  lcd.backlight();
  Serial.begin(9600);
  pinMode(entsperrtaste, INPUT_PULLUP); // Eingang für Entsaperrtaste
  //-----------------------------Motor 1----------------------------------------------------
  myStepperX.attach( stepPin1, dirPin1 );
  myStepperX.attachEnable( enaPin1, 10, LOW );        // Enable Pin aktivieren ( LOW=aktiv )
  myStepperX.setSpeed( 200 );
  myStepperX.setRampLen( 100 );                       // Rampenlänge 100 Steps bei 20U/min
  speedIntervall.setBasetime( 100 );                  // 100ms Tickerzeit
  //------------------------------Motor 2-----------------------------------------------------
  myStepperY.attach( stepPin2, dirPin2 );
  myStepperY.attachEnable( enaPin2, 10, LOW );        // Enable Pin aktivieren ( LOW=aktiv )
  myStepperY.setSpeed( 200 );
  myStepperY.setRampLen( 100 );                       // Rampenlänge 100 Steps bei 20U/min
  //-----------------------------Motor 3------------------------------------------------------
  myStepperZ.attach( stepPin3, dirPin3 );
  myStepperZ.attachEnable( enaPin3, 10, LOW );        // Enable Pin aktivieren ( LOW=aktiv )
  myStepperZ.setSpeed( 200 );
  myStepperZ.setRampLen( 100 );                       // Rampenlänge 100 Steps bei 20U/min
  //------------------------------------------------------------------------------------------
  //----------CD_Kartenleser aktivieren-------------------------------------------------------
  pinMode(SS, OUTPUT);
  Serial.begin(9600);
  while (!Serial)
    Serial.print("Initializing SD card...");
  if (!SD.begin(chipSelectPin)) // Ist SD Karte nicht ansprechbar?
  {
    Serial.println("Initialisierung fehlgeschlagen!");
    lcd.setCursor (0, 0);
    lcd.print(F("!! Karten_Fehler !!"));
    while (1); // Wenn Karte nicht ansprechbar, ist hier Programm Ende !!!
  }
  lcd.setCursor (0, 1);
  lcd.print(F("                   "));
  lcd.setCursor (0, 1);
  lcd.print(F(" Karte ist bereit! "));
  //-----------------------------------------------------------------------------------------
}
//=============================================================================================================
void loop() {
  lcd.setCursor (0, 0);
  lcd.print(F("Kreuztisch_Pr._V3.5 "));
  //------SD_Karte öffnen zum Lesen-------------------------------------------------------
  if (automatik == 1)
  {
    lcd.setCursor (0, 2);
    lcd.print(F("  Automatik l"AE"uft  "));
    lcd.setCursor (0, 3);
    lcd.print(F("                   "));
    lcd.setCursor (0, 1);
    lcd.print(F("                   "));
    myFile = SD.open(filename);
    if (myFile)
    {
      while (myFile.available())
      {
        if (fahren == 1)
        {
          leseZeile();
          ausgabeZeile();
          teileZeile();
          ausgabeWerte();
        }
        else {
          // ---------------Ist Taste Weiter gedrückt??---------------------------------
          if (digitalRead(entsperrtaste) == 0)
          {
            fahren = 1;
            lcd.setCursor (0, 2);
            lcd.print(F("    Weiterfahren   "));
          }
        }
      }
      // schließe die Datei:
      myFile.close();
      //Serial.println(F(" geschlossen!"));
      automatik = 0;
      lcd.setCursor (0, 2);
      lcd.print (F("                    "));
      lcd.setCursor (0, 2);
      lcd.print (F(" Karte abgearbeitet "));
    }
    else
    {
      // Wenn die Datei nicht geöffnet wurde, drucke einen Fehler :
      //Serial.print("Fehler beim öffnen von ");
      //Serial.println(filename);
    }
  }
  //--------------------------------------------------------------------------------------
  button.processButtons();          // Taster einlesen und bearbeiten

  // Speed alle 100ms neu einlesen und setzen
  if ( speedIntervall.tick() ) {
    // wird alle 100ms aufgerufen ( Tickerzeit = 100ms im setup() )
    vspeed = map((analogRead(potPin)), 0, 1023, 20, 1800);  //Poti mappen auf 2 ... 180 Umdr/Min
    //min speed =2 and max speed =180 rpm
    tempo1 = vspeed;
    tempo = tempo1;
    if (millis() - Sekundenablauf01 >= Pausezeit01)  // 1000msec abgelaufen?
    {
      lcd.setCursor (0, 3);
      lcd.print (F("  VSPEED = "));
      lcd.setCursor (12, 3);
      lcd.print (F("     "));
      lcd.setCursor (12, 3);
      lcd.print (vspeed);
      Sekundenablauf01 = millis();
    }
    myStepperX.setSpeed( tempo );
    myStepperY.setSpeed( tempo );
    myStepperZ.setSpeed( tempo );
  }
  //----------------------------------------------------------------
  // Drehen Motor1 rechtsrum
  if (button.pressed(Button1) ) {
    //Taster1 gedrückt
    tempo = tempo1;
    myStepperX.rotate( 1 );          // Stepper1 dreht vorwärts
  }
  if ( button.released(Button1) ) {
    //Taster1 losgelassen
    myStepperX.rotate(0);             // Stepper1 stoppt
  }

  //Drehen Motor1 linksrum
  if (button.pressed(Button2) ) {
    //Taster2 gedrückt
    tempo = tempo1;
    myStepperX.rotate( -1 );         // Stepper1 dreht rückwärts
  }
  if ( button.released(Button2) ) {
    //Taster2 losgelassen
    myStepperX.rotate(0);    // Stepper1 stoppt
  }
  //-----------------------------------------------------------------
  // Drehen Motor2 rechtsrum
  if (button.pressed(Button3) ) {
    //Taster3 gedrückt
    tempo = tempo1;
    myStepperY.rotate( 1 );          // Stepper2 dreht vorwärts
  }
  if ( button.released(Button3) ) {
    //Taster3 losgelassen
    myStepperY.rotate(0);            // Stepper2 stoppt
  }

  //Drehen Motor2 linksrum
  if (button.pressed(Button4) ) {
    //Taster4 gedrückt
    tempo = tempo1;
    myStepperY.rotate( -1 );         // Stepper2 dreht rückwärts
  }
  if ( button.released(Button4) ) {
    //Taster4 losgelassen
    myStepperY.rotate(0);            // Stepper2 stoppt
  }
  //-----------------------------------------------------------------
  // Drehen Motor3 rechtsrum
  if (button.pressed(Button5) ) {
    //Taster5 gedrückt
    tempo = tempo1;
    myStepperZ.rotate( 1 );          // Stepper3 dreht vorwärts
  }
  if ( button.released(Button5) ) {
    //Taster5 losgelassen
    myStepperZ.rotate(0);             // Stepper3 stoppt
  }

  //Drehen Motor3 linksrum
  if (button.pressed(Button6) ) {
    //Taster6 gedrückt
    tempo = tempo1;
    myStepperZ.rotate( -1 );         // Stepper3 dreht rückwärts
  }
  if ( button.released(Button6) ) {
    //Taster6 losgelassen
    myStepperZ.rotate(0);            // Stepper3 stoppt
  }
  if (button.pressed(Button7) ) {
    //Taster7 gedrückt
    automatik = 1;                  // Automatik von SD Karte starten
  }
  if ( button.released(Button7) ) {
    //Taster7 losgelassen
  }
  if (button.pressed(Button8) ) {
    //Taster8 gedrückt
    automatik = 1;                  // Automatik von SD Karte starten
  }
  if ( button.released(Button8) ) {
    //Taster8 losgelassen
  }
  //-----------------------------------------------------------------

}
//=========================================================================================
void leseZeile()
{
  char myChar = '\0';
  static byte bufferPosition = 0;
  if (bufferPosition == 0) memset(zeilenBuffer, '\0', sizeof(zeilenBuffer));
  while (myFile.available() && myChar != '\n')
  {
    myChar = myFile.read();
    if (isPrintable(myChar))
    {
      zeilenBuffer[bufferPosition] = myChar;
      bufferPosition++;
    }
  }
  // Hier ist ZeilenEnde / DateiEnde
  bufferPosition = 0;
}
//=========================================================================================
void ausgabeZeile()
{
  Serial.print(F("eingelesene Zeile ist: "));
  Serial.println(zeilenBuffer);
}
//=========================================================================================
void teileZeile()
{
  // zeilenbuffer in auswerteBuffer umschreiben
  memset(auswerteBuffer, '\0', sizeof(auswerteBuffer) / sizeof(auswerteBuffer[0]));
  strcpy (auswerteBuffer[0], strtok(zeilenBuffer, ";"));
  strcpy (auswerteBuffer[1], strtok(NULL, ";"));
  strcpy (auswerteBuffer[2], strtok(NULL, ";"));
  strcpy (auswerteBuffer[3], strtok(NULL, ";"));
  strcpy (auswerteBuffer[4], strtok(NULL, ";"));
  strcpy (auswerteBuffer[5], strtok(NULL, ";"));
  //Serial.println(F("Puffer geteilt!"));
}
//========================================================================================
void ausgabeWerte()
{
  for (byte b = 0; b < sizeof(auswerteBuffer) / sizeof(auswerteBuffer[0]); b++)
  {
    //Serial.print(F("Wert "));
    //Serial.print(b);
    //Serial.print(F(" ist: "));
    //Serial.println(auswerteBuffer[b]);
    motor = atoi(auswerteBuffer[0]);
    fahren = atoi(auswerteBuffer[1]);
    richtung = atoi(auswerteBuffer[2]);
    tempo = atoi(auswerteBuffer[3]);
    myStepperX.setSpeed(tempo);
    myStepperY.setSpeed(tempo);
    myStepperZ.setSpeed(tempo);
    // schritte = atoi(auswerteBuffer[4]);
    Serial.println(schritte);
    mm = atoi(auswerteBuffer[5]);
    schritte = (mm / 25) * teiler;
    lcd.setCursor (0, 3);
    lcd.print("                  ");
    lcd.setCursor (0, 3);
    lcd.print(schritte);
    if (b == 0)
    {
      lcd.setCursor (0, 3);
      lcd.print(F("                    "));
      lcd.setCursor (0, 0);
      lcd.print(F("                    "));
      //----Display Motor1-------------
      if (motor == 1)
      {
        lcd.setCursor (1, 0);
        lcd.print("Mot X");
        lcd.print (F(" "));
        if (richtung == 1)
        {
          lcd.print(F(RECHTS));
        }
        if (richtung == 2)
        {
          lcd.print(F(LINKS));
        }
      }
      //----Display Motor2-------------
      if (motor == 2)
      {
        lcd.setCursor (1, 0);
        lcd.print("Mot Y");
        lcd.print (F(" "));
        if (richtung == 1)
        {
          lcd.print(F("v"));
        }
        if (richtung == 2)
        {
          lcd.print(F(OBEN));
        }
      }
      //----Display Motor3-------------
      if (motor == 3)
      {
        lcd.setCursor (1, 0);
        lcd.print("Mot Z");
        lcd.print (F(" "));
        if (richtung == 1)
        {
          lcd.print(F(OBEN));
        }
        if (richtung == 2)
        {
          lcd.print(F("v"));
        }
      }
      lcd.print (F(" "));
      lcd.print(mm);
      lcd.print("mm");
    }
    //-------------Motor 1 fahren------
    if (motor == 1)
    {
      if (richtung == 1)
      {
        myStepperX.doSteps(schritte);
      }
      if (richtung == 2)
      {
        myStepperX.doSteps(-schritte);
      }
      lcd.setCursor (0, 3);
      lcd.print("                  ");
      lcd.setCursor (0, 3);
      lcd.print(schritte);
      lcd.print("-");
      lcd.print(motor);
      motor = 0;
      richtung = 0;
      schritte = 0;
    }
    //-------------Motor 2 fahren------
    if (motor == 2)
    {
      if (richtung == 1)
      {
        myStepperY.doSteps(schritte);
      }
      if (richtung == 2)
      {
        myStepperY.doSteps(-schritte);
      }
      lcd.setCursor (0, 3);
      lcd.print("                  ");
      lcd.setCursor (0, 3);
      lcd.print(schritte);
      lcd.print("-");
      lcd.print(motor);
      motor = 0;
      richtung = 0;
      schritte = 0;
    }
    //------------Motor 3 fahren-------
    if (motor == 3)
    {
      if (richtung == 1)
      {
        myStepperZ.doSteps(schritte);
      }
      if (richtung == 2)
      {
        myStepperZ.doSteps(-schritte);
      }
      if (fahren == 0)
      {
        lcd.setCursor (0, 2);
        lcd.print(F(" --- BOHRSTOPP --- "));
      }

      motor = 0;
      richtung = 0;
      schritte = 0;
    }
  }//---------fahren ende-----------------
  while (myStepperX.moving() > 0) {}
  while (myStepperY.moving() > 0) {}
  while (myStepperZ.moving() > 0) {}
}

meine ich - kannst mal noch das File der SD-Karte ranhängen?

Ich baue gerade auf einem wo das laufen könnte.
Für mich sieht das so aus, als würde eine Variable neu beschrieben....

unsigned int schritte = 0;

Position 5: Schritte 1 - 250000

unsigned int geht von 0 bis 65535

schritte = (mm / 25) * teiler;

so macht man nicht mit "unsigned int"

 ..... sizeof(auswerteBuffer[0])
...
char auswerteBuffer[6][8];

Ich habe mich entschieden den code nicht zu analysieren weil mir die Namen nicht selbsterklärend genug sind.

Button1 bis 8 was macht button 1 ? usw.

AusgabeWerte was für Werte?

Man könnte functions erstellen
lcdPrintMotorX
lcdPrintMotorY
lcdPrintMotorZ
die dann jeweils die einzelnen Zeilen

        lcd.setCursor (1, 0);
        lcd.print("Mot Y");
        lcd.print (F(" "));
        if (richtung == 1)

enthalten

Das würde das Programm wesentlich übersichtlicher machen
und auch einfacher zu analysieren
vgs

http://excel.franz-koehler.de/Mappe1.csv

Ja, aber das erklärt eigentlich nicht warum es bei 16000 nicht klappt. Aber das war trotzdem das Problem. An das da oben in den deklarationen habe ich schon nicht mehr gedacht. Ich habe ihm jetzt mal "long" verpasst dann geht es. Und ich muss mit 132000 kommen. Das muss ja dann gehen.

Zeile 72 +

... man könnte...
Erstmal könnte das warnungsfrei kompilieren.

Ich bin noch nicht durch, aber...
mm ist ein float.
Wenn Du dem einen Wert zuweist aus der SD machst Du atoi. Das sollte atof werden.

Und ich bin bei Dir, noch zu suchen, warum es in eine Richtung geht und in die andere Richtung nicht.
Aber das wirklich schwer zu lesen...

my_xy_projekt

Hast du eigentlich auch einen Namen, dass man dich auch richtig ansprechen kann?
Es funktioniert jetzt (mit long schritte;) bis rauf auf 330mm 132000 schritte. Also alles gut. Nur die Rechung ist ja trotzdem eine komische Mischung, mit der ich nicht glücklich bin. Diese Mischung mit float und long Werte in einer Rechnung.

Stefan

Ja, das Programm möchte ich schon mal noch neu aufsetzen. Das aufteilen in Funktionen.

Aber erst mal würde mich interessieren, wie würde diese Rechnung korrekt aussehen. Also passende Deklarationen und die dazu passende Rechnung. Denn mit float und long deklarierte Werte so irgendwie zusammen würfeln und eine Zahl aus dieser Mischung dann aus dem Hut ziehen, das macht unsicher. Da weiß man nicht, ob es funktioniert, und warum :roll_eyes:

Ich kann ja die schritte nicht mit float deklarieren, long geht, aber mm ist nun mal eine Wert mit komma also ein float. Wie kriegt man das korrekt zusammen? Nicht nur dass es funktioniert?

Ok.

Du könntest Excel freundlich bitten dir Werte in Schritten bereit zu stellen, anstatt in mm.

Ja, das hatte ich vorher. Da gabs Probleme wenn die schritte größer 40000 waren. Da war die Übergabe der schritte - Werte von der SD dann ein Problem. Dann bin ich dem aus den Weg gegangen und habe doch selber am Arduino gerechnet.

Muss ich mir mal anschauen. Danke einstweilen. Ich bin mit den Werten auslesen noch nicht durch. Das Lernen kommt erst, wenn ich das am laufen habe. Dann habe ich Zeit das in die Birne zu bekommen.

Franz

Vielleicht auch mm als int und dann einen cast via float während der Rechnerei machen.
Das dürfte die elegantere Variante sein.

Und jetzt auch?
Auserdem, wenn Schritte sowieso auf zwei-drei Nullen enden, könnte man sie kürzen.
Ganz unbeachtet, dass eine Zahl hexadecimal geschrieben werden kann.

Mehr als tausendstel Millimeter Auflösung wird du wohl nicht benötigen.
Dann könnte man einfach das Komma um drei Stellen verschieben
also die mm * 1000 macht und dieses Zwischenergebis dann in einen long
speichert.

Hm - moment du machst doch als Umrechnung
/ 25 * 10000
Mal und geteilt ist doch von der Reihenfolge her egal. Zumindest in der wissenschaftlichen Mathematik

100 mm / 25 = 4
4 * 10000 = 40000 Schritte

10000 / 25 = 400
Warum dann nicht gleich einfach die mm * 400?

Wenn du die beiden Zahlen also die 25 unbedingt behalten willst
den float könnte man immer noch loswerden indem man mit zuerst 10.000 mal nimmt

100 mm * 10.000 = 1.000.000
und dann durch 25 teilt
1.000.000 / 25 = 40.000

Durch das vorziehen der Multiplikation mit 10.000 wird das Komma um vier Stellen verschoben.
Das bedeutet das Ergebnis wird genauso genau sein wie mit float.

Das heißt am Anfang eine Umrechnung float auf integer und dann reine Integerrechnung

Wenn ich das richtig verstanden habe dann liest du die Werte eh von SD-Karte ein.
Also zunächst mal ASCII-Code
Beispiel
437,89 mm
Sich beim einlesen Merken wo das Komma war. Das komma garnicht in den String übernehmen.
Trotzdem mitzählen wie viel Nachkommastellen
wurden eingelesen dann die passende Anzahl Nullen hinten an den String anhängen
Im Beispiel wäre das
String "4378900"
437,89 * 10000 = 4378900

Den String "4378900" dann eins zu eins in long umwandeln.
Wenn ich so etwas programmiere dann wird schon das für sich alleine

gründlichst

ausgetestet
eine Null einlesen was kommt als Long-Zahl heraus
-0 einlesen
-1 einlesen
1 einlesen
1,1
1,12
1,23
1,234
1,2345 (obwohl das blödsinn ist einen Zahlenwert mit so vielen Kommastellen anzugeben
trotzdem testen was passiert?
gleiches Spiel mit zweistellen, 3, 4, 5 stelligen Zahlen plus und negativ
Was passiert wenn da
+ 1234,567 eingelesen wird?

plus Leerzeichen zu große Zahl

und wenn das alles richtig eingelesen / Fehler abgefangen werden

erst dann

kommt die Weiterverarbeitung.

Das mag jetzt umständlich vorkommen. Man verschiebt die Zeit zur Fehlersuche nach vorne
und ist eh dabei es zu testen = man macht das Sonderfall testen geplant
anstatt ungeplant später im Gesamtprogramm zu suchen huch!! wo kommt jetzt das her??

vgs

2 Likes

OK, ich war vorher wohl etwas trüb auf der Platte. Jetzt bin ich nochmal drann, und da war es eigentlich klar.

Sagen wir mal es sind 30mm dann mache ich
"schritte = (mm*10000) / 25"
als 30 * 10000 = 300000 / 25 = 12000 Schritte
Oder mit 330mm, der weiteste weg, den ich an dem Tisch fahren kann.
330 * 10000 = 3300000 / 25 = 132000 Schritte.
Da kommt mir kein Komme in den Weg, alles gut. Und die Kiste bis an die mechanischen Grenzen.
Ein Schritt ist 0,0025mm.

Die eigentlich einfache Rechnung y = a * b / c; kann es in sich haben. Ein Beispiel:

//
//

void setup()
{
  Serial.begin(9600);
  Serial.println("\nStart");
  char buf[100] = {"\0"};
  uint32_t y = 0;
  
  int a = 30;
  int b = 10000;
  int c = 25;
  int d = b / c;
  y = a * b / c;
  snprintf(buf, sizeof(buf), "a * b / c \t\t= %10lu \t falsch, weil rechts vom Komma int im Zwischenergebnis überläuft", y);
  Serial.println(buf);
  y = a * d;
  snprintf(buf, sizeof(buf), "a * d \t\t\t= %10lu \t richtig", y);
  Serial.println(buf);
  y = 1UL * a * b / c;
  snprintf(buf, sizeof(buf), "1UL * a * b / c \t= %10lu \t richtig, weil rechts vom Komma auf unsigned long umgeschaltet wird", y);
  Serial.println(buf);
  s = -y;
  snprintf(buf, sizeof(buf), "s = -y; \t\t= %10ld \t richtig", s);
  Serial.println(buf);
}

void loop() {}

Anzeige UNO:

Start
a * b / c 		= 4294966189 	 falsch, weil rechts vom Komma int im Zwischenergebnis überläuft
a * d 			=      12000 	 richtig
1UL * a * b / c 	=      12000 	 richtig, weil rechts vom Komma auf unsigned long umgeschaltet wird
s = -y; 		=     -12000 	 richtig

Meine Einschätzung:

  1. Fließkomma ist auf 8-Bit-AVRs ungenau und auch schwer einzuschätzen, daher würde ich es möglichst vermeiden.
  2. Fließkomma auf Teensy 4.x (Float point math unit, 64 & 32 bits) wäre ein Versuch wert.
  3. Rechnungen mit Hundertstel Millimeter in uint32_t sollten doch genau genug sein, da braucht es kein Fließlomma.
  4. Ein 32-Bit-µC könnte auch problemlos mit 64 Bit rechnen, da muß man mit den Zwischenergebnissen nicht so aufpassen.