Difference between revisions of "SDGPSLogger"

From Bloominglabs
Jump to: navigation, search
(3 intermediate revisions by one user not shown)
Line 3: Line 3:
 
It is based on the Arduino with an SD card shield and an attached GPS.
 
It is based on the Arduino with an SD card shield and an attached GPS.
  
Here is the source code:
+
Here is the source code for the arduino:
 
<pre>
 
<pre>
 
/*
 
/*
Line 203: Line 203:
  
  
 +
</pre>
 +
 +
Here is the source code for a perl program that will read the data file on the SD card and generate a kml file that can be read by google earth:
 +
 +
Use it like this:
 +
 +
perl converter.pl < sd_data_file.txt > output.kml
 +
 +
<pre>
 +
#!/bin/perl
 +
 +
# Copyright (C) 2011 Jay Sissom
 +
#
 +
# This program is free software; you can redistribute it and/or
 +
# modify it under the terms of the GNU General Public License
 +
# as published by the Free Software Foundation; version 2
 +
# of the License.  THIS SOFTWARE IS RELEASED UNDER THE TERMS OF
 +
# VERSION 2 OF THE GPL LICENSE ONLY.
 +
#
 +
# This program is distributed in the hope that it will be useful,
 +
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 +
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +
# GNU General Public License for more details.
 +
#
 +
# You should have received a copy of the GNU General Public License
 +
# along with this program; if not, write to the Free Software
 +
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 +
#
 +
# http://www.gnu.org/licenses/gpl-2.0.html
 +
#
 +
# Jay Sissom jsissom@gmail.com
 +
 +
print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
 +
print "<kml xmlns=\"http://earth.google.com/kml/2.0\">\n";
 +
print "  <Document>\n";
 +
print "    <Placemark>\n";
 +
print "      <LineString>\n";
 +
print "        <coordinates>\n";
 +
 +
while ($line = <STDIN>) {
 +
  @data = split(/\t/,$line);
 +
  $latitude = $data[1]/100000;
 +
  $longitude = $data[0]/100000;
 +
 +
  print "          $latitude,$longitude,0\n";
 +
}
 +
 +
print "        </coordinates>\n";
 +
print "      </LineString>\n";
 +
print "      <Style>\n";
 +
print "        <LineStyle>\n";
 +
print "          <color>#ff0000ff</color>\n";
 +
print "          <width>5</width>\n";
 +
print "        </LineStyle>\n";
 +
print "      </Style>\n";
 +
print "    </Placemark>\n";
 +
print "  </Document>\n";
 +
print "</kml>\n";
 +
</pre>
 +
 +
Here is the source code for a ruby program to convert the text file to a kml file.  Put this into a file named tokml.rb and run it like this:
 +
 +
ruby tokml.rb input_file_name output_file_name
 +
 +
<pre>
 +
# Copyright (C) 2011 Jay Sissom
 +
#
 +
# This program is free software; you can redistribute it and/or
 +
# modify it under the terms of the GNU General Public License
 +
# as published by the Free Software Foundation; version 2
 +
# of the License.  THIS SOFTWARE IS RELEASED UNDER THE TERMS OF
 +
# VERSION 2 OF THE GPL LICENSE ONLY.
 +
#
 +
# This program is distributed in the hope that it will be useful,
 +
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 +
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +
# GNU General Public License for more details.
 +
#
 +
# You should have received a copy of the GNU General Public License
 +
# along with this program; if not, write to the Free Software
 +
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 +
#
 +
# http://www.gnu.org/licenses/gpl-2.0.html
 +
#
 +
# Jay Sissom jsissom@gmail.com
 +
 +
class ToKml
 +
  def generate_kml(input_file_name,output_file_name)
 +
    File.open(output_file_name,'w') do |out|
 +
      out.puts "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
 +
      out.puts "<kml xmlns=\"http://earth.google.com/kml/2.0\">"
 +
      out.puts "  <Document>"
 +
      out.puts "    <Placemark>"
 +
      out.puts "      <LineString>"
 +
      out.puts "        <coordinates>"
 +
 +
      File.open(input_file_name,'r') do |fl|
 +
        while line = fl.gets
 +
          data = line.split("\t")
 +
          latitude = data[1].to_f / 100000.0
 +
          longitude = data[0].to_f / 100000.0
 +
          out.puts "          #{latitude},#{longitude},0"
 +
        end
 +
      end
 +
 +
      out.puts "        </coordinates>";
 +
      out.puts "      </LineString>";
 +
      out.puts "      <Style>";
 +
      out.puts "        <LineStyle>";
 +
      out.puts "          <color>#ff0000ff</color>";
 +
      out.puts "          <width>5</width>";
 +
      out.puts "        </LineStyle>";
 +
      out.puts "      </Style>";
 +
      out.puts "    </Placemark>";
 +
      out.puts "  </Document>";
 +
      out.puts "</kml>";
 +
    end
 +
  end
 +
end
 +
 +
if __FILE__ == $0
 +
  if ARGV.length != 2
 +
    puts "Must pass the source file name and target file name on the command line"
 +
    exit(1)
 +
  end
 +
 +
  tk = ToKml.new
 +
  tk.generate_kml(ARGV[0],ARGV[1])
 +
end
 
</pre>
 
</pre>

Revision as of 17:01, 6 May 2011

The SD GPS logger will take data from a GPS and log it into a file on an SD card every 5 seconds.

It is based on the Arduino with an SD card shield and an attached GPS.

Here is the source code for the arduino:

/*
  SD gps datalogger
  
  This will log locations to a file on an SD card.

  Known bugs:
    If the code writes to the SD card at the same time you power down, it
    can corrupt the file system on the SD card.

  Pins:
    SD MOSI - pin 11
    SD CLK - pin 13
    SD CS - pin 8
    GPS serial out - pin 7
    GPS serial in - pin 6 (not needed)

  SD Shield:
    http://www.sparkfun.com/products/9802
 
  GPS:
    http://www.byonics.com/tinytrak/gps.php (GPS2)
 
  Required Libraries:
    NewSoftSerial - http://arduiniana.org/libraries/newsoftserial/
    TinyGPS - http://arduiniana.org/libraries/tinygps/

Copyright (C) 2011 Jay Sissom

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.  THIS SOFTWARE IS RELEASED UNDER THE TERMS OF
VERSION 2 OF THE GPL LICENSE ONLY.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

http://www.gnu.org/licenses/gpl-2.0.html

Jay Sissom jsissom@gmail.com

 */
