Go Down

Topic: Spezieller Serialmonitor gesucht (Read 1 time) previous topic - next topic

fox00014

Feb 17, 2016, 08:15 am Last Edit: Feb 17, 2016, 08:20 am by fox00014
Guten morgen liebe Gemeinde.

Ich hab hier zwar schon viel gelesen aber jetzt bin  ich auch Offizielles Mitglied geworden denn ich brauch Eure Hilfe.

Zum Problem:

Ich schreibe momentan mit dem Arduino einen G-Codeinterpreter für meinen Eigenbau  3D-Drucker.
probeweise habe ich eine STL Datei in einen G-Code slicen lassen und diese Textdatei über den Seriallport gesendet.

mit einzelnen Zeilen funktioniert das Ganse soweit auch recht gut.

Schicke ich aber die komplette Datei mit 1,2 MB ASCII text legt sich die Sache nach ner weile auf die Nase.

Abgefragt wird im Programm zeilenweise. Das heißt:
Erstmal wird Serial eingelesen bis zu einem NL
dann wird sie Zeile zerlegt in befehl und Koordinaten.
dann wird der Verfahrweg berechnet und die Motoren angesteuert bis die entsprechenden Koordinaten erreicht sind.
dann wird die Nächste zeile eingelesen.

Ich Rate das das Problem darin besteht das der Serialmonitor bzw der Befehl "cat Helper.gcode >> /dev/ttyUSB0" Immer weiter sendet und im Ardoino ein recht kleiner SerialCash drinn ist der dann überläuft.

Meine frage ist nun:
Gibt es eine Möglichkeit die Serielle Schnittstelle so zu konfigurieren das die Übertragung angehalten wird sobald der Cash vom Arduino voll ist oder
Kennt von euch einen Serialmonitor der Textdateien Zeilenweise sendet und auf ein Steuerzeichen des Arduinos wartet bis er eine Neue Zeile sendet. z.B. wenn die verarbeitung mit dem Arduino Abgeschlossen ist lass ich ihn via Serial.println(); einfach ein NL an den PC senden. dieser reagiert darrauf mit dem senden der nächsten Textzeile???

oder hat jemand noch ne andere Idee???


Ich bin bestimmt nicht der Erste bzw. der Letzte mit dem Problem gabe aber nichts gefunden was annähernd mein Problem behandelt.


Serenifly

Quote
Kennt von euch einen Serialmonitor der Textdateien Zeilenweise sendet und auf ein Steuerzeichen des Arduinos wartet bis er eine Neue Zeile sendet. z.B. wenn die verarbeitung mit dem Arduino Abgeschlossen ist lass ich ihn via Serial.println(); einfach ein NL an den PC senden. dieser reagiert darrauf mit dem senden der nächsten Textzeile???
Was du beschreibst im Prinzip Software Handshaking mit XON/XOFF:
https://de.wikipedia.org/wiki/Datenflusssteuerung#Software-Flusssteuerung.2C_Software-Handshake.2C_Software-Protokoll_oder_X-ON.2FX-OFF


Ansonsten kannst du selbst ein Programm schreiben. z.B. in C#, Java, Python oder mit was auch immer du dich auskennst.

Whandall

Den Puffer den du, meinst bezeichnet man als Cache.

Im Gegensatz zu Bargeld, das im Englischen cash heisst.
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

fox00014

#3
Feb 18, 2016, 02:12 am Last Edit: Feb 18, 2016, 03:33 am by fox00014
Danke Serenify, Das wahr SEHR hilfreich!!!

aber so wirklich funktioniert das noch nicht. Ich bin nicht ganz so fit in Serial Kommunikation, um genau zu sein sind das meine ersten Gehversuche und ich bin mir unsicher ob ich den wikilink richtig verstanden habe.

Ich Poste den Protoype womit ich die Serialabfrage im Programm umgesetzt hab. der Ganze Code ist noch nicht fertig und hat mittlerweile über 600 Zeilen. ich glaub das würde den Ramen Sprengen.

Code: [Select]

String getline() {
  unsigned char c = 0;                         // Zählervariable
  char Zeichenkette[256];                      // Buffer CharArray für Eingelesene Zeile
  Serial.print((char)0x11);                    // DC1 X-ON
  for (c = 0; c != 255; c++) {                 // Zählerschleife zum Auslesen der Eingabezeile
    while (Serial.available() == '\0') {         // Solange kein Zeichen über Serial eingelesen wurde
      delay(1);                                    // Warte eine Millisecunde.
    };
    Zeichenkette[c] = Serial.read();             // Lese Ein Zeichen von der Serialen Schnittstelle
    if ((Zeichenkette[c] == 13) || (Zeichenkette[c] == '\n') || (Zeichenkette[c] == '\r')) {  // Wenn das Ausgelesene zeichen ein Return oder Newline ist dann
      Zeichenkette[c] = '\0';                      // Setze Nullbyte 
      break;                                       // Dann breche zählerschleife ab.
    };
  };
  Serial.print((char)0x13);                    // DC3 X-OFF
  Zeichenkette[c] = '\0';                      // Überschreibe letztes Zeichen mit Nullbyte und defeniere Stringende
  String Buffer = Zeichenkette;                // Überspiele den CharArray mit der Ausgelesenen Zeile in ein Sring
  Buffer.trim();                               // Schneide alle überflüssigen Lerzeichen raus
  return Buffer;                               // Liefere den Sring als wertigkeit im Befel getline();
};



