Help with write & read data from arduino sdcard

Hello forum member
i am newbie to arduino and programming
with the help from forum member i build a nice tool for light aviation (paramotor/paragliding/hang gliding)

GPS that show the Ground speed and the direction in real time

What i am trying to do now is :
To write the GPS variables (speed+direction/ heading) to sd card in a 1 minute loop
something like this :

speed Heading
30 180
32 188
35 190
10 020
8 010

from the data i can see that my lowest speed is 8 kmh and direction 010
the ide is to calibrate the device with 360 degree turn and then run a query to search for the lowest speed and direction
and display the data to lcd screen
Can get help with the code or example how to write the data in array and how to query for the data
Many appreciate for the help

i attached the code and picture of the device
Thanks in advance
Itay

#include <SoftwareSerial.h>
#include <Wire.h>
#include <TinyGPS.h>
#include <LiquidCrystal_I2C.h>

// start data loger
#include <SD.h>
#include <SPI.h>

////// end data loger
static const int RXPin = 4, TXPin = 3;

/* This sample code demonstrates the normal use of a TinyGPS object.
It requires the use of SoftwareSerial, and assumes that you have a
4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
TinyGPS gps;
SoftwareSerial ss(RXPin, TXPin);

static void smartdelay(unsigned long ms);
static void print_float(float val, float invalid, int len, int prec);
static void print_int(unsigned long val, unsigned long invalid, int len);
static void print_date(TinyGPS &gps);
static void print_str(const char *str, int len);
float TakeoffLA ;
float TakeoffLO ;
int CS_PIN = 10;
File GPSDATA;
void Takeofflocation()
{

}

void setup()
{
Serial.begin(115200);
lcd.begin(20,4);

ss.begin(9600);
for(int i = 0; i< 3; i++)
{

lcd.backlight();
delay(250);
lcd.noBacklight();
delay(250);
}
lcd.backlight(); // finish with backlight on
delay(1000);
float flat , flon;
unsigned long age, date, time, chars = 0;
unsigned short sentences = 0, failed = 0;
gps.f_get_position(&flat ,&flon, &age) ;
// delay(1000);
SD.begin(CS_PIN);

TakeoffLA = flat;
TakeoffLO = flon;
}

void loop()
{
float flat, flon;
unsigned long age, date, time, chars = 0;
unsigned short sentences = 0, failed = 0;
gps.f_get_position(&flat, &flon, &age);
print_float(gps.f_speed_kmph(), TinyGPS::GPS_INVALID_F_SPEED, 6, 2);
print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
float GPSSPEED = gps.f_speed_kmph() ;
//TakeoffLA = flat;
//TakeoffLO = flon;

float COURSE = gps.f_course();
float GPSALT = gps.f_altitude() ;
float GPSALT1 = round(GPSALT*10)/1000;
print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0xFFFFFFFF : (unsigned long)TinyGPS::distance_between(flat, flon, TakeoffLA, TakeoffLO) / 1000, 0xFFFFFFFF, 9);
float Distance = (flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0xFFFFFFFF : (unsigned long)TinyGPS::distance_between(flat, flon, TakeoffLA, TakeoffLO) / 1000, 0xFFFFFFFF, 9);
float Bearing = (flat == TinyGPS::GPS_INVALID_F_ANGLE ? TinyGPS::GPS_INVALID_F_ANGLE : TinyGPS::course_to(flat, flon, TakeoffLA, TakeoffLO), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
GPSDATA= SD.open("GPSData.txt",FILE_WRITE);
if (GPSDATA) {
gps.stats(&chars, &sentences, &failed);
Serial.println();
Serial.println("GPS-GROUND SPEED IS :");
Serial.println(GPSSPEED);
Serial.println("GPS Takeofflocation LAT");
Serial.println(TakeoffLA);
Serial.println("GPS Takeofflocation LON");
Serial.println(TakeoffLO);
Serial.println("GPS CORDINATE LAT NOW");
Serial.println(flat);
Serial.println("GPS CORDINATE LON NOW");
Serial.println(flon);
Serial.println("Distance from takeoff");
// GPSDATA.print("GPSSPEED");
// GPSDATA.println("SPEED");
GPSDATA.print("S");
GPSDATA.print(GPSSPEED);
GPSDATA.print("H");
GPSDATA.print(COURSE);

// GPSDATA.println("------------");
// GPSDATA.println("COURSE");
// GPSDATA.println(COURSE);
GPSDATA.close();
}
if (flat == TinyGPS::GPS_INVALID_F_ANGLE)
{
// lcd.print("N/A");
}
else
{
unsigned long distance = TinyGPS::distance_between(flat, flon, TakeoffLA, TakeoffLO) / 1000;
if (distance!= 0xFFFFFFFF)
{

lcd.setCursor(10,3);
// lcd.print(distance-13214);
lcd.print(distance);
print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0xFFFFFFFF : (unsigned long)TinyGPS::distance_between(flat, flon, TakeoffLA, TakeoffLO) / 1000, 0xFFFFFFFF, 9);
}
else
{

lcd.print(F("Invalid distance"));
}
}

//float Bearing = (flat == TinyGPS::GPS_INVALID_F_ANGLE ? TinyGPS::GPS_INVALID_F_ANGLE : TinyGPS::course_to(flat, flon, TakeoffLA, TakeoffLO), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);

if (flat == TinyGPS::GPS_INVALID_F_ANGLE)
{
lcd.setCursor(13,1);
// lcd.print("N/A");
}

else
{
unsigned long course_to1 = TinyGPS::course_to(flat, flon, TakeoffLA, TakeoffLO);
if (1!= 2)

lcd.setCursor(9,1);
lcd.print(course_to1);

}

//print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0xFFFFFFFF : (unsigned long)TinyGPS::distance_between(flat, flon, TakeoffLA, TakeoffLO) / 1000, 0xFFFFFFFF, 9);
Serial.println(" ");
Serial.println("Bearing");
print_float(flat == TinyGPS::GPS_INVALID_F_ANGLE ? TinyGPS::GPS_INVALID_F_ANGLE : TinyGPS::course_to(flat, flon, TakeoffLA, TakeoffLO), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
Serial.println(" ");
Serial.println("bearing from variable same lcd");

Serial.println( Bearing);
smartdelay(1000);
lcd.setCursor(0,0);
lcd.print("Speed");
lcd.setCursor(9,0);
lcd.print(GPSSPEED);
lcd.setCursor(17,0);
lcd.print("Kmh");
lcd.setCursor(0,2);
lcd.print("Altitude");
lcd.setCursor(10,2);
lcd.print(GPSALT);
lcd.setCursor(13,2);
lcd.print(" Meter");
lcd.setCursor(0,1);
// lcd.print("Course");
// Serial.println(gps.altitude.meters())
lcd.print("Bearing");
// lcd.setCursor(10,1);
lcd.setCursor(12,1);
lcd.print((char)223);
lcd.setCursor(14,1);
lcd.print("H");
/// H for heading
lcd.setCursor(16,1);
lcd.print(COURSE);
lcd.setCursor(19,1);
lcd.print((char)223);
lcd.setCursor(0,3);
lcd.print("Takeoff");
lcd.setCursor(18,3);
lcd.print("Km");

}

static void smartdelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (ss.available())
gps.encode(ss.read());
} while (millis() - start < ms);
}

static void print_float(float val, float invalid, int len, int prec)
{
if (val == invalid)
{
while (len-- > 1)
Serial.print('*');
Serial.print(' ');
}
else
{
Serial.print(val, prec);
int vi = abs((int)val);
int flen = prec + (val < 0.0 ? 2 : 1); // . and -
flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
for (int i=flen; i<len; ++i)
Serial.print(' ');
}
smartdelay(0);
}

static void print_int(unsigned long val, unsigned long invalid, int len)
{
char sz[32];
if (val == invalid)
strcpy(sz, "*******");
else
sprintf(sz, "%ld", val);
sz[len] = 0;
for (int i=strlen(sz); i<len; ++i)
sz = ' ';

  • if (len > 0)*
  • sz[len-1] = ' ';*
  • Serial.print(sz);*
  • smartdelay(0);*
    }
    static void print_date(TinyGPS &gps)
    {
  • int year;*
  • byte month, day, hour, minute, second, hundredths;*
  • unsigned long age;*
  • gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);*
  • if (age == TinyGPS::GPS_INVALID_AGE)*
    _ Serial.print("********** ******** ");_
  • {*
  • char sz[32];*
  • sprintf(sz, "%02d/%02d/%02d %02d:%02d:%02d ",*
  • month, day, year, hour, minute, second);*
  • Serial.print(sz);*
  • }*
  • print_int(age, TinyGPS::GPS_INVALID_AGE, 5);*
  • smartdelay(0);*
    }
    static void print_str(const char *str, int len)
    {
  • int slen = strlen(str);*
  • for (int i=0; i<len; ++i)*
    _ Serial.print(i<slen ? str : ' ');_
    * smartdelay(0);*
    }

Can get help with the code or example how to write the data in array

Write what data in what kind of array?

Does your code really look like that? There are stickies at the top of the forum that you are supposed to read BEFORE you post here. Either you didn't bother reading them, or you thought that they didn't apply to you. If you didn't read them, why should we bother trying to help you?

If you did, but thought they didn't apply to you, you thought wrong.

Attached device with the data

Sorry i did read the forum rules , but maybe i didnt mark the code properly
Not have much experience with posting questions in the forum

For your question :
The data i want to write to sd card is the speed and COURSE
Regards
Itay

GPSDATA= SD.open("GPSData.txt",FILE_WRITE);
if (GPSDATA) {
gps.stats(&chars, &sentences, &failed);
Serial.println();
Serial.println("GPS-GROUND SPEED IS :");
Serial.println(GPSSPEED);
Serial.println("GPS Takeofflocation LAT");
Serial.println(TakeoffLA);
Serial.println("GPS Takeofflocation LON");
Serial.println(TakeoffLO);
Serial.println("GPS CORDINATE LAT NOW");
Serial.println(flat);
Serial.println("GPS CORDINATE LON NOW");
Serial.println(flon);
Serial.println("Distance from takeoff");

[color=red][b]GPSDATA.print("S");
GPSDATA.print(GPSSPEED);
 GPSDATA.print("H");
GPSDATA.print(COURSE);[/b][/color]

// GPSDATA.println("------------");
//  GPSDATA.println("COURSE");
//  GPSDATA.println(COURSE);
GPSDATA.close();
}

itaym:
Sorry i did read the forum rules , but maybe i didnt mark the code properly
Not have much experience with posting questions in the forum

For your question :
The data i want to write to sd card is the speed and COURSE
Regards
Itay

GPSDATA= SD.open("GPSData.txt",FILE_WRITE);

if (GPSDATA) {
gps.stats(&chars, &sentences, &failed);
Serial.println();
Serial.println("GPS-GROUND SPEED IS :");
Serial.println(GPSSPEED);
Serial.println("GPS Takeofflocation LAT");
Serial.println(TakeoffLA);
Serial.println("GPS Takeofflocation LON");
Serial.println(TakeoffLO);
Serial.println("GPS CORDINATE LAT NOW");
Serial.println(flat);
Serial.println("GPS CORDINATE LON NOW");
Serial.println(flon);
Serial.println("Distance from takeoff");

GPSDATA.print("S");
GPSDATA.print(GPSSPEED);
GPSDATA.print("H");
GPSDATA.print(COURSE);

// GPSDATA.println("------------");
//  GPSDATA.println("COURSE");
//  GPSDATA.println(COURSE);
GPSDATA.close();
}

I would use comma-separated values so that they will be easier parse when you read the data back.
Look at reply #4 of Read CSV or TXT from SD card into string or array - Storage - Arduino Forum on how to read back two values separated by a comma which can be expanded.

Thanks for the advice
this what i did use CSV to separate the value speed & direction
Now i have them in a file line by line

void loop()
{
  float flat, flon;
  unsigned long age, date, time, chars = 0;
  unsigned short sentences = 0, failed = 0;
  gps.f_get_position(&flat, &flon, &age);
  print_float(gps.f_speed_kmph(), TinyGPS::GPS_INVALID_F_SPEED, 6, 2);
  print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
 float  GPSSPEED = gps.f_speed_kmph() ;
//TakeoffLA = flat;
//TakeoffLO = flon;

float COURSE = gps.f_course();
float   GPSALT = gps.f_altitude() ;
float GPSALT1 = round(GPSALT*10)/1000;
print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0xFFFFFFFF : (unsigned long)TinyGPS::distance_between(flat, flon, TakeoffLA, TakeoffLO) / 1000, 0xFFFFFFFF, 9);
float Distance = (flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0xFFFFFFFF : (unsigned long)TinyGPS::distance_between(flat, flon, TakeoffLA, TakeoffLO) / 1000, 0xFFFFFFFF, 9);
float Bearing = (flat == TinyGPS::GPS_INVALID_F_ANGLE ? TinyGPS::GPS_INVALID_F_ANGLE : TinyGPS::course_to(flat, flon, TakeoffLA,  TakeoffLO), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);

dataString = String(GPSSPEED) + "," + String(COURSE) ; // convert to CSV


GPSDATA= SD.open("GPSData.csv",FILE_WRITE);
if (GPSDATA) {
  gps.stats(&chars, &sentences, &failed);
  /*
  Serial.println();
  Serial.println("GPS-GROUND SPEED IS :");
  Serial.println(GPSSPEED);
  Serial.println("GPS Takeofflocation LAT");
  Serial.println(TakeoffLA);
  Serial.println("GPS Takeofflocation LON");
  Serial.println(TakeoffLO);
  Serial.println("GPS CORDINATE LAT NOW");
  Serial.println(flat);
  Serial.println("GPS CORDINATE LON NOW");
  Serial.println(flon);
  Serial.println("Distance from takeoff");
*/
GPSDATA.println(dataString);

 GPSDATA.close();
}