#include <SD.h>
#include <NewSoftSerial.h>
#include <TinyGPS.h>

// GPS and serial objects
TinyGPS gps;
NewSoftSerial nss(7,6,true);

// GPS data (global so we don't need to pass them around)
long lat, lon;
int year;
byte month, day, hour, minute, second, hundredths;
unsigned long age, date, time, chars, speed;
bool moving = true;

// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.
const int chipSelect = 8;

void setup() {
  Serial.begin(9600);
  Serial.print("Initializing SD card...");

  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
  
  // 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.");

  nss.begin(4800);
  
  Serial.println("GPS initialized.");
}

void loop() {
  bool newdata = false;
  unsigned long start = millis();

  // Every 5 seconds we write an update (if we are moving)
  while (millis() - start < 5000) {
    if ( feedgps() ) {
      newdata = true;
    }
  }

  if (newdata) {
    speed = gps.speed();
    gps.get_position(&lat, &lon, &age);
    feedgps();
    gps.get_datetime(&date, &time, &age);
    feedgps();
    gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
    feedgps();

    // Only write data if we are moving
    if ( moving ) {
      writeData();
    }
    moving = ( speed > 85 );
  } else {
    Serial.println("No GPS data during the last 5 seconds");
  }
}

bool feedgps() {
  while (nss.available()) {
    if (gps.encode(nss.read()))
      return true;
  }
  return false;
}