der Buffer läuft anscheinend immer noch über...

Verwendet wird das Programm CuteCom.
Handschake ist auf Software eingestellt.
Die Steuerzeichen tauchen auch nicht in dem Communikationsfenster auf. Also sollten sie teoretisch  interpretiert werden.
(Nichtaskizeichen werden im "/0xFF" Format Dargestellt.)
Allerdings tauchen Halbe und abgeschnittene Zeilen auf.

Kann mir Jemand helfen???

Serenifly

#4
Feb 18, 2016, 10:33 am Last Edit: Feb 19, 2016, 04:45 pm by Serenifly
Sorry, aber das ist Schrott. Unübersichtlich, unlogisch, blockierend und verschwenderisch.

Hier ist grundlegender Code wie man eine Zeile in ein char Array einliest. Ohne Fluss-Steuerung:

Code: [Select]

const int SERIAL_BUFFER_SIZE = 60;
char serialBuffer[SERIAL_BUFFER_SIZE];

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if (readSerial(Serial))
  {
    Serial.print("Read: "); Serial.println(serialBuffer);
  }

}

bool readSerial(Stream& stream)
{
  static byte index;

  while (stream.available())
  {
    char c = stream.read();

    if (c >= 32 && index < SERIAL_BUFFER_SIZE - 1)
    {
      serialBuffer[index++] = c;
    }
    else if (c == '\n' && index > 0)
    {
      serialBuffer[index] = '\0';
      index = 0;
      return true;
    }
  }
  return false;
}


Das liest erst mal nur eine Zeile ein und gibt sie aus.

Das Prinzip ist einfach: readSerial() wird ständig aufgerufen und schaut nach oben Daten da sind. Wenn nicht kehrt die Funktion gleich zurück. Wenn was da ist wird es eingelesen und nachgeschaut was es ist. Wenn es das Endzeichen ist wird der String terminiert und die Funktion gibt true zurück. Wenn es ein anderes Zeichen ist wird es abgespeichert falls noch Platz im Array ist. Die Funktion gibt false zurück wenn das Ende noch nicht erreicht ist.
Man fragt also auf den Rückgabewert ab und wenn er true ist hat man eine Zeile. In der Zwischenzeit kann man dann noch andere Dinge tun.

Du würdest das dann so machen:
Code: [Select]

  if (readSerial(Serial))
  {
    Serial.write(0x13);
 
    //Auswertung

    Serial.write(0x11);
  }


Nach dem Block wird dann automatisch wieder readSerial() ständig aufgerufen und geht weiter



Lerne außerdem wie man direkt mit C Strings arbeitet. Da gibt es massig Funktionen um Strings zu splitten und in Integer zu konvertieren. Oder nach Zeichen und Teil-Strings zu suchen. Das alles speicherschonend und in situ.
Wenn es wirklich unbedingt die Arduino String Klasse sein muss, dann verwende sie wenigstens korrekt. Erstelle ein Objekt und reserviere mit reserve() Speicher. Dann ist es auch nicht so schlimm wenn man jedes Zeichen mit + anhängt, wobei man auch bei der String Klasse auf jeden Index direkt zugreifen kann.

Aber erstelle nicht ein char Array und kopiere das in ein String Objekt. Das ist völlig unnötig und verschwendet nur Speicher. Gerade bei so großen Arrays. Auf String Objekte kann man wie gesagt aber komplett verzichten. Das geht alles direkt mit null-terminierten char Arrays.

fox00014

Mojens. Ersmal nochmal nen dickes Danke,

in gcc hatte ich den G-Code-Converter damals schon halb fertig. Wollte damals die Schrittmotorsteuerung über die LPT lösen was sich aus ättlichen Problemen auf die Nase gelegt hat.

Kurts um, ich bin dann vor die Wand gerannt das die verwendeten Bibliotheken nicht im Arduinopaket mit drin sind und sie nicht inklodiert werden konnten. Also hab ich mich darann gemacht und hab die Strings in Arryas zerlegt und die entsprechend verwurstet hab.

Das ich hier nen Array dreckt als String zurück geben kann war mir neu. Bin davon ausgegangen das ich erst die Variablen konvertieren muss.

