GCODE stream Zeile mit sscanf() richtig interpretieren.



  • Hallo C++ User.
    Ich bitte euch das hier mal durchzulesen und wenn jemand eine Idee dazu hat, mir bitte einen Lösungsansatz mitzuteilen. Ich bin leider nicht so vertraut mit der C/C++ Programmierung und benötige dringend Hilfe hierfür.
    Ich habe vor ca. 1 Jahr ein Programm geschrieben, wo GCODE Dateien eingelesen, ausgewertet und weiter berechnet werden. Diese werden dann über UART an einen Mikrocontroller gesendet der damit eine Stickmaschine steuert.
    Ich hatte dazu immer die GCODE-Datei geöffnet und mit

    fgets(OneLine, sizeof(OneLine), stream);
    

    eine Zeile aus der GCODE Datei ausgelesen und mit sscanf() dann folgendermaßen interpretiert:

    int ZahlLesen = sscanf(OneLine, "G0 X%ld.%ld Y%ld.%ld", &x_wert1, &x_wert2, &y_wert1, &y_wert2);
    

    x_wert1 bis y_wert2 sind INT-Variablen. In "x_wert1" befindet sich der Vorkommawert und in "x_wert2" der Nachkommawert. Das Selbe gilt auch für Y. Ich habe nach dem erfolgreichen Auslesen der Vor- und Nachkommastellen folgende Rechnung durchgeführt, um auf einen Ganzwert zu kommen:

    x_wert_neu = (x_wert1 * 1000) + x_wert2;
    y_wert_neu = (y_wert1 * 1000) + y_wert2;
    

    Das hat auch bis jetzt immer sehr gut funktioniert. Aber jetzt hat man bei der Sticksoftware die den GCODE erzeugt, die Ausgabe verändert. Früher waren es nur positive Werte und die Berechnung der Ganzzahl mit meiner Methode war kein Problem. Jetzt gibt es aber auch negative Werte in X und Y und ich habe versucht diese so zu erkennen:

    if (x_wert1 > 0)
    { x_wert_neu = (x_wert1 * 1000) + x_wert2;}
    if (x_wert1 < 0)
    {x_wert_neu = (x_wert1 * 1000) - x_wert2;}
    

    Das Ganze funktioniert auch sehr gut, NUR! bei einem Wert von -0,123 wird dann das Minus nicht mehr erkannt. Es gibt ja auch keinen Unterschied zwischen -0 und +0 in der Vorkommastelle! Die Nachkommastelle kann zur +/- Erkennung auch nicht mehr genutzt werden, denn die ist immer positiv. Dadurch ist es jetzt so, das alle Werte die -0,xxx sind als positive 0,xxx Werte gesehen werden und das Endergebnis natürlich um den 0-Wechsel herum nicht mehr passt. Alle anderen Werte ab -1.xxx passen dann wieder weil die -1 dann auch als negativer Wert erkennbar ist und dementsprechend verfahren werden kann.

    Mein Lösungsgedanke:
    Ich müßte die Möglichkeit haben, die gesamte Kommazahl mit +/- und Punkt in eine einzige Variable einzulesen und dann hätte ich auch die Möglichkeit diese als positiv oder negativ einzuordnen. Ich habe folgendes ausprobiert:

    int ZahlLesen = sscanf(OneLine, "G0 X%ld Y%ld", &x_wert1, &y_wert1);
      if (ZahlLesen == 2) //wenn 2 Werte erkannt wurden, sollte die Flieskommazahl in x_wert1 und y_wert1 sein.
       {
        if (x_wert1 > 0)
        { ...Abarbeitung für positive Zahlenwerte...}
        if (x_wert1 < 0)
        {...Abarbeitung für negative Zahlenwerte...}
       }
    

    Die Variablen "x_wert1" und "y_wert1" habe ich wegen der Fließkommazahl jetzt als "double" angelegt. Das Ganze funktioniert aber leider nicht. Das Erkennen der gesamten Kommazahl mit sscanf() scheint schon nicht richtig so zu funktionieren. Denn die Zeile:

    if (ZahlLesen == 2)
    

    erkennt keine 2 Ergebnisse und die "if" Anweisung wird niemals durchgeführt. Auch wenn ich die "if"-Anweisung komplett weglasse, sind keine Werte in den Variablen "x_wert1" und "y_wert1" Ich habe jetzt schon einiges anderes ausprobiert, habe aber leider keine Lösung wie ich die X und Y Werte des GCODE mit sscanf() als Ganzzahl bzw. Fließkommazahl innerhalb einer Variablen interpretieren kann.

    Hat jemand von den C/C++ Usern hier im Forum bitte eine Idee wie ich das machen kann, das ich positive und negative X Y - Werte aus einer Zeile einer GCODE-Datei mit sscanf() als Ganzzahl mit Vorzeichen und Komma in eine Variable eingelesen bekomme um diese dann auf positiven oder negativen Wert testen kann?


  • Mod

    Damit wir uns auch richtig verstehen: Da steht also so etwas wie "G0 -0.123 4.56"? Wieso dann nicht scanf("G0 %lf %lf", &xwert, &ywert) zum Einlesen der Zahlen ohne Rechnerei?

    (Unabhängig zu deinem konkreten Problem: Wenn man eine Zeile mit fgets liest, und diese dann in sscanf gibt, wollte man wahrscheinlich direkt fscanf nutzen.)

    PS: Du solltest dir auch sicher sein, welche Sprache du überhaupt nutzt. C und C++ haben nicht mehr viel gemeinsam und sollten nicht vermischt werden. Ich habe die Frage nach C geschoben, weil du derzeit C zu machen scheinst.



  • Hallo SeppJ.
    Sehr vielen Dank für deine so schnelle Antwort, die mir auch schon ein ganzes Stück weiter geholfen hat.

    @SeppJ sagte in GCODE stream Zeile mit sscanf() richtig interpretieren.:

    Damit wir uns auch richtig verstehen: Da steht also so etwas wie "G0 -0.123 4.56"?

    Ja genau so ist es. Eine Zeile sieht exakt so aus:
    G0 X-0.123 Y0.456 bzw. G0 X12.345 Y-22.654 oder G0 X-15.234 Y8.678
    und in der darauffolgenden Zeile der GCODE-Datei kommt immer die Angabe für Z
    G0 Z0.789 oder G0 Z-1.234 wobei der Wert für Z bei meiner Stickmaschine ignoriert werden kann.
    Ich erkenne nur das in der Zeile kein X und Y ist und somit muss es Z sein und die Nadel wird dann einmal gestochen, dann folgt in der nächsten Zeile wieder X-Y Angaben die von der Maschine ausgeführt werden usw. bis am Ende der GCODE Datei M30 als Stoppzeichen erkannt wird.

    Dein Vorschalg das Auslesen mit "%lf" zu machen scheint zu funktionieren. Ich konnte damit zumindest die Werte in die beiden Variablen "x_wert1" und "y_wert1" übergeben und die Abfrage:

    if (ZahlLesen == 2) 
    

    funktionert jetzt auch.
    In meinem Programm habe ich mit "Canvas" eine Simulationsdarstellung erstellt und darin werden mir auch die Verfahrwege bereits wieder angezeigt. Allerdings muss ich erst noch die Startposition bzw. 0-Koordinaten von Canvas anders bestimmen. Denn das angezeigte Stickbild liegt zum Teil jetzt außerhalb. Aber das bekomme ich schon hin...

    Das ist halt immer so ein Problem für einen "Versuchsprogrammierer" wie mich, der einmal im Jahr damit zu tun hat. Weil man erstens nicht die passenden Funktionen kennt, die man benutzen könnte, so wie dein Vorschlag mit fscanf, zum anderen auch keine Information darüber hat, wie man diese Funktionen richtig benutzen kann. So wie deine Idee das "%lf" zu verwenden.
    Ich hatte gestern noch im Netz nach sscanf gesucht und auch jede Menge Seiten gefunden. Aber mal so eine richtige Beschreibung was damit eigentlich alles Möglich ist und was all die %... die es da gibt überhaupt machen konnte ich leider nicht finden.
    Habe auch im Netz gesehen das es auch noch %s gibt, welches vermutlich für ASCII Strings sein könnte.

    Ich danke dir SeppJ recht freundlich für die Tolle Idee mit dem %lf welche bereits funktioniert. Den Rest hoffe ich mal, bekomme ich dann auch noch hin. Auch werde ich mir noch das fscanf anschauen um herauszufinden was der Unterschied zwischen sscanf und fscanf ist. Ich denke mal das f steht vielleicht für Float bzw. Fließkommazahl. Aber das werde ich sehen...
    Danke für die schnelle Hilfe und besten Gruß Eric.



  • @Eric
    sscanf parst einen string; Du liest ja in Deinem Programm erst mal eine Zeile in einen string ein:

    fgets(OneLine, sizeof(OneLine), stream);
    

    fscanf hingegen parst direkt das File ohne den Umweg über einen string ...
    aus:

    fgets(OneLine, sizeof(OneLine), stream);
    int ZahlLesen = sscanf(OneLine, "G0 X%ld.%ld Y%ld.%ld", &x_wert1, &x_wert2, &y_wert1, &y_wert2);
    

    wird also:

    int ZahlLesen = fscanf(stream, "G0 X%ld.%ld Y%ld.%ld", &x_wert1, &x_wert2, &y_wert1, &y_wert2);
    


  • @Eric sagte in GCODE stream Zeile mit sscanf() richtig interpretieren.:

    Aber mal so eine richtige Beschreibung was damit eigentlich alles Möglich ist und was all die %... die es da gibt überhaupt machen konnte ich leider nicht finden.


  • Mod

    Wie lernst du C? Das Format %f ist ziemlich grundlegend, ebenso die diversen f/s/(nix)-Versionen der Lesefunktionen. Und du wusstest auch nicht so recht, das C nicht C++ ist.

    Ich frage, weil du ein recht anspruchsvolles Projekt vor hast, aber da anscheinend Mängel bestehen, wie du die Sprache beigebracht bekommst. Deine Methode kann nicht grundverkehrt sein, da du keine Probleme mit Ablaufsteuerung zu haben scheinst, aber das macht es umso merkwürdiger, wo die anderen Lücken herkommen. Da kann und sollte man etwas verbessern.



  • @Swordfish

    Danke auch an Swordfish für die klassen Links. Letztendlich kommt man aber immer zu der Seite:CPPREFERENCE die ja wirklich sehr gut zu sein scheint. UND das Beste ist, es gibt diese Seite auch auf deutsch... 😃 deutsche Seite. Für diese Seite habe ich mir gleich mal den Link zu den Favoriten gelegt...

    Besten Dank auch an Belli, für die Darstellung wie man das mit fscanf richtig nutzen kann.

    Also, ich sehe dank eurer Hilfe jetzt erst einmal wieder Licht am Ende des Tunnels. Danke an alle für die super tolle schnelle Hilfe. 🙂



  • @Eric sagte in GCODE stream Zeile mit sscanf() richtig interpretieren.:

    es gibt diese Seite auch auf deutsch... deutsche Seite

    Ich empfehle dir dennoch, immer die englische Seite zu nutzen, sofern du genügend Englisch verstehst. Einerseits liest sich der maschinenübersetzte Text schlecht, andererseits fehlen z.B. in der hier verlinkten scanf*-Doku in der deutschen Übersetzungen die Beispiele!



  • @Eric sagte in GCODE stream Zeile mit sscanf() richtig interpretieren.:

    UND das Beste ist, es gibt diese Seite auch auf deutsch...


    This page has been machine-translated from the English version of the wiki using Google Translate.

    Gewöhn' Dich lieber an Englisch.



  • @SeppJ sagte in GCODE stream Zeile mit sscanf() richtig interpretieren.:

    Wie lernst du C?

    Leider hatte ich nie die Gelegenheit C so richtig von einem der es kann zu lernen. Habe mir alles selber erarbeiten müssen. Hatte mal so 1995 oder so in der Zeit damit angefangen. Arbeite deshalb auch noch mit Borland C++ Builder der Version 4.0. Ist sehr alt, aber funktioniert zum Glück noch immer... 😎

    Das Format %f ist ziemlich grundlegend, ebenso die diversen f/s/(nix)-Versionen der Lesefunktionen. Und du wusstest auch nicht so recht, das C nicht C++ ist.

    Ja das hast du wirklich gut erkannt. Es ist tatsächlich für mich nicht ganz einfach C von C++ zu unterscheiden. Für mich ist C++ die Erweiterung von C. Das es nicht ganz so ist, ist mir aber klar.

    Ich frage, weil du ein recht anspruchsvolles Projekt vor hast, aber da anscheinend Mängel bestehen, wie du die Sprache beigebracht bekommst.

    Ja, es war und es ist wirklich ein anspruchsvolles Programm und auch mein erstes dieser Größe. Außer ein paar kleinen Programmschnipseln die Werte über UART an einen Mikrocontroller übertragen, habe ich auch noch nicht mehr gemacht.

    Deine Methode kann nicht grundverkehrt sein, da du keine Probleme mit Ablaufsteuerung zu haben scheinst, aber das macht es umso merkwürdiger, wo die anderen Lücken herkommen. Da kann und sollte man etwas verbessern.

    Natürlich kann man immer etwas Verbessern. Aber das gelingt halt nur, wenn man Fachmänner zu Rate ziehen kann, die mir leider in meinem Privatfeld nicht zur Verfügung stehen. Aber auf der anderen Seite bin ich kein wirklicher Programmierer und das Stickmaschinenprogramm ist eigentlich mein erstes richtig großes Programm welches ich "programmiere". Wahrscheinlich auch mein letztes, wenn es die Zukunft nicht bringen sollte, das man doch wieder etwas besonderes auf PC Seite benötigt, was es so nicht gibt. Ich bin mir aber auch zu 100% sicher, wenn ich den gesamten Programmcode hier einstellen würde, findet man wahrscheinlich in jeder zweiten Zeile etwas, wo ein Fachmann die Hände über dem Kopf zusammen schlagen würde. Wie z.B. in der Reihenfolge solche Gesichtsausdrücke... 😟 😱 😫 😭

    Aber letztendlich... es funktioniert doch. 😇

    Das ich letztendlich doch etwas mehr über das Digitale weiß, liegt daran, das ich schon seit mehr als 30 Jahren mit Mikrocontrollern rum mache. Damals aber Assembler gelernt hatte, weil C für Mikrocontroller zu diesem Zeitpunkt noch nicht etabliert war und eine Programmierung für den PC nicht weiter von Nöten war... und auch ohne damit zu prahlen, aber in Assembler für Mikrocontroller bin ich König. 😎

    Also alles soweit gut. Werde mein Programm jetzt an das neue Format der GCODE-Datei anpassen und Dank eurer tollen Hilfe ist es für die weitere Verwendung in den nächsten Jahren hoffentlich auch weiterhin verwendbar.
    Nochmals vielen Danke für die Hilfe und besten Gruß Eric.



  • @Eric
    löst das Problem mit den auf 2 Zeilen verteilten zusammengehörenden Daten mit einem Aufruf:

    while( 3==fscanf(stream,"%*[^X]X%lf%*[^Y]Y%lf%*[^Z]Z%lf",&a,&b,&c) )
            printf("%f %f %f\n",a,b,c);
    

    fgets verwendet man, wenn es auf Zeilenumbrüche ankommt, was mit fscanf etwas schwieriger ist.

    @Eric

    fgets(OneLine, sizeof(OneLine), stream);

    Ist suboptimal, wenn OneLine ein Zeiger ist. (nein, Zeiger und Array sind nicht dasselbe)
    Besser ist die explizite Längenangabe:

    char z[1000];
    while(fgets(z,1000,stream))
    ...
    


  • @Belli sagte in GCODE stream Zeile mit sscanf() richtig interpretieren.:

    fscanf hingegen parst direkt das File ohne den Umweg über einen string ...
    aus:
    fgets(OneLine, sizeof(OneLine), stream);
    int ZahlLesen = sscanf(OneLine, "G0 X%ld.%ld Y%ld.%ld", &x_wert1, &x_wert2, &y_wert1, &y_wert2);

    G-Code besteht leider nicht nur aus G0 Zeilen. Man weiß nicht immer was da kommt. Daher ist für den Anfang das Zeilenweise lesen schon ok.
    Denn zwischen Zeile 1 und 2 kann noch mit dem String gearbeitet werden.


Log in to reply