can you help were i need to place the code for reading , after the GPSDATA.close in a new function ?
this is how my output file look like now
The speed is low because the gps not in a move

speed heading

1.63,279.13
0.78,265.68
0.94,273.58
0.31,140.63
0.30,161.19
0.41,137.69
0.78,97.62
0.61,106.00
0.80,103.00
0.80,108.33
0.33,106.24
0.20,113.11
0.13,55.94
0.20,200.34
0.15,184.66
0.19,162.61
0.24,118.59
0.28,96.79
0.28,96.79
0.48,70.29
0.57,80.32
0.35,30.80
0.28,157.89
0.19,148.60
0.13,71.41
0.35,127.66
0.35,127.66
0.39,266.87
0.20,119.45
0.39,226.12
0.33,214.33
0.24,190.64
0.11,255.53
0.04,312.84
0.15,268.38
0.43,220.69
0.37,243.17
0.13,201.75
0.06,341.57
0.26,211.28
0.57,233.10
0.37,217.72
0.15,151.20
0.26,133.19
0.09,216.30
0.07,262.27
0.31,225.78
0.19,222.54
0.04,258.05
0.17,232.83
0.11,163.25
0.28,333.88
0.11,58.94
0.20,214.78
0.37,246.52
0.33,240.24
0.28,226.79
0.30,232.63
0.24,197.09
0.11,240.61
0.22,176.10
0.31,156.00
0.09,219.03
0.39,225.15
0.24,189.11
0.30,158.02
0.17,177.67
0.30,188.32
0.26,206.31
0.35,231.06
0.61,246.25
0.59,238.70
0.22,225.44
0.39,259.64
0.13,116.85
0.28,243.18
0.19,145.63
0.07,193.57
0.33,266.33