Hab's umgebastelt und noch weitere Funktionen direkt eingebaut um das zuschnippeln aufs wesentliche direkt abzuarbeiten.

Kurze Erläuterungen zu G-Code;
Mit Semikolon werden Kommentare in G-Code definiert, (das heißt, alles was ab einem ";"  kommt ist für den Programmablauf Überflüssig)
Lehrzeichen sind nur zur Menschlichen Lesbarkeit im G-Code, (Werden also beim Auslesen ignoriert)
Eine Zeile Besteht aus einem Befehl und eventuell Koordinaten. (Typische Zeile währe G1 X100.305213 Y100; Kommentar);
Groß und Kleinschreibung sollte ignoriert werden.

was hälst du von dem Folgendem Code zum auslesen einer Anweisungszeile???
Code: [Select]
void setup()
{
  Serial.begin(9600);
}

void loop()
{
  String Line = getorder(Serial);
  if (Line != '\0')
  {
    Serial.print("Read: "); Serial.println(Line);
  }
//  Serial.print("#");
}

String getorder(Stream& stream)
{
  static byte index = 0;                                       // Statische Zählervariable für die Zeileposition mit 0 anlegen
  const byte BUFFER_SIZE = 255;                                // Größe des Arryas in einer variabele festlegen
  char Buffer[BUFFER_SIZE];                                    // Arrya für inhalt der Befelsleiste angeben
  char Zeichen ='\0';                                          // Zeichenvariabele Leer anlegen
  static boolean Kommi;                                        // Remanenter Blockiermerker

  Serial.print((char)0x11);                                    // DC1 X-ON
  while (stream.available())                                   // Solange noch ein Zeichen im SerialCache
  {
    Zeichen = stream.read();                                   // Lese das Nächste Zeichen ein
    if (index == 0) { Kommi = false; };                        // Feststellen ob ein Kommentar anfängt und Blokiermerker setzen
    if (isLowerCase(Zeichen)) { Zeichen = Zeichen - 32; };     // Aus Kleinbuchstaben Großbuchstaben machen 
    if (isGraph(Zeichen) && index < BUFFER_SIZE - 1)           // Ist das eingelesene Zeichen Druckbar und der Buffer nicht übergelaufen
    {
      if (Kommi == false) { Buffer[index++] = Zeichen; };      // Wenn noch nicht ein Kommentar gefunden wurde Übertrag das Zeichen in den Buffer und Zähl eins hoch
    }
    else if ((Zeichen == '\n' || Zeichen == '\r') && index > 0)// ist das zeichen nicht Druckbar und [( wird Newline oder Return erkannt) und es ist mindestens das 2. zeichen]
    {
      Buffer[index] = '\0';                                    // Dann setze Nullbyte als Stringende
      index = 0;                                               // Und setze Zähler auf 0
      Serial.print((char)0x13);                                // DC3 X-OFF
      return Buffer;                                           // und gebe die ausgewertete Zeile zurück
    };
    if (Zeichen == ';') { Kommi = true; };                     // Wird das Zeichen für Kommentar erkannt setze den Blockiermerker
  };
  return (String)'\0';                                         // Sind keine Zeichen im SerialCache dann Gebe NullByte zurück
};



Der Test mit meiner Beispiel-G-Codedatei läuft gerade.

Whandall

was hälst du von dem Folgendem Code zum auslesen einer Anweisungszeile???
Überhaupt nichts.

- es werden Strings benutzt -> späterer Crash vorprogrammiert

- die Routine funktioniert nur, wenn die gesamte Zeile bereits empfangen ist,
 oder während ihrer Laufzeit vollständig wird, das ist regelmäßig nicht der Fall

- die Rückgabe der Adresse eines lokalen Puffers geht selten gut,
 ob der implizite Cast zum String dies Problem umgeht will ich überhaupt nicht testen.

Code: [Select]
const byte XOFF = 0x13;
//Serial.print((char)0x13);
Serial.write(XOFF);
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

Serenifly

#7
Feb 19, 2016, 04:43 pm Last Edit: Feb 19, 2016, 05:30 pm by Serenifly
Quote
Kurts um, ich bin dann vor die Wand gerannt das die verwendeten Bibliotheken nicht im Arduinopaket mit drin sind und sie nicht inklodiert werden konnten. Also hab ich mich darann gemacht und hab die Strings in Arryas zerlegt und die entsprechend verwurstet hab.
Was du hast ist die AVR libc:
http://www.nongnu.org/avr-libc/user-manual/modules.html

Das sind größtenteils Standard C Funktionen mit ein paar GNU Erweiterungen. Hier sind besonders die zwei wichtig:
http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html

In stdlib.h sind Konvertierungs-Funktionen nach Integer und Float und umgekehrt

Inkludieren musst du die nicht. Die sind schon mit der Arduino Software drin



