GPS-Logger im Selbstbau: Status und Frage

Hallo.

Wie Ihr vielleicht erinnert hatte ich mich entschlossen einen GPS-Logger selbst zu bauen. Dazu habe ich mein EM406a-GPS-Modul und ein SD-Karten-Breakout mit einen Arduino Uno(der entsprechende Nano wartet bei der Post auf mich) gekoppelt.
Verwendet habe ich die, mit der IDE "mitgelieferte", SD-Bibliothek (#include <SD.h>). und SoftSerial (ursprünglich #include <SoftwareSerial.h>).
Die gelieferten Daten lese ich in einen char-Buffer von 512 Byte (+1) Größe. Nach Einlesen von 512-Zeichen wird der Puffer auf die SD-Karte geschrieben. Dabei kam es aber immer wieder zu Überläufen im seriellen Empfangspuffer von SoftSerial, weshalb ich den Puffer auf 128Byte vergrößert habe.
Aufgezeichnet werden sämtliche NMEA-Sentences, welche das Modul liefert und mein Gerät verarbeiten kann. Zur Vollständigkeit, diese Daten werden dann mit GPS-Babel ins GPX-Format gewandelt und mit QLandkarteGT betrachtet.

Das Ganze funktioniert auch ganz gut, am Donnerstag habe ich eine Fahrt von etwa 45 Minuten komplett aufgezeichnet. Bei der Weiterfahrt danach brach er aber nach etwa 15 Minuten ab. Dies führe ich noch auf das Breadborad-Equipment zurück. Heute nun hat er problemlos zweimal 25-Minuten-Fahrten aufgezeichnet.

Soweit der Status, nun zur Frage:
Bei der Fahrt am Donnerstag stellte ich besagte Überläufe fest, weshalb die Vergrößerung des Einlesepuffers der Softserial erfolgte. Allerdings reichte die anfängliche Vergrößerung auf 96 Byte noch nicht aus. Bei 128 Byte kam es dann aber schon zu Problemen beim Programmablauf, die ich auf Probleme mit der Speichergröße zurückführe. Also habe ich schon mal die Ermittlung des nächsten Dateinamens hinausgeworfen und speichere nun in immer dieselbe Datei.
Auf der Suche nach speicherplatzsparenden Alternativen zu SD stiess ich im Storage-Forum auf die Information, dass man statt SD die Bibliothek SdFat nehmen sollte. Sie sei deutlich fehlerbereinigt und wäre auch schneller.
Allerdings musste ich feststellen, dass das Schreiben meiner 512-Byte nun (trotz SPI_FULL_SPEED) etwa 1,5-mal solange dauert wie zuvor. Immerhin, RAM scheint das Teil weniger zu verbrauchen.

Daher nun meine Frage(n) (lange Rede kurzer Sinn):

  • Welche Bibliothek verwendet Ihr für "schnelle" Speicherung?
  • Sollte man SdFat oder SD verwenden (oder ist mittlerweile etwas ganz Anderes der Standard)?

Mit besten Grüßen
Gruaga

Ich habe gestern auch mal damit recherchiert. Die Arduino SD Klasse ist nur eine Wrapper Klasse einer alten sdFat Version. Deshalb wie du sagst, verbuggt.

sdFat scheint mehr schon deshalb besser, weil sie mehr Funktionen hat und vor allem C++ Input und Outputstreams. Wunderbare Syntax wenn man sich mal dran gewöhnt hat. Da muss man nicht immer gegen die begrenzten Sprachmittel der Standard Lib programmieren. Die Lib ist auch sehr gut dokumentiert mit doxygen HTML Dateien und zig Beispielen.

Aber dir geht es ja um die Geschwindigkeit. Da steht dabei, dass das auch stark von der SD Karte abhängt. Neuere SD Karten sind oft langsamer, da diese nicht für diese Art von Datentransfer ausgelegt sind. Siehe die readme Datei "card performance" in der sdFat Zip:

Cards have two write modes, single block random mode and multiple block sequential mode. For file writes I must use single block mode. This is always slow but often extremely slow in high end cards. microSD cards also have poor support for this mode.

I have several applications that use multiple block mode and they run much faster. The binaryLogger.pde example can log 40,000 16-bit samples per second without dropping data on a good SanDisk video card.

[...]

The write time for a 512 byte block in sequential mode is about 850 microseconds with occasional busy times of 2 - 3 ms on a SanDisk Extreme 30 MB/sec card. In random mode this card is often slower than five year old class 2 cards.

Praktisch habe ich da allerdings kaum Erfahrung.

EDIT:
Es sind in den Examples auch benchmarks vorhanden um die Karten zu Testen. Auch einer für die Standard SD Lib.

Hallo.

Was mich wundert ist ja, dass ich bei derselben Karte die Geschwindigkeitsunterschiede zwischen SD und SdFat feststelle. Die wenigen Millisekunden, die der Autor angegeben hatte kann ich gar nicht erreichen. Ich fülle ja immer 512 Byte und schreibe die dann raus. Wegen des 512-Byte_puffers arbeitet er da ja wohl im angesprochenen langsamen "single block random mode".

Bei der SD-Library lag ich so bei umrum 60 ms im Mittel, während ich bei der SdFat-Library bei etwa 100 ms lande.

Interessanterweise ergibt SPI_FULL_SPEED keinen merkbaren Unterschied zu SPI_HALF_SPEED.

BTW: Standardanschluss mit Chip-Select auf Pin 4 und Pin 10 als Output, auch wenn SdFat das ja wohl nicht benötigt. Wie ja schon geschrieben. Es funktioniert, nur könnte es mir vielleicht etwas mehr Luft lassen beim Funktionieren. :slight_smile:

Werde noch ein wenig probieren, bis zur Radtour sind es ja auch noch ein paar Monate. :slight_smile:

Schöne Grüße
Gruaga

gibst Du mal den Code?
Grüße Uwe

Hi.

Kann ich schon, aber der nicht, dass mir jetzt hier einer mit einheitlicher Strukturierung oder so kommt. Meine erste Programmiersprache war FORTRAN IV, sowas prägt!

#include "MK_SoftwareSerial.h"
#include <SdFat.h>

static const char PROG_VERSION[] = "06";
static const char PROG_NAME[]    = "GPS_Logger";


// Version 06: Datei wird beim Schreibvorgang geöffnet
// Version 07: "Bereinigte" Version von 06

static const int      RXPin   =     5, TXPin = 3;
static const uint32_t GPSBaud =  4800;
static const int      BUFLEN  = 1*512;

char *buffer;
unsigned int buf_ptr;

const int chipSelect = 4;    // SD-Karte

SoftwareSerial ss(RXPin, TXPin); // RX, TX
void blink_forever(int duration);

//const char FILE_PREEFIX[] = "TMK";
const char filename[] = "GPSTRACK.LOG";
const int ledPIN = 13;

SdFat filesystem;
SdFile dataFile;


void setup()  
{
  pinMode(ledPIN, OUTPUT);
  digitalWrite(ledPIN, HIGH);
  ss.begin(GPSBaud);

  pinMode(10, OUTPUT);     // change this to 53 on a mega
  if (!filesystem.begin(chipSelect, SPI_HALF_SPEED)) {
    // ToDo: Set red LED
    blink_forever(100);
  }

/*  
  sprintf(filename,"%s%05ld.LOG",FILE_PREEFIX,getNextNumber(SD.open("/")));
*/
  // Zeichenbuffer vorbereiten
  buf_ptr = 0;
  buffer  = (char*)malloc(BUFLEN+1);
  buffer[BUFLEN] = 0;
  buffer[buf_ptr++] = '\t';
  buffer[buf_ptr++] = '\r';
  buffer[buf_ptr++] = '\n';

  ignore_start_chars();
  digitalWrite(ledPIN, LOW);
}

void loop() // run over and over
{
  while (ss.available()) read_char_to_buffer();
}

void read_char_to_buffer(void) {
  buffer[buf_ptr] = ss.read();
  buf_ptr++;
  if (buf_ptr >= BUFLEN) {
    write_buffer_to_card();
  }
}

void write_buffer_to_card(void) {
  digitalWrite(ledPIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  buffer[buf_ptr] = 0;
  
  if (dataFile.open(filename, O_RDWR | O_CREAT | O_AT_END)) {
    // if the file is available, write to it:
    dataFile.print(buffer);
    dataFile.close();
  } else {
    // if the file isn't open, pop up an error:
    // ToDo: Set red LED
    blink_forever(500);
  } 
  buf_ptr = 0;
  digitalWrite(ledPIN, LOW);    // turn the LED off by making the voltage LOW
}

void blink_forever(int duration) {
  while (true) {
    digitalWrite(ledPIN, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(duration);              // wait for a second
    digitalWrite(ledPIN, LOW);    // turn the LED off by making the voltage LOW
    delay(duration);              // wait for a second
  }
}


void ignore_start_chars(void) {
  char last = 'A';
  char curr = 'B';
  while (ss.available()) {
    curr = ss.read();
    if ((last == '\r') and (curr == '\n')) return;
    last = curr;
  }
}

/* Funktioniert so nicht mit SdFile!!!!
// Function zum Feststellen der höchsten Dateinummer
long getNextNumber(SdFile dir) {
  char *ptr;
  long maxnum = -1;
  while(true) {
    SdFile entry = dir.openNextFile();
    long num   = 0;
    if (! entry) {
      // no more files
      #ifdef DEBUG_1
        Serial.println("**nomorefiles**");
      #endif
      break;
    }
    #ifdef DEBUG_1
      Serial.print(maxnum,DEC); Serial.print(" "); Serial.println(entry.name());
    #endif
    ptr = entry.name();
    if ((ptr[0] == FILE_PREEFIX[0]) and 
        (ptr[1] == FILE_PREEFIX[1]) and 
        (ptr[2] == FILE_PREEFIX[2])) {
      for (int i = 3; i < 8; i++) num = (num*10) + (ptr[i]-'0');
    }
    entry.close();
    maxnum = max(maxnum,num);
  }
  // Letzte Datei verarbeitet
  return (maxnum + 1);
}

*/

MK_SoftwareSerial.h ist meine Version der SoftwareSerial.h in der ich nur den Wert für den Eingangspuffer erhöht habe. Deshalb habe ich die hier nicht eingeblendet.
Ich habe dafür eine eigentständige Variante gewählt, da die Verzeichnisse über verschiedene Rechner an verschiedenen Standorten repliziert werden.

Mit besten Grüßen
Gruaga

Sieht doch gut aus :slight_smile:

malloc() brauchst du allerdings nicht wenn die Größe des Arrays zur Compile Zeit bekannt ist. Das ist dafür da dynamisch Arrays zur Laufzeit anzulegen. Hier reicht einfach das:
char buffer[BUFFERLEN];

Und Funktionen vor Gebrauch zu deklarieren braucht man auf dem Arduino auch nicht unbedingt. Das macht die IDE automatisch.

Das mit dem Block Transfer ist bei sdFat übrigens im "RawWrite" Beispiel. Da wird das mit writeData() gemacht und davor werden noch ein paar Befehle zur Vorbereitung geschickt und dann mit writeStop() abgeschlossen. Mit print() kann es gut sein, dass er die im Hintergrund immer noch char für char schreibt. Ich würde mich auf keinen Fall darauf verlassen, dass er da einen Block Transfer macht nur weil dein Puffer zufällig 512 Byte hat.

EDIT:
Außerdem geht das da über die Sd2Card Klasse und nicht die File Klasse! Sd2Card erlaubt diesen low level Zugriff und die ganzen Methoden arbeiten auf Block Ebene.

Die File Klasse hat aber mit createContiguous() eine Methode um eine Datei genau definierter Größe anzulegen. Das wird da vorher gemacht um eine Datei mit x Blöcken zu erzeugen. Aber das Schreiben erfolgt anders.

Hi.

Das malloc ist (noch) drin, da ich den Puffer erst nach der Ermittlung des nächsten Dateinamens angelegt habe. Die Aktivitäten zur Dateinamensermittlung (auskommentierte Funktion ganz unten) konnten nicht mit angelegtem Puffer und dem vergrösserten Puffer in SoftwareSerial durchgeführt werden. Dazu reicht das RAM nicht.

Die Funktions-Deklarationen sind noch drin wegen des guten Programmierstils. Sie sind beim "Optimieren" der Angelegenheit aber ein wenig ins Hintertreffen geraten. Implizite Typendeklarationen habe ich bei FORTRAN fürchten gelernt. Daher kommen sie vermutlich zur Fertigstellung wieder hinein.

Der Puffer hat nicht "zufällig" 512 Byte, sondern ganz gezielt um eben genau die Blockgröße der SD-Card zu treffen und damit dem Karten-"OS" die Arbeit zu erleichtern.

Da ich ja den Logger einschalte und dann irgendwann (wenn ich keine Lust mehr habe und meine aktuelle Etappe beende oder eine Pause einlegen) wieder ausschalte, weiss ich ja nicht vorher, wieviele Blöcke ich benötigen werden. Somit kann ich (nach aktuellem Kenntnisstand) keine entsprechenden Optimierungen bei Schreiben der Daten durchführen. Einen Ausschalter wollte ich mir auch sparen, den Verlust des letzten Blockes kann ich verkraften, da ich mindestens drei Sekunden brauche um mich aufzurichten und den Stromanschluss des Loggers zu erreichen. :slight_smile:
Wenn die vorliegende "Lösung" allerdings tatsächlich die Daten des Puffers Zeichen für Zeichen schreibt, so wundere ich mich nicht über die Geschwindigkeit. SD macht's in dem Falle wohl besser. Warum aber SPI_HALF_SPEED im Vergleich zu SPI_FULL_SPEED keine Änderung bringt verstehe ich aber immer noch nicht. Schliesslich würde dies bedeuten, dass die SPI-Geschwindigkeit nur wenig zum gesamten Zeitverbrauch beiträgt, was wiederum durchaus zu einer zeichenweisen Verarbeitung passen könnte.

Die Doku von SdFat fand ich suboptimal (deshalb habe ich bisher immer mit SD gearbeitet) und die Beispiele sind zwar vielfältig aber leider nicht sehr generell. Allerdings bin ich dem Hinweis mit doxygen noch nicht gefolgt. Vielleicht findet sich da ja ein wenig Erklärung. Momentan empfinde ich die Abläufe und Vorgehensweise bei SD ein wenig schlüssiger, aber SdFat hat eben ein bisschen weniger Speicherhunger. Dadurch konnte ich den Eingangspuffer für Softserial nochmals erhöhen und habe nun keine Ausfälle mehr. Aber ich schreibe immer noch jedesmal in dasselbe File, was mich nicht zufriedenstellt.

Fazit: Schauen wir mal in die Doku.

Mit besten Grüßen
Gruaga

Zufällig sind 512 Bytes natürlich nicht. Aber ist trotzdem nur ein beliebiger Puffer. Die Größe alleine bestimmt nicht wie das übertragen wird.

Doxygen ist nur ein Tool um solche Dokus aus speziell formatierten Kommentaren zu erstellen. Zum Ansehen braucht man sonst nichts.
Für die Doku öffne einfach SdFat.html. Da sind dann Links zu allen Klassen und die Methoden sind mit allen Parametern erklärt. Wenn man sich dann an die Beispiele hält und die verwendeten Methoden nachschlägt sieht man was gemacht wird.

Was einem halt am Anfang vielleicht etwas verwirrt ist die ganze C++ Syntax mit den Streams. Das ist auf dem Arduino eher selten. Aber wenn man sich mal dran gewöhnt hat ist das mächtiger und kürzer.

Sowie ich das sehe sind da folgende Schritte wichtig:

uint32_t bgnBlock, endBlock;

  // create a contiguous file
  if (!file.createContiguous(sd.vwd(), "RAW.TXT", 512UL*BLOCK_COUNT)) {
    error("createContiguous failed");
  }
  // get the location of the file's blocks
  if (!file.contiguousRange(&bgnBlock, &endBlock)) {
    error("contiguousRange failed");
  }

  // clear the cache and use it as a 512 byte buffer
  uint8_t* pCache = (uint8_t*)sd.vol()->cacheClear();

  // tell card to setup for multiple block write with pre-erase
  if (!sd.card()->erase(bgnBlock, endBlock)) error("card.erase failed");
  if (!sd.card()->writeStart(bgnBlock, BLOCK_COUNT)) {
    error("writeStart failed");
  }

  if (!sd.card()->writeData(pCache)) error("writeData failed");

Sowie da da steht musst du auch gar keinen extra Puffer anlegen! Du kannst den Pointer nehmen der von cacheClear() kommt und diesen vor dem Aufruf von erase(), writeStart() und writeData() mit den deinen Daten füllen.

Hm, also meine Überlegungen zu Deiner GPS-Anwendung:

  1. Ich habe gerade mal getestet, die SD-Library schreibt im Dauerstrich mit einer Schreibrate von über 40 KB pro Sekunde. Dein GPS-Modul liefert Daten mit 4800 Baud = 480 Byte/s, also weniger als 0,5 KB pro Sekunde. Von der möglichen Schreibrate her überhaupt kein Thema.

  2. Kritischer ist die "maximale Dauer pro Schreibvorgang", da diese keine Konstante ist, sondern variiert. Die maximale Dauer pro Schreibvorgang darf nicht länger sein als die Dauer, in der sich der serielle Eingangspuffer komplett füllen kann. Bei einer Standardpuffergröße von 64, die maximal 63 Zeichen zwischenpuffert, beträgt diese Dauer 63/480s = 131 ms. Das sollte eigentlich machbar sein.

  3. Um sowohl die durchschnittliche als auch die maximale Dauer von Schreibvorgängen möglichst gering zu halten, bietet es sich an, die Datei nicht vor jedem Schreibvorgang zu öffnen und nach jedem Schreibvorgang zu schließen, sondern die Datei seltener zu schließen und dies davon abhängig zu machen, dass auch "genug Zeit dafür" zur Verfügung steht. Siehe auch Punkt 5.

  4. Die GPS-Daten würde ich nicht einfach nur blind auf die SD-Karte weiterleiten, sondern vorab grob auswerten. Z.B. würde ich die bei den Daten zeilenweise die Prüfsumme testen und nur Daten mit gültiger Prüfsumme auf SD-Karte loggen. Außerdem ist es relativ unergiebig, Daten zu loggen, wenn überhaupt keine Daten vorliegen. Die mir bekannten GPS-Module generieren dann "leere NMEA-Datenzeilen". Das erste was kommt, wenn irgendwas empfangen wird, ist Datum und Uhrzeit. Loggen würde ich daher erst dann, wenn Datum und Uhrzeit in den Daten enthalten sind. Damit löst sich dann auch das Problem der "automatischen Dateinamen": Wenn nach Programmstart der erste Timestamp empfangen wird, wird ein Dateiname nach dem Schema YYMMDDHH.txt gebildet. So landen alle Logs, die in derselben Stunde beginnen, in derselben Datei. Der Dateiname ist so gleich ein "sprechender Dateiname" und verrät, wann das betreffende Log gestartet wurde.

  5. Außerdem würde ich "zeilenweise loggen" und nicht in 512 Byte-Blöcken. NMEA ist ein Textformat, das zeilenweise loggen würde dafür sorgen, dass immer ganze Zeilen in einer Log-Datei landen. Und es hätte den Vorteil: Da viele Schreibvorgänge nicht über eine 512 Byte-Puffergrenze hinausgehen, sind viele Schreibvorgänge extrem schnell. Tatsächlich werden die Daten nur in den Schreibpuffer der SD-Library übertragen. Die Dauer von Schreibvorgängen könne man messen, und wenn solche kurzen Schreibvorgänge auftreten, die Datei von Zeit zu Zeit (alle 10 Sekunden oder einmal pro Minute) schließen und wieder zum Schreiben öffnen.

  6. Und last but not least würde ich auf die unsagbar unbrauchbare SoftwareSerial Library verzichten und stattdessen die Verwendung der AltSoftSerial Library favorisieren, wenn es denn schon eine per Software emulierte Schnittstelle sein muß.

Soweit meine Überlegungen dazu.

Hallo.

Gestern Abend hatte ich den gesamten Beitrag schoin einmal eingetippt. Dann verweigerte das Frontend aber leider die weitere Zusammenarbeit und der Beitrag verschwand in den Tiefen des Rechners/Netzes. Leider hatte ich nicht daran gedacht, dass HTTP ja zustandslos ist und man solche Sachen lieber in echten Programmen eintippen sollte.

Nundenn, dank der Hinweise von Serenifly habe ich mich gleich einmal etwas tiefer mit SdFat beschäftigt. Das Anwenden des RawWrite-Beispieles scheint mir nicht passend, da ich ja immer nur (gewollt) einen Block von 512-Byte habe und nicht vorher weiss, wieviele Blöcke ich denn benötigen werde. Da ich ja keinen Ausschalter einbauen wollte (gemäß Malerleins Feststellung in einem anderen Thread "Strom an: Gerät geht; Strom aus: Gerät geht nicht.") kann ich auch keine "Abschlussarbeiten" durchführen.

Nachdem ich in der SD-Library vergeblich danach suchte, habe ich in SdFat eine write-Funktion gefunden. Ohne Senerifly's Hinweis und der folgenden Betrachtung der Codestücken hätte ich vielleicht gar nicht noch einmal gesucht, daher meinen Dank; denn nun schreibt das Ganze viel schneller. Zwischen unter 10ms und 40ms braucht er nun (nach der ersten Initialisierung). So sollte das passen.
Bei der Gelegenheit habe ich mich dann auch noch einmal mit der Funktion zur Ermittlung des nächsten Dateinamens geschäftigt und auch diese ist nun wieder drin.

@jurs:
Zu 1: Ja, sonst hätte ich das ganze Thema gar nicht erst angefangen, mich aber schon ein wenig gewundert, wie es denn andere Systeme machen, denn schnellere Controller brauchen ja auch meist (deutlich) mehr Leistung, etc.

Zu 2: Stimmt, dem Punkt hatte ich mich noch nicht gewidmet.

Zu 3: Das stete Öffnen und Schliessen erfolgt, damit die Daten auch auf der SD-Card "sichtbar" werden. Ich habe schon verschiedene Massenspeicher gesehen und viele davon realisierten die Daten erst dann auf dem Medium, wenn man Dateien schloss oder das System synchronisierte.
Da ich aber ja keine Daten verlieren, sondern sie umgehend auf der Karte realisiert sehen wollte, habe ich die Datei einfach geschlossen, was ja von jedem System als "So sei es!" aufgefasst wird.
Eine Verwaltung von Schreibvorgängen hatte ich zwar auch schon einmal angedacht, aber als weitere Fallback-Option zurückgestellt, da ich es eigentlich möglichst einfach halten wollte.

Zu 4: Gleich zu Beginn des Projektchens habe darüber nachgedacht, ob die rohen Sentences oder lieber prozessierte Daten geschrieben werden. Mit TinyGPS habe ich gute Erfahrungen gemacht. Aber schliesslich kam ich zu dem Schluss, dass ich alles haben will, einschliesslich den Daten vor dem ersten Fix. Daher schreibe ich nun auch alles (bis auf den ersten verstümmelten Sentence) weg.
Meine verschiedenen Dateinamen habe ich ja nun wieder, was mich erstmal zufriedenstellt. Vielleicht (ein wenig Zeit ist ja noch) versuche ich die Zeit des ersten Fix als Erstellungszeit der Datei zu setzen (diese Attribut trägt ja sonst sinnlose Informationen in sich), falls mich das System da heran lässt. :slight_smile:

Zu 5:
Da ich ja keinerlei Behandlung der Informationen vornehme erscheinen die Datei den nachfolgenden Systemen zeilenweise (zwar mit MSDOS-konformer Zeilenendekennung, aber damit kommen Unixe problemlos klar).
Ich schreibe Block- und nicht Zeilenweise um selbst sicherstellen zu können, dass das Karten-"OS" nicht tatsächlich bei jeder Zeile den entsprechenden Block auf dem Medium umherschiebt. Man sollte zwar erwarten dürfen, dass hierfür Vorkehrungen getroffen sind, aber wer weiss. Beim Schreiben eines Blockes besteht,so gesehen, eben auch keine Notwendigkeit für die Karte mit den schon geschriebenen Blöcken zu jonglieren (zumindest aus meiner Sicht).

Zu 6: Ah, sehr interessant. Zu dem Thema war ich nämlich "unterwegs", da mir die "Probleme" mit der SoftwareSerial der aus der Distribution zu "Ohren" gekommen waren. Da hatte ich dann gelesen, dass man statt dessen besser die NewSoft...-Library (den genauen Namen habe ich gerade mich parat) verwenden sollte und diese auch die AltSoftSerial toppen würde. Nachdem ich dann NewSoft... eingebunden hatte, erzählte mir diese wiederum, dass sie die alte defekte SoftwareSerial iun der Distribution ersetzt hätte und ich daher lieber die SoftwareSerial aus der Distribution einsetzen sollte.
Wie stehen nun AltSoftSerial und NewSoft... bzw. (alte) softwareSerial zueinander? Welches ist die bevorzugte Version?

Soviel dazu, ist doch ein wenig länger und ausführlicher geworden, als gestern Abend. :slight_smile: Heute fahre ich zurück nach Ottobrunn, da werde ich dann mal gucken, wie mein Spielzeug nun funktioniert.

Beste Grüße aus dem leicht angeschneiten Schwaben
Gruaga

NewSoftSerial ist schon in der Arduino IDE seit 1.0 dabei:
http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html

Das mit der unbekannten Größe könnte man grob z.B. so lösen, dass du alle x Blöcke eine neue Datei anfängst. Außerdem gibt eine truncate() Methode um Dateien zu kürzen wenn der Speicher nicht voll belegt ist. Das heißt wenn eine Datei mit Größe x angelegt ist, aber nur y gebraucht wurde, wird die Datei auf y verkleinert.

Aber wenn es erst mal schnell genug ist, dann brauchst du das nicht. Man muss ja nicht tausende Werte pro Sekunden speichern :slight_smile:

Hallo.

Erfolg!

Meine Fahrt aus dem Ulmer Raum nach Ottobrun heute Mittag hat eine Strecke von 177km in 1:42 Stunden ergeben. Dabei wurden 6077 Punkte des Tracks von gpsbabel verwertet. Eine genauere Auswertung der einzelnen Sentences ergab, dass in der Datei 28.364 Senstences drin waren und 28.363 Sentence davon korrekt waren (keine doppelten $-Zeichen und Checksumme okay). Auch die Abfolge der Sentences passt.

Vielen Dank für Eure Hilfe!

Ich werde mich jetzt dem Thema zuwenden den Fix zu identifizieren und die Zeitattribute der Datei korrekt zu setzen. Naja und natürlich das Zeugs auf einer Lochrasterplatine in einen stabileren Zustand zu versetzen.

Grüße
Gruaga

gruaga:
Meine Fahrt aus dem Ulmer Raum nach Ottobrun heute Mittag hat eine Strecke von 177km in 1:42 Stunden ergeben. Dabei wurden 6077 Punkte des Tracks von gpsbabel verwertet.

1:42 Stunden sind gute 100 Minuten sind knapp über 6000 Sekunden.

Dein GPS-Modul sendet einmal pro Sekunde einen Schwung Daten und Du wertest am Ende nur die $GPRMC Daten mit Deiner Software weiter aus.

Im Endeffekt würde es dann auch reichen, auf SD-Karte nur die 6077 relevanten Datenzeilen zu speichern.
Das macht am Ende: Du mußt weniger als 82 Bytes pro Sekunde speichern.

Und das ganze Tüüdelüüt von wegen Anzahl, ID-Nummer, Position und Empfangsstärke der empfangenen GPS-Satelliten und was weiß ich noch speicherst Du alles völlig über den Durst, weil Du es am Ende sowieso nicht auswertest, ob in Minute 3 Deiner Tour 5 Satelliten empfangen wurden und an welcher Stelle am Himmel sie dabei standen.

Aber wenn inzwischen die Zeit zum Speichern ausreicht - Glückwunsch zum Erfolg!

Hallole.

Also eigentlich will ich primär die GGA- und GSA-Sentences auswerten, RMC eher sekundär, da ja GGA die wichtigen Daten (ausser Datum) enthält bzw. sie sich ermitteln lassen. VTG brauche ich tatsächlich nicht und GSV, nun da wäre das S/N schon interessant, insbesondere falls man da mal eine Korrelation mit den DOP-Werten fahren würde. Allerdings stimme ich jurs zu, dass ich es bezüglich der Radtour wohl kaum auswerten werde.

Jedoch war ich der Überlegung im Zusammenahng mit der Speichermenge ledig, als ich die Größe meiner Speicherkarte sah. :slight_smile:

Mittlerweile habe ich noch Programminformationen in TXT-Sentences eingebettet und weiss daher, dass der Arduino im Produktivlauf (ohne die Debugausgaben auf Serial) derzeit noch 419 Byte Speicher frei hat, nach dem Anlegen des Buffers.

Also, als nächstes ist nun löten angesagt (den zugehörigen Nano kann ich wohl morgen auf der Post abholen) und das Thema mit der Zeit des ersten Fixes als Dateizeit lockt mich auch noch.

Was mir aber noch nicht klar ist, was für ein Gehäuse nehme ich denn da am Besten? Dem direkten Sonnenschein (wie erhofft) oder dem Regenschauer (wie üblich) werde ich mein sensibles Gerät dann doch nicht aussetzen wollen. Da sehe ich dann ein weiteres Betätigungsfeld um die Wartezeit zu überbrücken. :smiley:

Mit besten Grüßen
Gruaga