Why do you want to then read that file on the Arduino? What, EXACTLY, will trigger the block of code to read that file?

You can see the device out put screen in the picture (with out the sd card)
i must to do every thing with the same arduino board becouse i use it for paramotor and it mount's on a trike

Reading a bunch of historical data from the SD card, and pretending it represents real-time data doesn't make sense to me. Showing the latest data does. Writing that same data to the SD card also makes sense.

Reading the data that you have written, so you can show the data from the last record does not.

Let me explain how i plan to use the device
when you want to land with paragliding , you want to land into the wind (headwind)
Let say that i will calibrate the device with 360 turn and log the data to the sd card.
Now my last 100 raw 1 (1 raw per second)hold history data about my lowest speed and the direction
i can show them to the display evrey 1 minutes

with out tracking the real time display all the time when flying
The block will run in 1 / 2 minutes Loop

Hello
I find this code in the forum
it reads the data and print the values

#include <SPI.h>
#include <SD.h>
File file;

bool readLine(File &f, char* line, size_t maxLen) {
 for (size_t n = 0; n < maxLen; n++) {
   int c = f.read();
   if ( c < 0 && n == 0) return false;  // EOF
   if (c < 0 || c == '\n') {
     line[n] = 50;
     return true;
   }
   line[n] = c;
 }
 return false; // line too long
}