Ich würde dir auch raten dich was die Rückgabe-Werte betrifft an meinen Code zu halten

Wenn du was gegen globale Variablen hast, dann mach es so:
Code: [Select]

char* getorder(Stream& stream)
{
  static char buffer[BUFFER_SIZE];     //muss static sein!!

 

  return NULL;         //NULL zurückgeben wenn noch nicht fertig
}

Und return buffer; wenn fertig

Und dann auf NULL abfragen
Code: [Select]

char* buffer =  getorder(Serial);

if (buffer != NULL)
{
}

Also wenn der Rückgabe-Wert ungleich Null ist man fertig.

Das Puffer muss dann aber unbedingt static sein, da du keine Zeiger auf lokale, nicht-statische Variablen zurückgegeben kannst.

Wenn du dann ein String Objekt willst, kannst du das immer noch an der Stelle kopieren. Aber dazu eine Warnung: Das ist eben eine Kopie! Du hast einen 256 Byte Puffer. Mit dem Objekt sind dann zumindest kurzzeitig 500 Bytes belegt. Ich nehme an, du hast vielleicht einen Mega. Dann wäre das wahrscheinlich nicht so schlimm. Aber auf kleineren Prozessoren sollte man das nicht tun.


Quote
Groß und Kleinschreibung sollte ignoriert werden.
Wenn du willst kannst du das auch noch später in einem Rutsch konvertieren. Da gibt es strlwr() (string lower) dazu:
http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html#ga119342b34031ba4ee28f4e38a22c5f0d
Oder strupr() für Großbuchstaben

Du kannst es aber auch beim Einlesen machen. Geschmackssache



@Whandall
Quote
die Rückgabe der Adresse eines lokalen Puffers geht selten gut,
 ob der implizite Cast zum String dies Problem umgeht will ich überhaupt nicht testen.
Er gibt keine Adresse zurück. Sondern ein Objekt. Welchen der Compiler dank return value optimiziation sogar wegoptimieren kann. Eine gute Idee ist das aber trotzdem nicht.

Übrigens will er indirekt Zeichen von einer SD-Karte lesen. Das heißt es sollte irgendwann man ein CR/LF ankommen, auch wenn zwischendurch Zeichen verloren gehen.
Die Ausnahme ist vielleicht am Ende, wenn die letzte Zeile nicht richtig ankommt. Es wäre aber auch kein Problem hier zusätzlich ein Timeout einzubauen und das Einlesen abzubrechen wenn eine gewisse Zeit lang nichts ankommt.

fox00014

Also, ich binn grad dabei eure Vorschläge umzusetzen und nachzulesen.

In der Theorie wollt ich alles mit String umsetzen grade wegen der Speicherbelastung. String gegenüber char Array hat den vorteil das man sich nicht darum scheren muss ob man in einen nicht definierten Speicherbereich schreibt und der String verbraucht im Speicher immer nur soviel wie auch drin steht. Und muss nicht dauerhaft 255 Zeichen haben um sicher zu stellen das auch Mörderkommentare nicht das einlesen von "new line" verhindert...
Daher auch die Idee die Kommentare beim einlesen gleich zu identifizieren und das schreiben in die char Array dabei sofort zu unterbinden und die Lehrzeichen rauszuwerfen.

Auf der anderen Seite hab ich auch ein wenig Angst davor Bibliotheken zu inklodieren da diese das Programm aufpumpt da ja alle dort enthaltenen Prototypen mit Komeliert werden.
Zudem hab ich hir mal irgendwo gelesen das String nicht string ist. Soll heißen das der String Arduino nicht das gleiche wie string c++ sein soll sondern irgendwie ne abgespeckte Version ist oder so. Genau hab ich es damals nicht gelesen da ich eigentlich was anderes gesucht hatte und nur durch Zufall drauf gestoßen bin.

Zu den Früchten eurer Arbeit bis jetzt:

Im bereich Serialkommunikation scheint das ersetzen von Serial.prit((char)0x13); durch Serial.write(0x13); für XOFF des Rätzels Lösung gewesen zu sein. ich teste aber noch. Warum  das so ist hab ich allerdings noch nicht verstanden. Das heist doch nicht ohne Grund SteuerZEICHEN???

Was ich oben vergessen hatte zu erwähnen ist das "new line" bzw "Return" in G-Code die Befehlszeile beendet.
das Semikolon wird dort verwirrender weise als Satzende bezeichnet. aber sowas wie (G91; G30 X0 Y0 Z0; Nullpunkt fahrt\n) geht nicht.
das wird dann (G30G91 X0 Y0 Z0; Nullpunkt fahrt\n) geschrieben.
Also ist "New Line" unbedingt ervorderlich.
G-Code ist auch nicht wirklich eine Programiersprache. eher sowas in die Richtung html. beschreibt was zu tuen ist.

