[GPRS GPS] Tracking device

Summary

I decided to make the “Sherlock I” which essentially is a GPS monitor that parses the info via GPRS to an FTP server, which converts it to a website with a simple PHP script to a google maps website-thingy, so that i can monitor ‘stuff’ real-time. I tried it a few times and it worked well. Then i got bored and forgot about it. But not before i made a youtube video from it!

Parts List

  • Arduino or equivalent
  • FTP server
  • Sim card with GPRS option (i used my unlimited iPhone one!)
  • GPS sensor with serial interface (I used a FALCOM FSA03)
  • GPRS Hilo/SAGEM module (€40 from Libelium)

Impression

Code



/*
*
* Copyright (C) 2010 Tim Zaman
* http://www.hollandshoogte.nl
*
*/

#define GPS_PIN_1 9 // GPS serial pin RX
#define GPS_PIN_2 8 // GPS serial pin TX
#define CHECKPIN 13 // Pin that lights up when things are checked
#define GPSRATE 4800 // GPS baud rate
#include
#include
#include
#define BUFFERSIZE 100 // How many bytes of input to buffer from the GPS?
#define ENDLN "\r\n" // SD

int onModulePin = 2; // the pin to switch on the module (without press on button)
SoftwareSerial mySerial = SoftwareSerial(GPS_PIN_1, GPS_PIN_2); //(rx,tx)

//GPS var
int numSats = 0;
int fixType = 0;
int time[] = {
0, 0, 0};
double latitude = 0.0;
double longitude = 0.0;
long altitude = 0;
long maxAlt = 0;
int speed = 0;
int txCount = 0;

int ExOnce = 0;
int FalcomCheck = 0;
int LogCheck =0;
unsigned long GpsOffTime = 0; // Tijd dat GPS uit gaat
unsigned long SmsStart = 0; // SMS-time

char buffer[BUFFERSIZE];

void switchModule(){ // Funtion to switch the module ON
digitalWrite(onModulePin,HIGH);
delay(2000);
digitalWrite(onModulePin,LOW);
delay(2000);
Serial.print("AT+CPIN=");
Serial.print(34,BYTE);
Serial.print("1337");
Serial.println(34,BYTE);
delay(2000);
}

void setup(){

pinMode(onModulePin, OUTPUT);
Serial.begin(19200); // the GPRS baud rate
switchModule(); // swith the module ON

for (int i=0;i<2;i++){ // Wait 20 sec for connection delay(10000); } mySerial.begin(4800); pinMode(GPS_PIN_1, INPUT); pinMode(GPS_PIN_2, OUTPUT); pinMode(7, OUTPUT); pinMode(13, OUTPUT); digitalWrite(7, HIGH); } void loop(){ Serial.flush(); // Get a GGA string from the GPS, // check if it's a valid fix, and extract the data getNMEA("$GPGGA"); delay(100); numSats = getSats(); fixType = getFixType(); // Make sure we have a valid fix if (fixType != 0) { getTime(time); latitude = getLat(); longitude = getLong(); altitude = getAlt(); // Keep track of the maximum altitude } // Convert lat & long into strings char latString[12]; char longString[12]; doubleToString(latitude, 4, latString); doubleToString(longitude, 4, longString); sprintf(buffer, "%02d:%02d:%02d,%s,%s,%ld", time[0], time[1], time[2], latString, longString, altitude); Serial.println(buffer); if (fixType > 0) {
digitalWrite(13, HIGH);

if (ExOnce==0){

ExOnce=1;
//sendsms();
logftpfirst();
// for (int i=0;i<3;i++){ // Wait 30 sec for connection
// delay(10000);
//}
}
else{
logftp();
}
}

delay(200);
}

void sendsms(){
Serial.println("AT+CMGF=1"); // set the SMS mode to text
delay(500);
Serial.print("AT+CMGS="); // send the SMS the number
Serial.print(34,BYTE); // send the " char
Serial.print("0613653490"); // send the number change ********* by the actual number
Serial.println(34,BYTE); // send the " char
delay(1500);
Serial.print("Hi Tim, i'm uploading now. X, your computer"); // the SMS body
delay(500);
Serial.print(0x1A,BYTE); // end of message command 1A (hex)

delay(20000);

}