bool readVals(long* v1, long* v2) {
 char line[40], *ptr, *str;
 if (!readLine(file, line, sizeof(line))) {
   return false;  // EOF or too long
 }
 *v1 = strtol(line, &ptr, 10);
 if (ptr == line) return false;  // bad number if equal
 while (*ptr) {
   if (*ptr++ == ',') break;
 }
 *v2 = strtol(ptr, &str, 10);
 return str != ptr;  // true if number found
}

void setup(){
 long x, y;
 Serial.begin(9600);
 if (!SD.begin(SS)) {
   Serial.println("begin error");
   return;
 }
 file = SD.open("TEST.CSV", FILE_READ);
 if (!file) {
   Serial.println("open error");
   return;
 }
 while (readVals(&x, &y)) {

   Serial.print("x: ");
   Serial.println(x);
   Serial.print("y: ");
   Serial.println(y);
   Serial.println();
 }
 Serial.println("Done");
}
void loop() {}

The problem now i am trying to solve is how to ** search for the lowest value in the list and print it only**
Thanks in advance for any help
Itay

This is output from the example text file
y: 274

x: 1050
y: 280

x: 1051
y: 265

x: 1052
y: 270

x: 1053
y: 271

x: 1054
y: 272

x: 1055
y: 256

x: 1056
y: 248

