My Cart

Geocaching Santa Claus

Difficulty Level: Expert -


The legend of Santa Claus tells that he lives in the cold, far, far north of the World. But does Santa Claus really live in the same North Pole? and if so, what is his exact position? The Cooking Hacks team decided to solve these questions!

To do so we ask to the little Tamara for writing her letter to Santa Claus, and we sent it along with a geolocation tracking device we built. The tracking unit is composed by the 3G+GPS module for Arduino and Raspberry Pi equipped with a camera, a battery and a light sensor.

The idea is to track real time the position of the letter when it is travelling throughout the World looking for its final destination (Santa Claus' home!). So we program the Arduino to take the information from the GPS and send to one of our Internet Servers via 3G.

We knew it was going to be a long way, as almost not any courier in the World knows where Santa Claus lives and they just send the letter from one to another until one of them delivers it to the secret place.

But knowing where Santa Claus lives was not enough for us, and we decided to take a picture of him! To do so, we programmed Arduino to take and send a picture triggered by the light sensor, and... we get it!

Hope you enjoy, the video and the article explaining how to make your own Geolocation Tracking Unit.

The Cooking Hacks Team wish you a Merry Christmas!

Step 1: Introduction

Ingredients:

  • 3G + GPS option:

    • 1x Arduino Uno
    • 1x 3G/GPRS shield for Arduino / Raspberry Pi (3G +GPS)
    • 1x 2300mA/h Rechargeable battery
    • 1x VGA sensor camera module
    • 1x Internal GPRS-GSM Antenna
    • 1x Internal GPS Antenna
  • GPRS +GPS option:

    • 1x Arduino Uno
    • 1x Geolocation Tracker (GPRS + GPS) with SIM908
    • 1x 2300mA/h Rechargeable Battery
    • 1x Internal GPRS-GSM Antenna
    • 1x INTERNAL GPS Antenna

    Preparation time: 30 minutes

    If you are interested in Internet of Things (IoT) or M2M projects check our open source sensor platform Waspmote which counts with more than 100 sensors available to use 'off the shelf', a complete API with hundreds of ready to use codes and a low consumption mode of just 0.7µA to ensure years of battery life.

    Know more at:

    Get the Starter Kits at:

    STEP 2: Hardware selection

    The board (shield) we are going to use in this tutorial is 3G shield for Arduino the from Cooking hacks. The 3G + GPS shield is fully compatible with old Arduino USB versions, Duemilanove and Mega.

    The 3G shield for Arduino enables the connectivity to high speed WCDMA and HSPA cellular networks in order to make possible the creation of the next level of worldwide interactivity projects inside the new "Internet of Things" era.

    The module counts also with an internal GPS what enables the location of the device outdoors and indoors combining standard NMEA frames with mobile cell ID triangulation using both assisted-mobile ( A-GPS ) and mobile-based ( S-GPS ) modes.

    Other interesting accessories which can be connected to the module are a video camera which enables the record of video in high resolution (640x480).

    As a second option we could use the GPRS/GPS SIM908 shield to make the same application (this is a cheaper option but you can not use the cammera with it or join high speed cell networks).

    3G/GPRS/GPS Shield (SIM5218) GPRS/GPS (SIM908)
    SD Card Slot Yes No
    3G Yes No
    GPRS Yes Yes
    GPS Yes Yes
    Video Calls Yes No
    HTTP Yes Yes
    Send/Receive mails Yes No
    Upload/Download by FTP Yes Yes
    Play compressed audio files Yes No

    STEP 3: System assembly

    The first step is to connect the 3G shield over Arduino. Connect the board as shown in the picture.

    Electrical features

    The 3G module used is the SIM5218 from SIMCOM. The power supply of SIM5218 is from a single voltage source of VBAT= 3.4v-4.2v. In some case, the ripple in a transmit burst may cause voltage drops when current consumption rise to typical peaks of 2A.

    So the power supply must be able to provide sufficient current up to 2A. The maximum rating are VBAT=4,4v and 3A peak. The maximum value of voltage for digital or analogy pins is 2.8v.

    Use an external power supply or a battery and place the power jumpers in the right position. If the shield is powered from the Arduino, the power jumper must be in Arduino 5V position. It the shield is powered from the Vin input (in the shield), the power jumper must be in Vext position.

    If you use a power supply with output smaller than 2 A, you should add an extra capacitor for the power. For example, a 220 uF electrolytic capacitor between 3.3V and GND.

    Power supply jumper should be set to Arduino 5V position if you are using 12 volt power supply directly connected to Arduino (because the Arduino powers the module).

    We use a 2300mA/h Rechargeable Battery. The 3G module hasn't battery connector so we should solder the battery between 4V and GND pins of the shield as shown in the picture.

    Once it is connected we must assemble different accessories:

    Antennas

    SIM5218 has 3 UFL connectors. Two for diversity of 3G mobile carriers and one for GPS antenna. The impedance of the RF interface is 50Ω. It is recommended use just the "main" antenna socket for the mobile connection unless you experience coverage or performance problems. In this case two antennas allowing diversity may be placed.

    Also, the module allows to solder the antenna to the pad, or attach it via contact springs.

    Antenna availability

    We recommend the usage of the following antennas:

    Connect GPS Antenna as shown in the picture.

    And then plug the GPRS-GSM Antenna.

    Important Issues:

    • Handle with care the internal antenna. It's fragile.
    • The GPS antenna must be in horizontal position.
    • For improving the satellites signal, the antenna has to be in a place with a clear sky view (no trees, no buildings...).
    • Maybe the GPS takes 2-3 minutes to get signal the firs time.

    Camera

    This module allows to connect a VGA camera for video recording and taking photos. The maximum resolution for images is 640x480 (VGA) and 320x240 (QVGA) with 15 fps for video. Once saved the video or image, the file can be sent to an FTP or FTPS as you'll see later. The pin diagram shows below:

    Follow these simple steps to mount the camera into the 3G Arduino board.

    The first step is to open the socket. To do this, pull carefully out the sides of the connector.

    Insert the camera with metallic contacts facing up.

    At the final step, push in the laterals of the connector.

    LDR: Light sensor

    Light dependent resistors (LDRs) or photoresistors are resistors that have high resistance in the dark and decrease in resistance as they are exposed to more light.

    The Arduino reads the voltage at a pin, so in order for the LDR to be read by the Arduino, it needs to affect the voltage. This is done by creating a voltage divider.

    The circuit diagram is shown below. As the light increases, the LDR's resistance drops and hence the voltage across it drops. Thus the voltage across the resistor increases, so the voltage into the Arduino ADC increases. The opposite is true as it gets darker.

    Final assembly

    In order to protect the hardware we are going to use a Cooking-Hacks Box.

    Place carefully the electronic assembly inside the box.

    STEP 4: Software: Arduino code

    IIn this step we use an Arduino UNO with the 3G shield to send GPS coordinates to a mobile using an SMS and to do a video call.

    Remember, the serial communication jumpers have to be set on Arduino position. If we are connecting the module to a PC directly (using an Arduino as gateway), we should set the jumpers on USB gateway position.

    NOTE: The Arduino/Raspberry Pi jumper MUST be in Arduino position. The Raspberry Pi position should be used only if the shield is connected to a Raspberry Pi. A wrong position of this jumper can damage the 3G shield.

    Send GPS coordinates through HTTP request

    SIM5218 supports both A-GPS and S-GPS and provides three operating modes: mobile-assisted mode, mobile-based mode and standalone mode. A-GPS is include mobile-assisted and mobile-based mode.

    In standalone mode, the GPS obtains position, altitude,... with only the signal of the satellites, making it the slowest of the three modes. If you use the AT+CGPSINFO command, the module brings directly latitude, longitude, date, UTC time, altitude and speed.

    Connecting the pack to an Arduino and using the code below, Arduino sends GPS data to a web server:

    Code:
    
    /*  
     *  Geocaching Santa Claus
     *  
     *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
     *  http://www.libelium.com 
     *  
     *  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, either version 3 of the License, or 
     *  (at your option) any later version. 
     *  a
     *  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, see http://www.gnu.org/licenses/. 
     *  
     *  Version:           2.0
     *  Design:            David GascĂłn 
     *  Implementation:    Luis Martin
     */
    
    
    int8_t answer;
    int onModulePin= 2;
    char gps_data[100];
    int counter;
    
    char aux_string[30];
    char phone_number[]="*********";
    
    int data_size = 0;
    int end_file = 0;
    
    char aux_str[100];
    
    char data[350];
    int x = 0;
    long previous;
    
    char url[ ]="cooking-hacks.com";
    int port= 80;
    char request[ ]="GET /t/gps-route.php?gps=";
    char request1[ ]= "HTTP/1.1\r\nHost: cooking_hacks.com\r\nContent-Length: 0\r\n\r\n";
    
    void setup(){
    
        pinMode(onModulePin, OUTPUT);
        Serial.begin(115200);    
    
        Serial.println("Starting...");
        power_on();
    
        delay(5000);
              // starts GPS session in stand alone mode
        answer = sendATcommand("AT+CGPS=1,1","OK",1000);    
        if (answer == 0)
        {
            Serial.println("Error starting the GPS");
            Serial.println("The code stucks here!!");
            while(1);
        }
    
        delay(3000);
    
        while( (sendATcommand("AT+CREG?", "+CREG: 0,1", 500) || 
            sendATcommand("AT+CREG?", "+CREG: 0,5", 500)) == 0 );
    
        // sets APN, user name and password
        sendATcommand("AT+CGSOCKCONT=1,\"IP\",\"movistar.es\"", "OK", 2000);
        sendATcommand("AT+CSOCKAUTH=1,1,\"movistar\",\"movistar\"", "OK", 2000);
    
    }
    void loop(){
    
        answer = sendATcommand("AT+CGPSINFO","+CGPSINFO:",1000);    // request info from GPS
        if (answer == 1)
        {
    
            counter = 0;
            do{
                while(Serial.available() == 0);
                gps_data[counter] = Serial.read();
                counter++;
            }
            while(gps_data[counter - 1] != '\r');
            gps_data[counter] = '\0';
            if(gps_data[0] == ',')
            {
                 Serial.println("No GPS data available");  
                 delay(3000);
            }
            else
            {
            answer = sendATcommand("AT+CGPS=0","OK",1000);    
     	
            // request the url
      	sprintf(aux_str, "AT+CHTTPACT=\"%s\",%d", url, port);
            answer = sendATcommand(aux_str, "+CHTTPACT: REQUEST", 60000);
    
            if (answer == 1)
             {        
              Serial.print(request);
    	  Serial.print(gps_data);
              Serial.println(request1);
              // Sends 
              aux_str[0] = 0x1A;
              aux_str[1] = 0x00;
              answer = sendATcommand(aux_str, "+CHTTPACT: DATA,", 60000);
    
            if (answer == 1)
            {
                Serial.print("Sent ");    
                
                int a=0;
                for(int a=0;a<60;a++){  //Wait 30 minutes
                  delay(30000); 
                 }
    
                 // starts GPS session in stand alone mode
                  answer = sendATcommand("AT+CGPS=1,1","OK",1000);    
                  if (answer == 0)
                  {
                     Serial.println("Error starting the GPS");
                    Serial.println("The code stucks here!!");
                    while(1);
                  }
            }
            else
            {
                Serial.print("error ");
            }
        }
        else
        {
            Serial.print("error ");
            Serial.println(answer, DEC);
        }
    
    
            }       
    
        }
        else
        {
            Serial.println("Error"); 
        }
    
    
    }
    
    void power_on(){
    
        uint8_t answer=0;
    
        // checks if the module is started
        answer = sendATcommand("AT", "OK", 2000);
        if (answer == 0)
        {
            // power on pulse
            digitalWrite(onModulePin,HIGH);
            delay(3000);
            digitalWrite(onModulePin,LOW);
    
            // waits for an answer from the module
            while(answer == 0){    
                // Send AT every two seconds and wait for the answer
                answer = sendATcommand("AT", "OK", 2000);    
            }
        }
    
    }
    
    
    int8_t sendATcommand(char* ATcommand, char* expected_answer1, unsigned int timeout)
    {
    
        uint8_t x=0,  answer=0;
        char response[100];
        unsigned long previous;
    
        memset(response, '\0', 100);    // Initialize the string
    
        delay(100);
    
        while( Serial.available() > 0) Serial.read();    // Clean the input buffer
    
        Serial.println(ATcommand);    // Send the AT command 
    
    
            x = 0;
        previous = millis();
    
        // this loop waits for the answer
        do{
    
            if(Serial.available() != 0){    
                response[x] = Serial.read();
                x++;
                // check if the desired answer is in the response of the module
                if (strstr(response, expected_answer1) != NULL)    
                {
                    answer = 1;
                }
            }
            // Waits for the asnwer with time out
        }
        while((answer == 0) && ((millis() - previous) < timeout));    
    
        return answer;
    }
            

    Upload the next sketch into your Arduino and then assemble the 3G shield with the antennas and the SIM card installed. Remember, you must insert your telephone number.

    During the long journey the letter traveled through ten different countries:

      1. Zaragoza (Spain) (41.652649 -0.889063)
      2. Cairo (Egypt) (30.047402 31.235647)
      3. Buenos Aires (Argentina) (-34.597042 -58.381405)
      4. Mexico D.F. (Mexico) (19.435514 -99.14795)
      5. Austin (Texas) (30.287532 -97.714234)
      6. Sevilla (Spain) (37.394982 -5.982456)
      7. Edinburgh (Scotland) (55.958042 -3.188839)
      8. Shangai (China) (31.257422 121.471481)
      9. Moscow (Russia) (55.774256 37.619705)
      10. Rovaniemi (Finland) (66.497383 25.724866)

    Make a video call

    The SIM5218 allows video calls, but to carry them out correctly the operator and the network must be able to allow it. The example code is below. Cooking Hacks does not ensure that the video call functions correctly.

    Please, be sure that your SIM card have activated the videocall feature, with your network operator and with the phone that you want to call, before testing the next sketch.

    Upload the next sketch into your Arduino and then assemble the 3G shield with the antennas and the simcard installed. Remember, you must configure your APN, login and password. If you don't do this, the GPRS+GPS cannot connect to the GPRS network. This example does a videocall of 20 seconds.

    We are going to use the Light Dependent Resistor (LDR) to create a simple videocall trigger which turns on automatically when it gets light.

    Code:
    
    /*  
     *  Geocaching Santa Claus
     *  
     *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
     *  http://www.libelium.com 
     *  
     *  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, either version 3 of the License, or 
     *  (at your option) any later version. 
     *  a
     *  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, see http://www.gnu.org/licenses/. 
     *  
     *  Version:           2.0
     *  Design:            David GascĂłn 
     *  Implementation:    Luis Martin & Alejandro Gallego
     */
    
    
    int8_t answer;
    int onModulePin = 2;
    int button = 12;
    char aux_str[30];
    
    char phone_number[]="*********";     // ********* is the number to call
    
    void setup(){
    
        pinMode(onModulePin, OUTPUT);
        pinMode(button, INPUT);
        Serial.begin(115200);      
    
        Serial.println("Starting...");
        power_on();
    
        delay(3000);
    
        // sets the PIN code
        sendATcommand2("AT+CPIN=****", "OK", "ERROR", 2000);
        
        // read the value from the ldr:
        sensorValue = analogRead(sensorPin);     
      
        while(sensorValue < 700) {
          sensorValue = analogRead(sensorPin);   
        }
    
        delay(3000);
    
        Serial.println("Connecting to the network...");
    
        while(sendATcommand2("AT+CREG?", "+CREG: 0,1", "+CREG: 0,5", 1000) == 0 );
    
    
        // Starts the camera
        answer = sendATcommand2("AT+CCAMS", "OK", "CAMERA NO SENSOR", 3000);
        if (answer == 1)
        {
            // Sets resolution
            sendATcommand2("AT+CCAMSETD=320,240", "OK", "ERROR", 2000);
    
            sprintf(aux_str, "AT+VPMAKE=%s", phone_number);
            answer = sendATcommand2(aux_str, "VPCONNECTED", "VPEND", 30000);
            if (answer == 1)
            {
                delay(20000);
                sendATcommand2("AT+VPEND", "OK", "", 30000);
            }
            else
            {
                Serial.println("Error originating the call");    
            }
        }
        else if (answer == 2)
        {
            Serial.println("Camera not detected");    
        }
        else
        {
            Serial.println("Error starting the camera");    
        }
    
    }
    
    
    void loop(){
    
    }
    
    
    
    void power_on(){
    
        uint8_t answer=0;
    
        // checks if the module is started
        answer = sendATcommand2("AT", "OK", "OK", 2000);
        if (answer == 0)
        {
            // power on pulse
            digitalWrite(onModulePin,HIGH);
            delay(3000);
            digitalWrite(onModulePin,LOW);
    
            // waits for an answer from the module
            while(answer == 0){    
                // Send AT every two seconds and wait for the answer
                answer = sendATcommand2("AT", "OK", "OK", 2000);    
            }
        }
    
    }
    
    
    int8_t sendATcommand2(char* ATcommand, char* expected_answer1,
        char* expected_answer2, unsigned int timeout)
    {
    
        uint8_t x=0,  answer=0;
        char response[100];
        unsigned long previous;
    
        memset(response, '\0', 100);    // Initialize the string
    
        delay(100);
    
        // Clean the input buffer
        while( Serial.available() > 0) Serial.read(); 
    
        Serial.println(ATcommand);    // Send the AT command 
    
    
            x = 0;
        previous = millis();
    
        // this loop waits for the answer
        do{
    
            if(Serial.available() != 0){    
                response[x] = Serial.read();
                x++;
                // check if the expected answer 1 is in the response of the module
                if (strstr(response, expected_answer1) != NULL)    
                {
                    answer = 1;
                }
                // check if the expected answer 2 is in the response of the module
                if (strstr(response, expected_answer2) != NULL)    
                {
                    answer = 2;
                }
            }
            // Waits for the asnwer with time out
        }
        while((answer == 0) && ((millis() - previous) < timeout));    
    
        return answer;
    }
            

    Other option is to use the GPRS+GPS Module as we say in the intro.

    In the next example code we use the GPRS+GPS Module for Arduino (SIM908) to get the GPS position and send an SMS to your phone every 30 minutes:

    Code:
    
    /*  
     *  Geocaching Santa Claus
     *  
     *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
     *  http://www.libelium.com 
     *  
     *  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, either version 3 of the License, or 
     *  (at your option) any later version. 
     *  a
     *  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, see http://www.gnu.org/licenses/. 
     *  
     *  Version:           2.0
     *  Design:            David GascĂłn 
     *  Implementation:    Luis Martin & Victor Boria
     */
    
    int8_t answer;
    int onModulePin= 2;
    char aux_string[30];
    int flag = 0;
    char numero [20];
    char numeroreal[9];
    char numeromio[9];
    int a=0;
    char phone_number[]="*********"; // Insert your telephone number here
    
    char data[100];
    int data_size;
    
    char aux_str[30];
    char aux;
    int x = 0;
    char N_S,W_E;
    char frame[200];
    
    char latitude[15];
    char longitude[15];
    char altitude[6];
    char date[16];
    char time[7];
    char satellites[3];
    char speedOTG[10];
    char course[10];
    
    void setup(){   
    
        pinMode(onModulePin, OUTPUT);
        Serial.begin(115200);    
        
        power_on();
        power_onGPS();
        power_onSMS();
        
        delay(5000);
        
        sendATcommand("AT+CPIN=****", "OK", 2000);  
      
        delay(3000);  
    
        while( (sendATcommand("AT+CREG?", "+CREG: 0,1", 1000) || sendATcommand("AT+CREG?", "+CREG: 0,5", 1000)) == 0 );
    
    
        sendATcommand("AT+CLIP=1", "OK", 1000); 
        
        while ( start_GPS() == 0);
    
        while (sendATcommand("AT+CREG?", "+CREG: 0,1", 2000) == 0);
        
        delay(1000);
        while(Serial.available() != 0)
        {
          Serial.read();  
        }
    }
    
    void loop(){
        
      get_GPS(); //Get GPS data
      sendSMS(); //Send SMS
    
      a=0;
      for(int a=0;a<60;a++){  //Wait 30 minutes
      delay(30000); 
      }
    
                       
    }
    
    void power_on(){
    
        uint8_t answer=0;
    
        digitalWrite(onModulePin,HIGH);
        delay(3000);
        digitalWrite(onModulePin,LOW);
    
        while(answer == 0){     // Send AT every two seconds and wait for the answer
            answer = sendATcommand("AT", "OK", 2000);    
        }
    }
    
    int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout){
    
        uint8_t x=0,  answer=0;
        char response[100];
        unsigned long previous;
    
        memset(response, '\0', 100);    // Initialice the string
        
        delay(100);
        
        while( Serial.available() > 0) Serial.read();    // Clean the input buffer
        
        if (ATcommand[0] != '\0')
        {
            Serial.println(ATcommand);    // Send the AT command 
        }
    
    
        x = 0;
        previous = millis();
    
        // this loop waits for the answer
        do{
            if(Serial.available() != 0){    // if there are data in the UART input buffer, reads it and checks for the asnwer
                response[x] = Serial.read();
                //Serial.print(response[x]);
                x++;
                if (strstr(response, expected_answer) != NULL)    // check if the desired answer (OK) is in the response of the module
                {
                    answer = 1;
                }
            }
        }while((answer == 0) && ((millis() - previous) < timeout));    // Waits for the asnwer with time out
    
        return answer;
    }
    
    void power_onGPS(){
    
        uint8_t answer=0;
    
        // checks if the module is started
        answer = sendATcommand("AT", "OK", 2000);
        if (answer == 0)
        {
            // power on pulse
            digitalWrite(onModulePin,HIGH);
            delay(3000);
            digitalWrite(onModulePin,LOW);
    
            // waits for an answer from the module
            while(answer == 0){  
                // Send AT every two seconds and wait for the answer   
                answer = sendATcommand("AT", "OK", 2000);    
            }
        }
    
    }
    
    int8_t start_GPS(){
    
        unsigned long previous;
    
        previous = millis();
        // starts the GPS
        sendATcommand("AT+CGPSPWR=1", "OK", 2000);
        sendATcommand("AT+CGPSRST=0", "OK", 2000);
    
        // waits for fix GPS
        while(( (sendATcommand("AT+CGPSSTATUS?", "2D Fix", 5000) || 
            sendATcommand("AT+CGPSSTATUS?", "3D Fix", 5000)) == 0 ) && 
            ((millis() - previous) < 90000));
    
        if ((millis() - previous) < 90000)
        {
            return 1;
        }
        else
        {
            return 0;    
        }
    }
    
    int8_t get_GPS(){
    
        int8_t counter, answer;
        long previous;
    
        // First get the NMEA string
        // Clean the input buffer
        while( Serial.available() > 0) Serial.read(); 
        // request Basic string
        sendATcommand("AT+CGPSINF=0", "AT+CGPSINF=0\r\n\r\n", 2000);
    
        counter = 0;
        answer = 0;
        memset(frame, '\0', 100);    // Initialize the string
        previous = millis();
        // this loop waits for the NMEA string
        do{
    
            if(Serial.available() != 0){    
                frame[counter] = Serial.read();
                counter++;
                // check if the desired answer is in the response of the module
                if (strstr(frame, "OK") != NULL)    
                {
                    answer = 1;
                }
            }
            // Waits for the asnwer with time out
        }
        while((answer == 0) && ((millis() - previous) < 2000));  
    
        frame[counter-3] = '\0'; 
        
        // Parses the string 
        strtok(frame, ",");
        strcpy(longitude,strtok(NULL, ",")); // Gets longitude
        strcpy(latitude,strtok(NULL, ",")); // Gets latitude
        strcpy(altitude,strtok(NULL, ".")); // Gets altitude 
        strtok(NULL, ",");    
        strcpy(date,strtok(NULL, ".")); // Gets date
        strtok(NULL, ",");
        strtok(NULL, ",");  
        strcpy(satellites,strtok(NULL, ",")); // Gets satellites
        strcpy(speedOTG,strtok(NULL, ",")); // Gets speed over ground. Unit is knots.
        strcpy(course,strtok(NULL, "\r")); // Gets course
    
        convert2Degrees(latitude);
        convert2Degrees(longitude);
        
        return answer;
    }
    
    /* convert2Degrees ( input ) - performs the conversion from input 
     * parameters in  DD°MM.mmm’ notation to DD.dddddd° notation. 
     * 
     * Sign '+' is set for positive latitudes/longitudes (North, East)
     * Sign '-' is set for negative latitudes/longitudes (South, West)
     *  
     */
    int8_t convert2Degrees(char* input){
    
        float deg;
        float minutes;
        boolean neg = false;    
    
        //auxiliar variable
        char aux[10];
    
        if (input[0] == '-')
        {
            neg = true;
            strcpy(aux, strtok(input+1, "."));
    
        }
        else
        {
            strcpy(aux, strtok(input, "."));
        }
    
        // convert string to integer and add it to final float variable
        deg = atof(aux);
    
        strcpy(aux, strtok(NULL, '\0'));
        minutes=atof(aux);
        minutes/=1000000;
        if (deg < 100)
        {
            minutes += deg;
            deg = 0;
        }
        else
        {
            minutes += int(deg) % 100;
            deg = int(deg) / 100;    
        }
    
        // add minutes to degrees 
        deg=deg+minutes/60;
    
    
        if (neg == true)
        {
            deg*=-1.0;
        }
    
        neg = false;
    
        if( deg < 0 ){
            neg = true;
            deg*=-1;
        }
        
        float numeroFloat=deg; 
        int parteEntera[10];
        int cifra; 
        long numero=(long)numeroFloat;  
        int size=0;
        
        while(1){
            size=size+1;
            cifra=numero%10;
            numero=numero/10;
            parteEntera[size-1]=cifra; 
            if (numero==0){
                break;
            }
        }
       
        int indice=0;
        if( neg ){
            indice++;
            input[0]='-';
        }
        for (int i=size-1; i >= 0; i--)
        {
            input[indice]=parteEntera[i]+'0'; 
            indice++;
        }
    
        input[indice]='.';
        indice++;
    
        numeroFloat=(numeroFloat-(int)numeroFloat);
        for (int i=1; i<=6 ; i++)
        {
            numeroFloat=numeroFloat*10;
            cifra= (long)numeroFloat;          
            numeroFloat=numeroFloat-cifra;
            input[indice]=char(cifra)+48;
            indice++;
        }
        input[indice]='\0';
    
    
    }
    
    
    
    
    void power_onSMS(){
    
        uint8_t answer=0;
        
        // checks if the module is started
        answer = sendATcommand("AT", "OK", 2000);
        if (answer == 0)
        {
            // power on pulse
            digitalWrite(onModulePin,HIGH);
            delay(3000);
            digitalWrite(onModulePin,LOW);
        
            // waits for an answer from the module
            while(answer == 0){     // Send AT every two seconds and wait for the answer
                answer = sendATcommand("AT", "OK", 2000);    
            }
        }
        
    }
    
    void sendSMS(){
      sendATcommand("AT+CPIN=****", "OK", 2000);
        
        delay(3000);
        
        Serial.println("Connecting to the network...");
    
        while( (sendATcommand("AT+CREG?", "+CREG: 0,1", 500) || 
                sendATcommand("AT+CREG?", "+CREG: 0,5", 500)) == 0 );
    
        Serial.print("Setting SMS mode...");
        sendATcommand("AT+CMGF=1", "OK", 1000);    // sets the SMS mode to text
        Serial.println("Sending SMS");
        
        sprintf(aux_string,"AT+CMGS=\"%s\"", phone_number);
        answer = sendATcommand(aux_string, ">", 2000);    // send the SMS number
        if (answer == 1)
        {
            Serial.print("This is your ");
            Serial.print("latitude: ");
                  int i = 0;
                  while(latitude[i]!=0){
                  Serial.print(latitude[i]);
                  i++;
                  }
                  Serial.print(" and longitude: ");
                  i = 0;
                  while(longitude[i]!=0){
                  Serial.print(longitude[i]);
                  i++;
                  }
            Serial.write(0x1A);
            answer = sendATcommand("", "OK", 20000);
            if (answer == 1)
            {
                Serial.print("Sent ");    
            }
            else
            {
                Serial.print("error ");
            }
        }
        else
        {
            Serial.print("error ");
            Serial.println(answer, DEC);
        }
    
    }
            

    In this code we use the SD Shield for Arduino to write the GPS position in a SD card, so you don't have to send an SMS in order to save money.

    Code:
    
    /*  
     *  Geocaching Santa Claus
     *  
     *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
     *  http://www.libelium.com 
     *  
     *  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, either version 3 of the License, or 
     *  (at your option) any later version. 
     *  a
     *  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, see http://www.gnu.org/licenses/. 
     *  
     *  Version:           2.0
     *  Design:            David GascĂłn 
     *  Implementation:    Luis Martin & Victor Boria
     */
    
    #include<SD.h>
    
    Sd2Card card;
    SdVolume volume;
    SdFile root;
    
    int a=0;
    
    int8_t answer;
    int onModulePin= 2;
    
    char data[100];
    int data_size;
    
    char aux_str[30];
    char aux;
    int x = 0;
    char N_S,W_E;
    
    
    char frame[200];
    
    char latitude[15];
    char longitude[15];
    char altitude[6];
    char date[20];
    char time[7];
    char satellites[3];
    char speedOTG[10];
    char course[10];
    
    const int chipSelect=10;
    const int MEM_PW=8;
    
    File myFile;
    
    
    void setup(){
      
        pinMode(MEM_PW,OUTPUT);
        digitalWrite(MEM_PW,HIGH);
        
        pinMode(onModulePin, OUTPUT);
        Serial.begin(115200);   
        
        Serial.println("Starting...");
        power_on();
    
        delay(3000);
        
        if (!SD.begin(chipSelect)) {
          Serial.println("initialization failed!");
          return;
        }
        Serial.println("initialization done.");
    
        
        // starts the GPS and waits for signal
        while ( start_GPS() == 0);
    
    }
    
    void loop(){
    
    
        get_GPS(); // Get the GPS position
        
        myFile = SD.open("GPS.txt", FILE_WRITE);
        
        Serial.println(date);
        Serial.println(longitude);
        Serial.println(latitude);
        Serial.println(altitude);
       
        //Write data in the SD card
        myFile.println(date);  
        myFile.println(longitude);
        myFile.println(latitude);
        myFile.println(altitude);
    
        myFile.close();
        
        a=0;
        for(int a=0;a<60;a++){  //Wait 30 minutes
        delay(30000); 
        }
    
    }
    
    void power_on(){
    
        uint8_t answer=0;
    
        // checks if the module is started
        answer = sendATcommand("AT", "OK", 2000);
        if (answer == 0)
        {
            // power on pulse
            digitalWrite(onModulePin,HIGH);
            delay(3000);
            digitalWrite(onModulePin,LOW);
    
            // waits for an answer from the module
            while(answer == 0){  
                // Send AT every two seconds and wait for the answer   
                answer = sendATcommand("AT", "OK", 2000);    
            }
        }
    
    }
    
    int8_t start_GPS(){
    
        unsigned long previous;
    
        previous = millis();
        // starts the GPS
        sendATcommand("AT+CGPSPWR=1", "OK", 2000);
        sendATcommand("AT+CGPSRST=0", "OK", 2000);
    
        // waits for fix GPS
        while(( (sendATcommand("AT+CGPSSTATUS?", "2D Fix", 5000) || 
            sendATcommand("AT+CGPSSTATUS?", "3D Fix", 5000)) == 0 ) &&
            ((millis() - previous) < 90000));
    
        if ((millis() - previous) < 90000)
        {
            return 1;
        }
        else
        {
            return 0;    
        }
    }
    
    int8_t get_GPS(){
    
        int8_t counter, answer;
        long previous;
    
        // First get the NMEA string
        // Clean the input buffer
        while( Serial.available() > 0) Serial.read(); 
        // request Basic string
        sendATcommand("AT+CGPSINF=0", "AT+CGPSINF=0\r\n\r\n", 2000);
    
        counter = 0;
        answer = 0;
        memset(frame, '\0', 100);    // Initialize the string
        previous = millis();
        // this loop waits for the NMEA string
        do{
    
            if(Serial.available() != 0){    
                frame[counter] = Serial.read();
                counter++;
                // check if the desired answer is in the response of the module
                if (strstr(frame, "OK") != NULL)    
                {
                    answer = 1;
                }
            }
            // Waits for the asnwer with time out
        }
        while((answer == 0) && ((millis() - previous) < 2000));  
    
        frame[counter-3] = '\0'; 
        memset(date, '\0', sizeof(date)); 
        // Parses the string 
        strtok(frame, ",");
        strcpy(longitude,strtok(NULL, ",")); // Gets longitude
        strcpy(latitude,strtok(NULL, ",")); // Gets latitude
        strcpy(altitude,strtok(NULL, ".")); // Gets altitude 
        strtok(NULL, ",");    
        strcpy(date,strtok(NULL, ".")); // Gets date
        strtok(NULL, ",");
        strtok(NULL, ",");  
        strcpy(satellites,strtok(NULL, ",")); // Gets satellites
        strcpy(speedOTG,strtok(NULL, ",")); // Gets speed over ground. Unit is knots.
        strcpy(course,strtok(NULL, "\r")); // Gets course
    
    
        date[18]=date[13];
        date[17]=date[12];
        date[16]=':';
        date[15]=date[11];
        date[14]=date[10];
        date[13]=date[16];    //":"
        date[12]=date[9];
        date[11]=date[8];
        date[10]=' ';
        date[9]=date[7];
        date[8]=date[6];
        date[7]='/';
        date[6]=date[5];
        date[5]=date[4];
        date[4]=date[7];      //"/"
        
        
        
        convert2Degrees(latitude);
        convert2Degrees(longitude);
        
        return answer;
    }
    
    /* convert2Degrees ( input ) - performs the conversion from input 
     * parameters in  DD°MM.mmm’ notation to DD.dddddd° notation. 
     * 
     * Sign '+' is set for positive latitudes/longitudes (North, East)
     * Sign '-' is set for negative latitudes/longitudes (South, West)
     *  
     */
    int8_t convert2Degrees(char* input){
    
        float deg;
        float minutes;
        boolean neg = false;    
    
        //auxiliar variable
        char aux[10];
    
        if (input[0] == '-')
        {
            neg = true;
            strcpy(aux, strtok(input+1, "."));
    
        }
        else
        {
            strcpy(aux, strtok(input, "."));
        }
    
        // convert string to integer and add it to final float variable
        deg = atof(aux);
    
        strcpy(aux, strtok(NULL, '\0'));
        minutes=atof(aux);
        minutes/=1000000;
        if (deg < 100)
        {
            minutes += deg;
            deg = 0;
        }
        else
        {
            minutes += int(deg) % 100;
            deg = int(deg) / 100;    
        }
    
        // add minutes to degrees 
        deg=deg+minutes/60;
    
    
        if (neg == true)
        {
            deg*=-1.0;
        }
    
        neg = false;
    
        if( deg < 0 ){
            neg = true;
            deg*=-1;
        }
        
        float numeroFloat=deg; 
        int parteEntera[10];
        int cifra; 
        long numero=(long)numeroFloat;  
        int size=0;
        
        while(1){
            size=size+1;
            cifra=numero%10;
            numero=numero/10;
            parteEntera[size-1]=cifra; 
            if (numero==0){
                break;
            }
        }
       
        int indice=0;
        if( neg ){
            indice++;
            input[0]='-';
        }
        for (int i=size-1; i >= 0; i--)
        {
            input[indice]=parteEntera[i]+'0'; 
            indice++;
        }
    
        input[indice]='.';
        indice++;
    
        numeroFloat=(numeroFloat-(int)numeroFloat);
        for (int i=1; i<=6 ; i++)
        {
            numeroFloat=numeroFloat*10;
            cifra= (long)numeroFloat;          
            numeroFloat=numeroFloat-cifra;
            input[indice]=char(cifra)+48;
            indice++;
        }
        input[indice]='\0';
    
    
    }
    
    
    
    
    int8_t sendATcommand(char* ATcommand, char* expected_answer1, unsigned int timeout){
    
        uint8_t x=0,  answer=0;
        char response[100];
        unsigned long previous;
    
        memset(response, '\0', 100);    // Initialize the string
    
        delay(100);
    
        while( Serial.available() > 0) Serial.read();    // Clean the input buffer
    
        Serial.println(ATcommand);    // Send the AT command 
    
    
            x = 0;
        previous = millis();
    
        // this loop waits for the answer
        do{
            if(Serial.available() != 0){    
                response[x] = Serial.read();
                x++;
                // check if the desired answer is in the response of the module
                if (strstr(response, expected_answer1) != NULL)    
                {
                    answer = 1;
                }
            }
            // Waits for the asnwer with time out
        }
        while((answer == 0) && ((millis() - previous) < timeout));    
    
        return answer;
    }
            
    NOTE: With some sketches, the buffer of the Software Serial may be small, to increase the length of the buffer you need to change this line in the file SoftwareSerial.h (/arduino-1.0.X/hardware/arduino/libraries/SoftwareSerial):
    #define _SS_MAX_RX_BUFF 64 // RX buffer size
    by
    #define _SS_MAX_RX_BUFF 256 // RX buffer size

    STEP 5: Results: GPS realtime geolocation tracking
    and Santa Claus Videocall

    When the GPS fixes the GPS satellites, the GPRS+GPS shield will connect to the network and it will send the GPS data throught HTTP request. Then we can show the position of the device in Google Maps.

    It's very simple: a GPS module to get position data and the 3G module that sends the HTTP request with the coordinates of the letter. It starts to send the HTTP request every 30 minutes with data of the position (latitude, longitude and altitude).

    When the packet arrives at destination the device detects the light level and makes a video call to see who is on the other side.

    COORDINATES CONVERSION / REPRESENTATION IN THE PLANE

    If you want to convert the NMEA output of your GPS to the coordinates format that you need, you can visit this website to make it easier:

    http://www.earthpoint.us/convert.aspx