void writeData() {
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    feedgps();
    dataFile.print(lat);
    dataFile.print("\t");
    dataFile.print(lon);
    dataFile.print("\t");
    dataFile.print(gps.altitude());
    dataFile.print("\t");
    feedgps();
    dataFile.print(year);
    dataFile.print("\t");
    dataFile.print(static_cast<int>(month));
    dataFile.print("\t");
    dataFile.print(static_cast<int>(day));
    dataFile.print("\t");
    dataFile.print(static_cast<int>(hour));
    feedgps();
    dataFile.print("\t");
    dataFile.print(static_cast<int>(minute));
    dataFile.print("\t");
    dataFile.print(static_cast<int>(second));
    dataFile.print("\t");
    dataFile.print(gps.course());
    dataFile.print("\t");
    dataFile.print(speed);
    dataFile.print("\t");
    dataFile.println(age);
    feedgps();
    dataFile.close();
  } else {
    Serial.println("error opening datalog.txt");
  } 

  // print to the serial port too:
  feedgps();
  Serial.print(lat);
  Serial.print("\t");
  Serial.print(lon);
  Serial.print("\t");
  Serial.print(gps.altitude());
  Serial.print("\t");
  feedgps();
  Serial.print(year);
  Serial.print("\t");
  Serial.print(static_cast<int>(month));
  Serial.print("\t");
  Serial.print(static_cast<int>(day));
  Serial.print("\t");
  Serial.print(static_cast<int>(hour));
  feedgps();
  Serial.print("\t");
  Serial.print(static_cast<int>(minute));
  Serial.print("\t");
  Serial.print(static_cast<int>(second));
  Serial.print("\t");
  Serial.print(gps.course());
  Serial.print("\t");
  Serial.print(gps.speed());
  Serial.print("\t");
  Serial.println(age);
  feedgps();
}


Here is the source code for a perl program that will read the data file on the SD card and generate a kml file that can be read by google earth:

Use it like this:

perl converter.pl < sd_data_file.txt > output.kml

#!/bin/perl

# Copyright (C) 2011 Jay Sissom
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 2
# of the License.  THIS SOFTWARE IS RELEASED UNDER THE TERMS OF
# VERSION 2 OF THE GPL LICENSE ONLY.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
# 
# http://www.gnu.org/licenses/gpl-2.0.html
# 
# Jay Sissom jsissom@gmail.com

print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
print "<kml xmlns=\"http://earth.google.com/kml/2.0\">\n";
print "  <Document>\n";
print "    <Placemark>\n";
print "      <LineString>\n";
print "        <coordinates>\n";

while ($line = <STDIN>) {
  @data = split(/\t/,$line);
  $latitude = $data[1]/100000;
  $longitude = $data[0]/100000;

  print "          $latitude,$longitude,0\n";
}

print "        </coordinates>\n";
print "      </LineString>\n";
print "      <Style>\n";
print "        <LineStyle>\n";
print "          <color>#ff0000ff</color>\n";
print "          <width>5</width>\n";
print "        </LineStyle>\n";
print "      </Style>\n";
print "    </Placemark>\n";
print "  </Document>\n";
print "</kml>\n";

Here is the source code for a ruby program to convert the text file to a kml file. Put this into a file named tokml.rb and run it like this:

ruby tokml.rb input_file_name output_file_name

# Copyright (C) 2011 Jay Sissom
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 2
# of the License.  THIS SOFTWARE IS RELEASED UNDER THE TERMS OF
# VERSION 2 OF THE GPL LICENSE ONLY.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
# 
# http://www.gnu.org/licenses/gpl-2.0.html
# 
# Jay Sissom jsissom@gmail.com

class ToKml
  def generate_kml(input_file_name,output_file_name)
    File.open(output_file_name,'w') do |out|
      out.puts "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
      out.puts "<kml xmlns=\"http://earth.google.com/kml/2.0\">"
      out.puts "  <Document>"
      out.puts "    <Placemark>"
      out.puts "      <LineString>"
      out.puts "        <coordinates>"

      File.open(input_file_name,'r') do |fl|
        while line = fl.gets
          data = line.split("\t")
          latitude = data[1].to_f / 100000.0
          longitude = data[0].to_f / 100000.0
          out.puts "          #{latitude},#{longitude},0"
        end
      end

      out.puts "        </coordinates>";
      out.puts "      </LineString>";
      out.puts "      <Style>";
      out.puts "        <LineStyle>";
      out.puts "          <color>#ff0000ff</color>";
      out.puts "          <width>5</width>";
      out.puts "        </LineStyle>";
      out.puts "      </Style>";
      out.puts "    </Placemark>";
      out.puts "  </Document>";
      out.puts "</kml>";
    end
  end
end

if __FILE__ == $0
  if ARGV.length != 2
    puts "Must pass the source file name and target file name on the command line"
    exit(1)
  end

  tk = ToKml.new
  tk.generate_kml(ARGV[0],ARGV[1])
end
Personal tools