x: 1057
y: 262

x: 1058
y: 259

x: 1059
y: 263

x: 1060
y: 263

x: 1061
y: 262

x: 1062
y: 265

x: 1063
y: 245

x: 1064
y: 240

x: 1065
y: 251

x: 1066
y: 228

x: 1067
y: 0

x: 1068
y: 302

x: 1069
y: 232

x: 1070
y: 325

x: 1071
y: 241

x: 1072
y: 229

x: 1073
y: 286

x: 1074
y: 242

x: 1075
y: 226

x: 1076
y: 166

x: 1077
y: 166

x: 1078
y: 172

x: 1079
y: 136

x: 1080
y: 52

x: 1081
y: 52

x: 1082
y: 293

x: 1083
y: 331

x: 1084
y: 28

x: 1085
y: 118

x: 1086
y: 81

x: 1087
y: 79

x: 1088
y: 63

x: 1089
y: 109

x: 1090
y: 119

x: 1091
y: 264

x: 1092
y: 266

x: 1093
y: 259

x: 1094
y: 273

x: 1095
y: 255

x: 1096
y: 294

x: 1097
y: 279

x: 1098
y: 279

x: 1099
y: 253

x: 1100
y: 268

The problem now i am trying to solve is how to search for the lowest value in the list and print it only

You don't have a list. You get a series of values, two at a time, from the file. You print them. You overwrite them with the next set of values.

You could create two new variables, lowestX, lowestY. When reading the first set of values from the file, set lowestX and lowestY to those values. After that, compare the values just read to the current lowest values. If the current values are lower, replace the lowest values with the current values.

One thing to consider. In this set of data:
x: 1092
y: 266

x: 1093
y: 259

What are the lowest values?

The number are just test i make , i place them manually in the text file .

This numbers are from a test i make today with my bike in the city (the lowest speed i get when driving in traffic jam )
Can see the speed and the direction i drive separated by coma

In the first raw can see that i drive at speed 1.00 kmh to west direction 259.54
in the last raw can see that my speed was 9.87 and to East direction 108.25
what i want to inquire the data in the text file is :

To what direction i drive in the slowest speed !!!

I Think need to load the file into 2 different array and then make a query
but i dont know how to write the code and how to do it

1.00,259.54
1.06,243.39
1.17,273.80
1.20,284.44
1.20,79.67
0.89,68.87
0.70,40.69
0.37,328.42
0.59,333.28
2.94,350.99
6.70,352.93
26.69,345.15
30.71,345.53
33.85,344.30
36.63,343.37
39.26,341.99
39.45,342.89
39.80,341.11
37.52,340.89
35.73,341.82
33.93,344.16
31.60,345.23
31.21,342.11
31.93,342.20
30.24,343.23
28.17,345.32
27.32,350.00
26.52,354.08
26.58,356.01
26.58,354.27
26.21,358.46
25.26,1.07
24.63,3.30
25.65,10.53
26.61,15.86
28.52,19.80
30.93,21.77
31.43,30.04
30.63,26.33
28.67,28.50
26.63,32.50
24.35,37.13
23.84,36.71
25.52,34.08
26.91,34.53
26.78,30.60
25.76,27.11
22.04,26.48
20.43,34.05
19.78,34.71
23.65,33.62
24.21,32.89
23.76,35.46
24.22,33.40
23.59,31.61
22.21,36.18
16.02,39.17
12.70,39.97
9.63,13.78
5.87,355.50
5.48,343.02
7.54,336.03
8.32,325.66
11.09,325.02
9.83,322.68
10.98,311.86
18.95,293.39
21.15,296.15
22.58,298.82
25.71,299.32
25.85,301.86
26.32,302.67
25.71,302.03
26.28,297.01
28.11,294.04
29.87,293.28
32.82,296.43
32.43,297.31
34.08,296.42
32.32,298.85
32.19,306.45
32.28,310.76
30.85,302.56
30.47,300.96
29.78,304.40
28.89,311.23
28.87,313.11
18.56,316.60
18.11,324.48
14.65,330.29
13.17,336.59
11.83,338.01
9.30,352.39
9.24,357.07
9.96,352.11
10.91,333.55
13.00,334.71
8.13,8.25
6.80,24.18
5.07,24.18
3.13,24.18
4.20,24.18
7.24,78.75
8.93,90.22
11.87,104.39
14.20,110.23
21.89,120.90
24.91,120.54
26.84,115.45
27.48,112.84
29.15,115.79
26.11,116.55
24.85,117.37
24.24,110.37
22.39,107.48
20.35,120.20
19.32,128.89
17.11,125.57
13.43,123.98
10.32,114.25
5.82,115.68
3.82,115.68
5.00,115.68
5.83,126.66
8.11,142.48
9.22,132.35
9.20,131.51
7.72,127.38
5.89,113.62
4.72,113.62
0.30,113.62
0.30,113.62
0.63,113.62
8.83,112.99
9.87,108.25

I Think need to load the file into 2 different array

Why? Why can't you simply determine that any given value is lower, or not, than the first value?

If the data in the file is speed and direction, with one value for each per record, when you read the first record, that is the lowest speed, and the direction associated with that speed. When you read the next record, the speed for that record is either faster, in which case the direction doesn't matter, or it is slower, in which case that is the lowest speed, and you know the direction associated with that speed. Repeat for all the records, and you know the lowest speed and its associated direction using only 4 variables (currentSpeed (from the record just read), lowestSpeed, currentDirection (from the record just read), and directionAtLowestSpeed) and an array to read a record into.

can you write a small code for example to start with ?
i will try to make changes and understand how it work
if it's not complected ...
Thanks and many appreciate for the help !