Hallo zusammen, Kurze Projekt erklärung:
Der MPU-6050 soll mit hilfe des UP501 die Kurvenlage und die Position eines Motorrads auf der SD-Karte speichern.
Momentanes Problem:
Der GPS-Sensor sendet die Ausgegeben Zeilen nicht als ganzen Block, sondern als einzelne Zeichen, weshalb ich es nicht vernünftig auf der SD-Karte speichert und ich auch nicht gleichzeitig die Werte des MPU-6050 speichern kann.
Momentane Gespeicherte Werte(Beispiel):
G
P
S
:
1
2
5
4
6
6
N
3
X:2123 Y:1356 Z:1563
S
F
5
2
1
,
:
und so weiter
Wunsch:
Program Mit dem man auf einer Karte Die Strecke und den Winkel sieht. Besseres abspeichern:
Hatte einen Fehler übersehen.
Die SD Karte Speicherte mit dataFile.println() ,was dann das halbe Speicherproblem erklärt.
Den MPU-6050 hab ich noch garnicht miteingebunden, weil der meines Erachtens nach dann immer in den Zeichen rum "Trollt".
Hab momentan keinen Arduino zurhand.
Mein Lehrer meinte grade dass man die einzelnen Zeichen als Zeichenkette zwischenspeichern kann.
Weis wer wie man das machen Könnte?
#include <SoftwareSerial.h>
#include <SPI.h>
#include <SD.h>
const int chipSelect = 4;
char GPS;
SoftwareSerial mySerial(2, 3); // RX, TX ... the 10 is what matters based on my suggested wiring above
#define PMTK_SET_NMEA_UPDATE_1HZ "$PMTK220,1000*1F"
//#define PMTK_SET_NMEA_UPDATE_5HZ "$PMTK220,200*2C"
//#define PMTK_SET_NMEA_UPDATE_10HZ "$PMTK220,100*2F"
// turn on only the second sentence (GPRMC)
#define PMTK_SET_NMEA_OUTPUT_RMCONLY "$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29"
// turn on ALL THE DATA
//#define PMTK_SET_NMEA_OUTPUT_ALLDATA "$PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0*28"
void setup()
{
Serial.begin(115200);
Serial.println("Adafruit MTK3329 NMEA test!");
Serial.print("Initializing SD card...");
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
Serial.println("card initialized.");
// 9600 NMEA is the default baud rate
mySerial.begin(9600);
// uncomment this line to turn on only the "minimum recommended" data for high update rates!
mySerial.println(PMTK_SET_NMEA_OUTPUT_RMCONLY);
// uncomment this line to turn on all the available data - for 9600 baud you'll want 1 Hz rate
//mySerial.println(PMTK_SET_NMEA_OUTPUT_ALLDATA);
// Set the update rate
// 1 Hz update rate
mySerial.println(PMTK_SET_NMEA_UPDATE_1HZ);
// 5 Hz update rate- for 9600 baud you'll have to set the output to RMC only (see above)
//mySerial.println(PMTK_SET_NMEA_UPDATE_5HZ);
// 10 Hz update rate - for 9600 baud you'll have to set the output to RMC only (see above)
//mySerial.println(PMTK_SET_NMEA_UPDATE_10HZ);
}
void loop() // run over and over
{
if (mySerial.available()) {
GPS = (char)mySerial.read();
Serial.print(GPS);
File dataFile = SD.open("GPS.txt", FILE_WRITE);
dataFile.print(GPS);
dataFile.close();
}
if (Serial.available()) {
mySerial.print((char)Serial.read());
}
}
Frek07:
Mein Lehrer meinte grade dass man die einzelnen Zeichen als Zeichenkette zwischenspeichern kann.
Weis wer wie man das machen Könnte?
Dein Programm arbeitet viel zu ineffektiv, weil Du jedes einzelne Zeichen so schreibst:
öffne die Datei
schreibe ein Zeichen
schließe die Datei
Da die Aktionen "öffne die Datei" und "schließe die Datei" um ein Vielfaches länger dauern als "schreibe ein Zeichen", verbraucht Dein Programm beim Loggen der Daten die mehr als tausendfache Zeit wie es notwendig wäre.
Was Dein Lehrer nun vorschlägt wäre: Sammele die Zeichen einer kompletten Zeile in einem String zusammen und schreibe dann mit der Logik:
öffne die Datei
schreibe eine ganze Zeile
schließe die Datei
Ich hätte da aber noch eine andere Idee, allerdings nicht getestet, vielleicht probierst Du mal diese Logik mal aus:
File dataFile;
void loop() // run over and over
{
if (mySerial.available()) {
GPS = (char)mySerial.read();
dataFile.print(GPS);
Serial.print(GPS);
if (GPS=='\n') // bei erkanntem Zeilenende
{
// hier ggf. Funktion aufrufen zur Ausgabe von X, Y, Z
dataFile.close(); // Datei schließen
dataFile = SD.open("GPS.txt", FILE_WRITE); // und sofort wieder öffnen
}
}
if (Serial.available()) {
mySerial.print((char)Serial.read());
}
}
Dabei wäre das Filehandle 'dataFile' eine globale Variable, alle Schreibvorgänge bis zum ersten Zeilenende schlagen fehl (weil die Datei bis dahin nicht geöffnet ist) und es können am Anfang der Datei keine "halben Zeilen" auftreten. Ab dem ersten eingetroffenen Zeilenende dann wird die Datei dann immer geschlossen und sofort wieder geöffnet, und alle nachfolgenden Schreibvorgänge im Program können dass das geöffnete Dateihandle verwenden, womit die Schreibrate des Programms sehr viel höher sein kann.
Das Zeilenende vom GPS mußt Du ja sowieso erkennen können, weil das immer der Punkt ist, wo Du nachfolgend die X,Y,Z-Werte in einer Zeile ausgeben möchtest.
P.S.: Die zu Arduino mitgelieferte "SoftwareSerial" Library ist eine der schlechtesten Libraries, die mitgeliefert wird. Bei gleichzeitiger Verwendung von "Serial" und "SoftwareSerial" ist Buchstabensalat vorprogrammiert. Besser wäre es, Du installierst Dir die zusätzliche "AltSoftSerial" Library, die funktioniert um Längen besser. Allerdings nicht bei freier Pinwahl für RX/TX: Je nach Board mußt Du zusammen mit AltSoftSerial fest vorgegebene Pins verwenden, beim UNO wären das also beispielsweise Pin-8 für RX und Pin-9 für TX.
Sollen die Zeilen wirklich so erzeugt werden, wie Du es vorzeigst:
ax;ay;az;gx;gy;gz;ms;GPRMC
Sieht mir etwas merkwürdig aus.
Ansonsten zu den Fehlern: Schwierig zu sagen, ohne den Code zu kennen, der den Fehler produziert.
Aber lasse mich mal raten:
Trotz meiner oben gegebenen Hinweise liest Du das GPS-Modul immer noch mit der "SoftwareSerial" Library aus und hast Dir entgegen meines Ratschlags noch nicht die "AltSoftSerial" Library installiert?
Dann wäre das vollkommen normal: Die gleichzeitige Benutzung von SoftwareSerial mit einer HardwareSerial-Schnittstelle führt immer dazu, dass Softwareserial die Daten verhackstückt. Nur AltSoftSerial kann mit einer HardwareSerial-Schnittstelle problemlos gleichzeitig betrieben werden.
Oder in Frage käme auch ein Pufferüberlauf wegen zu langsamer Verarbeitung Deiner Daten.
Das GPS-Modul sendet mit 9600 Baud, das sind bis zu 960 Zeichen pro Sekunde. Der serielle Eingangspuffer beim Arduino kann maximal 63 Zeichen aufnehmen. D.h. wenn Du Daten vom GPS-Modul in Realzeit verarbeiten möchtest, hast Du vom vollständigen Auslesen des seriellen Eingangspuffers bis Du diesen wieder auslesen mußt nur 63/960= 0,065s = 65 Millisekunden Zeit.
Im schlimmsten Fall kann es bereits länger dauern, eine Datei auf SD-Karte zu schließen und wieder zu öffnen (wobei das typischerweise allerdings schneller geht). Aber wenn Du beispielsweise irgendwo auch nur eine Zehntesekunde delay() drin hast wie ein delay(100), dann ist das bereits schon viel zu viel, um GPS-Daten in Echtzeit zu verarbeiten, ohne dass dabei Daten verloren gehen. Zur Verarbeitung von Echtzeitdaten darf kein delay() in Deiner Datenverarbeitung drin sein.
BTW: Die NMEA-Daten in den GPRMC-Zeilen sind am Ende mit einer CRC-Prüfsumme gesichert, d.h. Du könntest beim Einlesen prüfen, ob die CRC-HEX-Prüfsumme stimmt, das sind die beiden letzten HEX-Ziffern nach dem Sternchen in "*6A" beispielsweise).
ich benutze die NewSoftSerial, welche ich mir bloß umbenannt hatte.
Die Daten wollte ich mir so rausgeben lassen, weil die so erstmal am besten in Excel eintragen kann, damit ich dann nur die Spalte mit GPS auswählen kann.
Gibt es einen großen unterschied zwischen AltSerialSoft und NewSerialSoft ?
Frek07:
Gibt es einen großen unterschied zwischen AltSerialSoft und NewSerialSoft ?
NewSoftSerial von Mikal Hart ist quasi dasselbe wie SoftwareSerial aus der Arduino-IDE.
Da gibt es praktisch keinen großen Unterschied, außer dass die eine Library für die alten Doppelnull-Versionen vor Arduino 1.0 geschrieben wurde und das andere in die Arduino-IDE ab 1.0 und höher direkt integriert worden ist.
Und da es einen sehr großen Unterschied zwischen SoftwareSerial aus der Arduino IDE zu AltSoftSerial gibt, gibt es natürlich denselben sehr großen Unterschied auch zwischen NewSoftSerial von Mikal Hart zur AltSoftSerial Library.
Nur die AltSoftSerial funktioniert mit einer HardwareSerial Schnittstelle zusammen gleichzeitig fehlerfrei.
Dass sich eine solche Datenformatierung, bei der manche Spalten offenbar mit Tabulator-Trennzeichen und andere Spalten mit einem Komma als Trennzeichen abgetrennt sind, besonders lässig in Excel importieren lassen sollen, kann ich kaum glauben.
Ich mache zwar praktisch nichts mit Excel, abe wenn ich mich richtig erinnere, lassen sich Daten am einfachsten importieren, wenn man sich bei der zu importierenden Datei nach den Ländereinstellungen richtet, also zum Beispiel Feldtrennter Tabulator '\t' und das Komma als Dezimaltrennzeichen für die Darstellung von Dezimalwerten verwendet wird und auch das Datum in deutscher Formatierung in der Datei steht.
Um ein wirklich gut zum Import in MS-Excel geeignetes Format schreiben zu können, wirst Du die GPS-Daten beim Einleseh wahrscheinlich doch zeilenweise sammeln und die Inhalte interpretieren müssen. Alleine auch deshalb, weil die Geokordinaten wie "5227.2821,N,00722.4883,E" ja auch nicht in dezimalen Gradzahlen angegeben sind, sondern die Werte noch ein wenig umgestellt/umgerechnet werden müssen, um die tatsächliche Geoposition zu erhalten.
Man kann die Trennzeichen beim Import einstellen. Da gibt es viele Optionen. Tabs, Leerzeichen, Kommas, Strichpunkte ist alles möglich. Es gibt auch ein Feld für frei definierte Trennzeichen
Serenifly:
Man kann die Trennzeichen beim Import einstellen. Da gibt es viele Optionen. Tabs, Leerzeichen, Kommas, Strichpunkte ist alles möglich. Es gibt auch ein Feld für frei definierte Trennzeichen
Ja klar, kann man diverse Optionen beim Datenimport auch jedesmal interaktiv einstellen, wenn man Daten in Excel importiert. Aber wenn man 25 Messreihen am Tag fährt und auswerten möchte, wäre es schon bedeutend bequemer, eine Datei nur per Doppelklick zu öffnen (oder Daten aus der Windows-Zwischenablage mit "Einfügen" zu übernehmen) und mit Default-Einstellungen zu importieren, ohne jedesmal irgendwas haarklein als geänderte Option einstellen zu müssen.
deswegen speicher ich die Datei gleich als .csv, ersetze vorm schreiben in die Datei bei Kommazahlen den Punkt durch ein Komma und nutze als Trennzeichen für Spalten das Semikolon. Dann ist jeder Import sehr einfach.
ok gut, das mit der AltSoftSerial probiere ich mal aus.
hier nochmal der gesammte code.
das übertragen in excel ist für mich jetzt nicht so schlimm.
weiß jemand wie ich die Kurvenlage mit auf der karte anzeigen lassen kann?
Am geilsten wäre, wenn an der Stelle wo der Corser hinzeigt, ein kleines Motorrad von hinten gezeigt wird, welches sich je nach gemessener kurvenlage drecht.
#include <SoftwareSerial.h>
#include <SPI.h>
#include <SD.h>
#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"
const int chipSelect = 4;
char GPS;
MPU6050 mpu;
int16_t ax, ay, az;
int16_t gx, gy, gz;
SoftwareSerial mySerial(2, 3); // RX, TX ... the 10 is what matters based on my suggested wiring above
#define PMTK_SET_NMEA_UPDATE_1HZ "$PMTK220,1000*1F"
#define PMTK_SET_NMEA_UPDATE_5HZ "$PMTK220,200*2C"
#define PMTK_SET_NMEA_UPDATE_10HZ "$PMTK220,100*2F"
// turn on only the second sentence (GPRMC)
#define PMTK_SET_NMEA_OUTPUT_RMCONLY "$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29"
// turn on ALL THE DATA
//#define PMTK_SET_NMEA_OUTPUT_ALLDATA "$PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0*28"
void setup()
{
Wire.begin();
Serial.begin(115200);
Serial.println("Adafruit MTK3329 NMEA test!");
Serial.print("Initializing SD card...");
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
Serial.println("card initialized.");
Serial.println("Initialize MPU");
mpu.initialize();
Serial.println(mpu.testConnection() ? "Connected" : "Connection failed");
// 9600 NMEA is the default baud rate
mySerial.begin(9600);
// uncomment this line to turn on only the "minimum recommended" data for high update rates!
mySerial.println(PMTK_SET_NMEA_OUTPUT_RMCONLY);
// uncomment this line to turn on all the available data - for 9600 baud you'll want 1 Hz rate
//mySerial.println(PMTK_SET_NMEA_OUTPUT_ALLDATA);
// Set the update rate
// 1 Hz update rate
//mySerial.println(PMTK_SET_NMEA_UPDATE_1HZ);
// 5 Hz update rate- for 9600 baud you'll have to set the output to RMC only (see above)
mySerial.println(PMTK_SET_NMEA_UPDATE_5HZ);
// 10 Hz update rate - for 9600 baud you'll have to set the output to RMC only (see above)
//mySerial.println(PMTK_SET_NMEA_UPDATE_10HZ);
File dataFile = SD.open("GPS.txt", FILE_WRITE);
dataFile.println("");
dataFile.println("");
dataFile.println("");
dataFile.println("");
dataFile.println("##############################################################################################################");
dataFile.println("");
dataFile.println("#################");
dataFile.println("##Neue Messung###");
dataFile.println("#################");
dataFile.println("ax;ay;az;gx;gy;gz;ms");
dataFile.close();
}
/*
void loop() // run over and over
{
if (mySerial.available()) {
GPS = (char)mySerial.read();
Serial.print(GPS);
File dataFile = SD.open("GPS.txt", FILE_WRITE);
dataFile.print(GPS);
dataFile.close();
}
if (Serial.available()) {
mySerial.print((char)Serial.read());
}
}
*/
File dataFile;
void loop() // run over and over
{
if (mySerial.available()) {
GPS = (char)mySerial.read();
dataFile.print(GPS);
Serial.print(GPS);
if (GPS == '\n') // bei erkanntem Zeilenende
{
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
dataFile.print(ax); dataFile.print("\t"); Serial.print(ax); Serial.print("\t");
dataFile.print(ay); dataFile.print("\t"); Serial.print(ay); Serial.print("\t");
dataFile.print(az); dataFile.print("\t"); Serial.print(az); Serial.print("\t");
dataFile.print(gx); dataFile.print("\t"); Serial.print(gx); Serial.print("\t");
dataFile.print(gy); dataFile.print("\t"); Serial.print(gy); Serial.print("\t");
dataFile.print(gz); dataFile.print("\t"); Serial.print(gz); Serial.print("\t");
dataFile.print(millis()); dataFile.print("\t"); Serial.print(millis()); Serial.print("\t");
// hier ggf. Funktion aufrufen zur Ausgabe von X, Y, Z
dataFile.close(); // Datei schließen
dataFile = SD.open("GPS.txt", FILE_WRITE); // und sofort wieder öffnen
}
}
if (Serial.available()) {
mySerial.print((char)Serial.read());
}
}
Frek07:
ok gut, das mit der AltSoftSerial probiere ich mal aus.
Mit AltSoftSerial sollten die Datenfehler in der Aufzeichnung verschwinden.
Datenfehler bei gleichzeitiger Verwendung von SoftwareSerial und einer HardwareSerial-Schnittstelle sind ganz typisch und verschwinden, sobald Du auf AltSoftSerial umgestellt hast. Ist ja nicht viel Arbeit: Du mußt ja praktisch nur:
die AltSoftSerial Library ins richtige Verzeichnis installieren
die #include-Zeile zum Einbinden der Library ändern
den GPS-TX Pin an den AltSoftSerial-RX Pin (anstelle des SoftwarSerial-RX Pin) anschließen
Was mir sonst auffällt:
Dass in Deiner Aufzeichnung nun die Sensordaten und die GPS-$GPRMC Daten in einer Zeile immer um eine Sekunde zeitversetzt aufgezeichnet werden, ist Dir klar?
Du zeichnest wie folgt auf:
wenn eine $GPRMC-Zeile komplett aufgezeichnet und eine neue Zeile begonnen wurde
hole Sensordaten und schreibe sie in die neue Zeile
nach einer Sekunde: Die nächste $GPRMC-Zeile wird an die Messdaten drangehängt
D.h. die Messdaten vom Beschleunigungssensor am Anfang der Zeile sind immer bereits eine Sekunde alt, wenn die $GPRMC-Zeile ans Ende der von Dir aufgezeichneten Zeile geschrieben wird.