ich Poste hier mal ne kleine Brocke von ner G-Codedatei zum besseren Verständnis wie son ding aufgebaut ist.
Code: [Select]

; diese datei hat 41346 Zeilen
; generated by Slic3r 1.0.0RC2 on 2014-03-16 at 00:48:36

; layer_height = 0.4
; perimeters = 3
; top_solid_layers = 3
; bottom_solid_layers = 3
; fill_density = 0.4
; perimeter_speed = 30
; infill_speed = 60
; travel_speed = 130
; nozzle_diameter = 0.5
; filament_diameter = 3
; extrusion_multiplier = 1
; perimeters extrusion width = 0.50mm
; infill extrusion width = 0.53mm
; solid infill extrusion width = 0.53mm
; top infill extrusion width = 0.53mm
; first layer extrusion width = 0.70mm

G21 ; set units to millimeters
M107
M104 S200 ; set temperature
G28 ; home all axes
G1 Z5 F5000 ; lift nozzle

M109 S200 ; wait for temperature to be reached
G90 ; use absolute coordinates
G92 E0
M82 ; use absolute distances for extrusion
G1 F1800.000 E-1.00000
G92 E0
;G92 E0
G1 Z0.350 F7800.000
G1 X86.978 Y85.612 F7800.000
G1 E1.00000 F1800.000
G1 X87.569 Y85.122 E1.02495 F540.000
G1 X89.728 Y83.562 E1.11164
G1 X90.309 Y83.192 E1.13402
G1 X90.928 Y82.882 E1.15658
G1 X93.359 Y81.802 E1.24309
G1 X93.999 Y81.552 E1.26545
G1 X94.659 Y81.372 E1.28771
G1 X97.258 Y80.812 E1.37424
G1 X97.959 Y80.702 E1.39729
G1 X98.659 Y80.662 E1.42010
G1 X101.329 Y80.662 E1.50697
G1 X102.029 Y80.702 E1.52978
G1 X102.728 Y80.812 E1.55284
G1 X105.329 Y81.372 E1.63937
G1 X105.989 Y81.552 E1.66163
G1 X106.619 Y81.792 E1.68356
G1 X109.059 Y82.872 E1.77038
G1 X109.689 Y83.192 E1.79337
G1 X110.279 Y83.572 E1.81620
U.S.W.

Serenifly

String gegenüber char Array hat den vorteil das man sich nicht darum scheren muss ob man in einen nicht definierten Speicherbereich schreibt
Wird beim Einlesen hier berücksichtigt
Code: [Select]

 if (index < SERIAL_BUFFER_SIZE - 1)

- 1 damit noch Platz für den Terminator ist

Quote
und der String verbraucht im Speicher immer nur soviel wie auch drin steht.
Beim ursprünglichen Einlesen ja. Wobei es auch bei Strings nicht verkehrt ist reserve() zu machen, damit nicht ständig realloc() ausgeführt wird wenn man den String größer machen muss.

Aber es wird u.a. ein neues Objekt erstellt wenn du Dinge wie substring() machst. C Strings kann man dagegen in situ bearbeiten! Eine Such-Funktion liefert einfach einen Zeiger im bestehenden String zurück.

Quote
Daher auch die Idee die Kommentare beim einlesen gleich zu identifizieren und das schreiben in die char Array dabei sofort zu unterbinden und die Lehrzeichen rauszuwerfen.
Kommentare gleich zu entfernen ist sicherlich eine sehr gute Idee.

Das mit den Leerzeichen würde ich mir aber überlegen. Die könnte man nämlich beim Splitten des Strings sehr schön als Delimiter verwenden :)
strtok() mit dem Leerzeichen machen und dann die Teil-Strings analysieren

Quote
Im bereich Serialkommunikation scheint das ersetzen von Serial.prit((char)0x13); durch Serial.write(0x13); für XOFF des Rätzels Lösung gewesen zu sein. ich teste aber noch. Warum  das so ist hab ich allerdings noch nicht verstanden. Das heist doch nicht ohne Grund SteuerZEICHEN??
Ich dachte eigentlich auch dass es letztlich das Gleiche tun sollte.

Quote
Auf der anderen Seite hab ich auch ein wenig Angst davor Bibliotheken zu inklodieren da diese das Programm aufpumpt da ja alle dort enthaltenen Prototypen mit Komeliert werden.
Es werden nur die Funktionen kompiliert die auch verwendet werden. Man holt sich am Anfang recht viel rein, aber nicht alles. Aber generell frisst die String Klasse schon mehr Speicher und ist viel langsamer.