void logftpfirst(){
Serial.println("AT&k3"); // Flow activate

delay(1000);
Serial.print("AT+KCNXCFG=0,"); // connect to GPRS
Serial.print(34,BYTE);
Serial.print("GPRS");
Serial.print(34,BYTE);
Serial.print(",");
Serial.print(34,BYTE);
Serial.print("internet");
Serial.print(34,BYTE);
Serial.print(",");
Serial.print(34,BYTE);
Serial.print(34,BYTE);
Serial.print(",");
Serial.print(34,BYTE);
Serial.println(34,BYTE);

delay(1000);
Serial.println("AT+KCNXTIMER=0,60,2,70"); // set timers

delay(1000);
Serial.println("AT+CGATT=1"); //Network check

delay(1000);
Serial.print("AT+KFTPCFG=0,"); //FTP config/connect
Serial.print(34,BYTE);
Serial.print("ftp.timbobel.nl"); //ftp adres
Serial.print(34,BYTE);
Serial.print(",");
Serial.print(34,BYTE);
Serial.print("timbobel.nl"); //password
Serial.print(34,BYTE);
Serial.print(",");
Serial.print(34,BYTE);
Serial.print("<>");
Serial.print(34,BYTE);
Serial.println(",21,0");

delay(500);
Serial.print("AT+KPATTERN="); //Zet EOF pattern (als stop na data)
Serial.print(34,BYTE);
Serial.print("--EOF--Pattern--");
Serial.println(34,BYTE);

delay(500);
Serial.print("AT+KFTPSND=0,,");
Serial.print(34,BYTE);
Serial.print("log"); //Directory binnen de ftp
Serial.print(34,BYTE);
Serial.print(",");
Serial.print(34,BYTE);
Serial.print("pol.txt"); //Textfile
Serial.print(34,BYTE);
Serial.println(",0");

delay(12000); //Wachten tot hij is verbonden...

Serial.print(buffer); //Hier zit de info in
Serial.println("--EOF--Pattern--"); //Data verzenden
delay(12000);

}

void logftp(){

delay(500);
Serial.print("AT+KFTPSND=0,,");
Serial.print(34,BYTE);
Serial.print("log"); //Directory binnen de ftp
Serial.print(34,BYTE);
Serial.print(",");
Serial.print(34,BYTE);
Serial.print("pol.txt"); //Textfile
Serial.print(34,BYTE);
Serial.println(",0");

delay(5000); //Wachten tot hij is verbonden...

Serial.print(buffer); //Hier zit de info in
Serial.println("--EOF--Pattern--"); //Data verzenden
delay(4000);

}

// ------- GPS Parsing ----------

// Reads a line from the GPS NMEA serial output
// Give up after trying to read 1000 bytes (~2 seconds)
int readLine(void) {
char c;
byte bufferIndex = 0;
boolean startLine = 0;
byte retries = 0;
while (retries < 20) {

c= mySerial.read();

if (c == -1) {
delay(2);
continue;
}
if (c == '\n') continue;
if (c == '$') startLine = 1;
if ((bufferIndex == BUFFERSIZE-1) || (c == '\r')) {
if (startLine) {
buffer[bufferIndex] = 0;
return 1;
}
}
if (startLine) buffer[bufferIndex++] = c;
//}
else {
retries++;
delay(50);
}
}
return 0;
}

// Returns a specific field from the buffer
void getField(int getId, char *field, int maxLen) {
byte bufferIndex = 0;
byte fieldId = 0;
byte i = 0;
while (bufferIndex < sizeof(buffer)) { if (fieldId == getId) { // End of string, or string overflow if (buffer[bufferIndex] == ',' || i > (maxLen - 2)) {
field[i] = 0; // Null terminate
return;
}
// Buffer chars to field
field[i++] = buffer[bufferIndex++];
}
else {
// Advance field on comma
if (buffer[bufferIndex] == ',') {
bufferIndex++; // Advance in buffer
fieldId++; // Increase field position counter
}
else {
bufferIndex++; // Advance in buffer
}
}
}
// Null terminate incase we didn't already..
field[i] = 0;
}

// Polls for an NMEA sentence of type requested
// Validates checksum, silently retries on failed checksums
int getNMEA(char *getType) {
char type[7];
byte retries = 0;
while (retries < 2) {
if (readLine() && validateChecksum()) {
;
getField(0, type, sizeof(type));
if (strcmp(type, getType) == 0) {

return 1;
}
}
else {
retries++;

}
}
Serial.println("Failed to read GPS");

return 0;
}

// Validates the checksum on an NMEA string
// Returns 1 on valid checksum, 0 otherwise
int validateChecksum(void) {
char gotSum[2];
gotSum[0] = buffer[strlen(buffer) - 2];
gotSum[1] = buffer[strlen(buffer) - 1];
// Check that the checksums match up
if ((16 * atoh(gotSum[0])) + atoh(gotSum[1]) == getCheckSum(buffer)) return 1;
else return 0;
}