Quote
Zudem hab ich hir mal irgendwo gelesen das String nicht string ist. Soll heißen das der String Arduino nicht das gleiche wie string c++ sein soll sondern irgendwie ne abgespeckte Version ist oder so.
Die Arduino String Klasse ist eine Art Wrapper für einen Teil AVR lib c Funktionen. Ein Problem ist dass man nicht viel damit machen kann. Gerade an Konvertierungs- und Formatierungs-Funktionen mangelt es deutlich.

Und sowas wie strtok() gibt es auch nicht. Es gab mal split(), aber das war auch nicht so toll, das es ein Array aus neuen String Objekten geliefert hat. Auf einem PC ist das kein Problem. Aber auf einem µC frisst das einfach viel Speicher. Vielleicht wurde es deshalb entfernt. kA.

Whandall

In der Theorie wollt ich alles mit String umsetzen grade wegen der Speicherbelastung. String gegenüber char Array hat den vorteil das man sich nicht darum scheren muss ob man in einen nicht definierten Speicherbereich schreibt und der String verbraucht im Speicher immer nur soviel wie auch drin steht. Und muss nicht dauerhaft 255 Zeichen haben um sicher zu stellen das auch Mörderkommentare nicht das einlesen von "new line" verhindert...
Einen Puffer maximaler Größe dauerhaft zur Verfügung zu stellen, ist in deinem Fall ganz sicher sinnvoll, da das Programm ja die ganze Zeit zeilenweise das Script abarbeitet. Wo die Daten herkommen ist ja erst einmal nebensächlich. Die Hoffnung jederzeit einen String von 255 Zeichen dynamisch anlegen zu können ist sehr optimistisch. Bei Programmen würde ich mich auch weniger auf Hoffnung verlassen wollen.

Strings und strings sind natürlich nicht das Gleiche. Strings sind eine C++ Abstraktion von strings, die in beiden Varianten letztlich die Daten beinhalten. Wegen der geringen Menge an Speicher (2/8/16k) in die alle statischen Variablen, der Stack, alle gleichzeitig aktiven lokalen Variablen und noch etwas Platz für Interrupts passen müssen, sollte man diesen Platz sehr kontrolliert verwenden.

Im bereich Serialkommunikation scheint das ersetzen von Serial.prit((char)0x13); durch Serial.write(0x13); für XOFF des Rätzels Lösung gewesen zu sein. ich teste aber noch. Warum  das so ist hab ich allerdings noch nicht verstanden. Das heist doch nicht ohne Grund SteuerZEICHEN???
Serial.print(0x13) druckt '1' und '9' (den Wert als Zahl in dezimaler Darstellung)
Serial.write(0x13) druckt ein einzelnes Zeichen mit dem Wert 19 bzw. 0x13 (ein Zeichen mit dem Wert)
Deshalb geht das mit dem Steuerzeichen besser.
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

Serenifly

#11
Feb 20, 2016, 02:24 am Last Edit: Feb 20, 2016, 02:42 am by Serenifly
Hier mal ein sehr grobes Beispiel wie man das einfach machen könnte:

Code: [Select]

char str[] = "G1 X90.928 Y82.882 E1.15658";

void setup()
{
  Serial.begin(9600);

  splitString(str);
}

void loop()
{
}

void splitString(char* str)
{
  char* ptr = strtok(str, " ");

  while (ptr != NULL)
  {
    analyzeToken(ptr);
    ptr = strtok(NULL, " ");
  }
}

void analyzeToken(char* str)
{
  if (strcmp(str, "G1") == 0)
  {
    Serial.println(F("Vorlauf"));
  }
  else
  {
    switch (str[0])
    {
      case 'X':
        Serial.print(F("X: "));
        Serial.println(atof(str + 1), 3);
        break;
      case 'Y':
        Serial.print(F("Y: "));
        Serial.println(atof(str + 1), 3);
        break;
      case 'E':
        Serial.print(F("E: "));
        Serial.println(atof(str + 1), 5);
        break;
    }
  }
}



Wie gesagt nur grob. Letztlich muss man hier ja mehrere Varianten unterscheiden:
Code: [Select]

G1 Z0.350 F7800.000
G1 X86.978 Y85.612 F7800.000
G1 E1.00000 F1800.000
G1 X87.569 Y85.122 E1.02495 F540.000
G1 X89.728 Y83.562 E1.11164

Alles G1 aber mit verschiedenen Parametern

Wirklich beschäftigt habe ich mich dem Thema G Code aber nicht. rudirabbit hat glaube ich einen G Code Parser geschrieben. Mir geht es eher eher um die Verwendung von C Strings. Einfacher wird das mit der String Klasse sicherlich nicht


Eine Option ist es den Parser als Zustands-Automaten auszuführen. So dass man wenn der erste Parameter nach G1 mit 'Z' anfängt in einem anderen Zustand ist als wenn ein 'X' oder 'E' kommt. Dann weiß man auch welche Teil-Strings danach zu erwarten sind. Das ist wahrscheinlich das Vernünftigste.

fox00014

#12
Feb 20, 2016, 03:24 am Last Edit: Feb 20, 2016, 03:33 am by fox00014
Befor ich es Vergessen. Jain: G1 ist am häufigsten verwendet.
G1 = Liniere Symmetrische Bewegung.
G0 = Schnellstmögliche Bewegung ohne Symmetrie.
G28 = Nullpunktfahrt
usw.

Gelöst ist es bei mir das ich erst nach G oder M suche.
G = Befehl
M = MaschienenMackro wie Werkzeugwechsel Temeratur setzen und warten bis temp. erreicht ist usw.

Danach wir Nach XYZES gesucht und die Passenden Variablen gesetzt.
zusammen wird das dann an den passenden Prototype für G1 G0 ... Übergeben.

Der berechnet dann und steuert die Motoren an.
--------------------------------------------------------------------------------

Uff. Also erstmal das Ergebnis des ersten Testes.

Code: [Select]
Read: G1X84.995Y106.804F7800.0
Read: G1X85.956Y100.782F7800.0
Read: G1X85.Y101.038E16.63409F2443.9621X85.019Y101.271E16.660561X84.848Y101.909E16.67998
Read: G1X85.102Y103.558E16.72906
Read: G1X85.189Y103.646E16.73270
Read: G116.73573
Read: G1X86.396Y103.592E.77227
Read: G1X85.691Y103.780E169372
Read: G1X85.Y104.653E16.82028
Read: G1X87.24Y106.007E16.88626
Read: G1X87.23Y106.057E16.88778
Read: G1X86.4Y106.290E16.91424
Read: G1X86.Y106.719E16.92731
Read: G1X87.39Y108.704E16.99469
Read: G1X87.90Y108.567E17.01025
Read: G1X88.Y107.598E17.03974
Read: G1X88.5Y108.235E17.06135
Read: G1X88.40108.701E17.07555
Read: G1X89.04Y109.338E17.10202
Read: G1X88.7Y110.350E17.13283
Read: G1X89.6Y109.455E17.16884
Read: G1X89.5Y109.472E17.17077
Read: G1X89.1Y110.810E17.21150
Read: G1X90.43Y111.924E17.26068
Read: G1X91.0Y111.749E17.28055
Read: G1X91.2Y111.030E17.30244
Read: G1X91.73111.357E17.31881
Read: G1X91.59111.883E17.33484
Read: G1X92.22112.520E17.36131
Read: G1X92.06113.110E17.37928
Read: G1X92.53Y113.388E17.39517
Read: G1X92.7112.654E17.41752
Read: G1X93.44Y112.461E17.43946
Read: G1X94.45112.907E17.47171
Read: G1X94.7Y113.192E17.48356
Read: G1X94.45114.244E17.51559
Read: G1X94.93114.458E17.53106
Read: G1X95.23113.327E17.56551
Read: G1X95.33113.301E17.56848
Read: G1X97.13Y113.752F7800.000
Read: G1X97.2Y113.865E17.57319F2443.91X96.951Y114.962E17.606581X97.460Y115.070E17.62189
Read: G1X97.747Y113.999E17.65448
Read: G1X97.989Y113.935E17.66184
Read: G17800.000
Read: G1X99.755Y114.537E.68218F2443.962
Read: G1X99.559Y1.269E17.704X100.097Y115.269E17.72027
Read: G1X100.257Y114.672E17.73845
Read: G1X101.126Y114.439E17.76491
Read: G1X101.231Y114.048E17.77679
Read: G1X102.198Y115.143E17.81973


Wie ihr seht haut etwas bei der Datenübertragung nicht hin. Teile des Textes verschwinden einfach. Interessanter weise gibt es weniger Crashs bei geringerer Datenübertragungsrate. Könnt nen Bufferproblem sein was heißen würde das die Handshake Geschichte nicht funktioniert.
Oder es ist ein Problem mit dem Timing des Serial Signals wo ich jetzt echt nicht wüsste was ich da noch machen könnte.
Eventuell kommt es auch PC seitig her. vom Programm CuteCom, vom Betribsystem SuSE Linux, vom Serial Treiber.
Ich werde erstmal den Handshake testen. Nach dem XOFF Signal bau ich nen delay(3000); ein oder so um optisch an den LED's auf dem Board sehen zu können ob das überhaupt funktioniert.

Mensch meier, ich will doch nur ne ASCII Datei an den Arduino schiken. Dat kann doch nit so schwer sein.... Dachte ich.... Denken is wohl glücksache.

Eure Artikel hab ich übrigens schon überflogen und bin wirklich von eurer Hilfsbereitschaft und den Informationen begeistert.
Danke, So fängt es wieder an spaß zu machen.

Ich füge die oben genannte bremse rein und füttere den Arduino wieder. in der Zeit wie das läuft Schau ich mir eure Ausführungen genau an.

fox00014

Kurtsfassung.  Der Software Handshake funktioniert nicht...

aktuelles Programm sieht noch so aus:
Code: [Select]
void setup()
{
  Serial.begin(9600);
}

void loop()
{
  String Line = getorder(Serial);
  if (Line != NULL)
  {
    Serial.print("Read: "); Serial.println(Line);
  }
//  Serial.print("#");
}

char* getorder(Stream& stream)
{
  const byte XOFF = 0x13;
  const byte XON = 0x11;
  static byte index = 0;                                       // Statische Zählervariable für die Zeileposition mit 0 anlegen
  static const byte BUFFER_SIZE = 255;                                // Größe des Arryas in einer variabele festlegen
  char Buffer[BUFFER_SIZE];                                    // Arrya für inhalt der Befelsleiste angeben
  char Zeichen ='\0';                                          // Zeichenvariabele Leer anlegen
  static boolean Kommi;                                        // Remanenter Blockiermerker

  if (stream.available() == false) stream.write(XON);          // Ist der SerialBuffer Leer dann sende DC1 X-ON
  while (stream.available())                                   // Solange noch ein Zeichen im SerialCache
  {
    Zeichen = stream.read();                                   // Lese das Nächste Zeichen ein
    if (index == 0) { Kommi = false; };                        // Feststellen ob ein Kommentar anfängt und Blokiermerker setzen
    if (isLowerCase(Zeichen)) { Zeichen = Zeichen - 32; };     // Aus Kleinbuchstaben Großbuchstaben machen 
    if (isGraph(Zeichen) && index < BUFFER_SIZE - 1)           // Ist das eingelesene Zeichen Druckbar und der Buffer nicht übergelaufen
    {
      if (Kommi == false) { Buffer[index++] = Zeichen; };      // Wenn noch nicht ein Kommentar gefunden wurde Übertrag das Zeichen in den Buffer und Zähl eins hoch
    }
    else if ((Zeichen == '\n' || Zeichen == '\r') && index > 0)// ist das zeichen nicht Druckbar und [( wird Newline oder Return erkannt) und es ist mindestens das 2. zeichen]
    {
      Buffer[index] = '\0';                                    // Dann setze Nullbyte als Stringende
      index = 0;                                               // Und setze Zähler auf 0
      stream.write(XOFF);                                      // Sende DC3 X-OFF
      delay(5000);
      return Buffer;                                           // und gebe die ausgewertete Zeile zurück
    };
    if (Zeichen == ';') { Kommi = true; };                     // Wird das Zeichen für Kommentar erkannt setze den Blockiermerker
  };
  return NULL;                                         // Sind keine Zeichen im SerialCache dann Gebe NullByte zurück
};


Egebnis ist das Die Komplette Datei durchgesendet wird ohne bei XOFF anzuhalten.
den Delay sieht man ledeglich an der Ausgabe des Arduinos im Fenster. Read: Kommt da mit der Verzögerrung an.
Emfangs LED ist schon lange dunkel während noch Meldungen ankommen und die SendeLED  noch blitzt.
Die LED'S sind auf dem Arduinobord Vorinstalliert.
Die EmpfangsLED ist durchgänig am Anfang am leuchten. das heist XOFF wird komplett ignoriert...


Ideen??? :'(

Serenifly

#14
Feb 20, 2016, 04:34 am Last Edit: Feb 20, 2016, 05:10 am by Serenifly
Ich habe kein Linux, aber ich habe mal mit RealTerm probiert. Normal nehme ich HTerm, aber das macht kein Software Handshaking (nur Hardware).

Was ich da habe, ist dass das nach ein paar Zeilen aufhört :(
Aber es liegt nicht am Arduino! Wenn per Hand eine Zeile schickt reagiert er darauf! Also läuft das Programm und hängt nicht irgendwo


Aber davor macht er XON/XOFF (glaube ich) korrekt. Mit diesem Code:

Code: [Select]

void loop()
{
  if (readSerial(Serial))
  {
    Serial.write(XOFF);
 
    Serial.println("ack");
 
    delay(1000);

    Serial.write(XON);
  }
}


Ich glaube zumindest dass die RX LED nur alle Sekunde blinkt...

Wieso das nicht durchläuft kann ich aber nicht sagen :(

Vielleicht liegt es bei dir auch eher am Terminal Programm


Nachtrag: CoolTerm zeigt genau das gleiche Verhalten :(

Es sieht doch danach aus dass das Terminal Programm nicht auf XOFF reagiert. Wenn ich auf dem Arduino kein Delay mache empfange ich alles. Mit dem Delay kann es sein dass dann der Eingangspuffer zu schnell gefüllt wird. Und der ist nach 64 Zeichen voll.

Go Up