// Calculates the checksum for a given string
// returns as integer
int getCheckSum(char *string) {
int i;
int XOR;
int c;
// Calculate checksum ignoring any $'s in the string
for (XOR = 0, i = 0; i < strlen(string); i++) {
c = (unsigned char)string[i];
if (c == '*') break;
if (c != '$') XOR ^= c;
}
return XOR;
}

// Returns the groundspeed in km/h
int getSpeed(void) {
char field[10];
getField(7, field, sizeof(field));
int speed = atoi(field);
return speed;
}

// Return the fix type from a GGA string
int getFixType(void) {
char field[5];
getField(6, field, sizeof(field));
int fixType = atoi(field);
return fixType;
}

// Return the altitude in meters from a GGA string
long getAlt(void) {
char field[10];
getField(9, field, sizeof(field));
long altitude = atol(field);
return altitude;
}

// Returns the number of satellites being tracked from a GGA string
int getSats(void) {
char field[3];
getField(7, field, sizeof(field));
int numSats = atoi(field);
return numSats;
}

// Read the latitude in decimal format from a GGA string
double getLat(void) {
char field[12];
getField(2, field, sizeof(field)); // read the latitude
double latitude = atof(field); // convert to a double (precise)
int deg = (int) latitude / 100; // extract the number of degrees
double min = latitude - (100 * deg); // work out the number of minutes
latitude = deg + (double) min/60.0; // convert to decimal format
getField(3, field, sizeof(field)); // get the hemisphere (N/S)
if (strcmp(field, "S") == 0) latitude *= -1; // sign the decimal latitude correctly
return latitude;
}

// Read the longitude in decimal format from a GGA string
double getLong(void) {
char field[12];
getField(4, field, sizeof(field)); // read the longitude
double longitude = atof(field); // convert to a double
int deg = (int) longitude / 100; // extract the number of degrees
double min = longitude - (100 * deg); // work out the number of minutes
longitude = deg + (double) min/60.00; // convert to decimal format
getField(5, field, sizeof(field)); // get the E/W status
if (strcmp(field, "W") == 0) longitude *= -1; // sign decimal latitude correctly
return longitude;
}

// Converts UTC time to the correct timezone
void convertTime(int *time) {
// How many hours off GMT are we?
float offset = 2;
long sectime = ((long)(time[0]) * 3600) + (time[1] * 60) + time[2];
sectime += (offset * 3600.0);
// Did we wrap around?
if (sectime < 0) sectime += 86400; if (sectime > 86400) sectime -= 86400;
// Convert back to time
time[0] = (int)(sectime / 3600);
time[1] = (int)((sectime % 3600) / 60);
time[2] = (int)((sectime % 3600) % 60);
}

// Parses a time field from a GGA string
void parseTime(char *field, int *time) {
char tmp[3];
tmp[2] = 0; // Init tmp and null terminate
tmp[0] = field[0];
tmp[1] = field[1];
time[0] = atoi(tmp); // Hours
tmp[0] = field[2];
tmp[1] = field[3];
time[1] = atoi(tmp); // Minutes
tmp[0] = field[4];
tmp[1] = field[5];
time[2] = atoi(tmp); // Seconds
}

// Gets the hours, minutes and seconds from a GGA string
void getTime(int *time) {
char field[12];
getField(1, field, sizeof(field));
parseTime(field, time);
convertTime(time);
}

// ------ MISC ----------

// Returns a string with a textual representation of a float
void doubleToString(double val, int precision, char *string){

// Print the int part
sprintf(string, "%d", (int)(val));
if(precision > 0) {
// Print the decimal point
strcat(string, ".");
unsigned long frac;
unsigned long mult = 1;
int padding = precision -1;
while (precision--) {
mult *=10;
}
if (val >= 0)
frac = (val - (int)(val)) * mult;
else
frac = ((int)(val)- val ) * mult;
unsigned long frac1 = frac;
while (frac1 /= 10) {
padding--;
}
while (padding--) {
strcat(string, "0");
}

// Convert and print the fraction part
sprintf(string+strlen(string), "%d", (int)(frac));
}
}

 

// Converts a HEX string to an int
int atoh(char c) {
if (c >= 'A' && c <= 'F') return c - 55; else if (c >= 'a' && c <= 'f')
return c - 87;
else
return c - 48;
}

One response

5 09 2012
Sergio Silva

Hello Tim Zaman, live in Brazil, pleased to meet your site.

A lot of time looking for a way to track my dog​​, bought a shild Sagemcom Hilo GPRS and GPS Skm53, but I’m beginner with arduino and programming.

Could you pass me your project so I try to play here?

In Brazil we do not have GPRS card manufacturers and was expensive to import this module Hilo. And unfortunately could not make it work.

I am very grateful for your attention.

Sergio

sergiolinux@gmail.com

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: