My Cart

Where is my car? Realtime GPS+GPRS Tracking of Vehicles Using Arduino

Difficulty Level: Expert -


Avoid car thef is impossible but now find your stolen car will be easier!

You just need to install your Arduino with the GPRS+GPS Quadband Module (SIM908) in a hidden place in your car, maybe in your trunk, in the glove compartment or under your spare tyre. Then connect the GPRS-GSM and the GPS antenna and a SIM card, all of this powered with a battery and... you are ready!

First of all you have to call the police of course, but you can help them a lot. If your car is not parked where do you think, something is wrong... Call immediately to your Arduino, hidden in your car, and it will send you an SMS with the location, longitude and latitude at the moment, and it also sends GPS data to a web server with the realtime position (Google Maps). Thanks to the GPS+GPRS shield you can track your car in realtime. This shield is programmed to recognise your number and only if it is correct it will send you this data.

Picture description 1
Picture description 2

Don't miss our video and this amazing tutorial!

STEP 2: Hardware selection

The board (shield) we are going to use in this tutorial is the GPRS+GPS Quadband Module for Arduino (SIM908) from Cooking hacks.

The GPRS+GPS shield is fully compatible with old Arduino USB versions, Duemilanove and Mega.

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.

GPRS+GPS shield diagram (top):

GPRS+GPS shield diagram (bottom):

The LED of the shield shows the status of the GPRS+GPS module. The table below shows the meaning of the blink of the LED.

Status SIM908 behavior
Off SIM908 is not running
64ms On/ 800ms Off SIM908 not registered the network
64ms On/ 3000ms Off SIM908 registered to the network
SIM908 registered to the network PPP GPRS communication is established

STEP 3: System assembly

Antenna availability

We recommend the usage of the following antennas:

Connect the antennas to the shield:

Connect the shield to the Arduino:

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...).

Final assembly

You can fix the batteries to the module with flanges so the whole system will need less room and you will be able to place it better in your car.

Installation

Installation is very simple, you can place it wherever you want maybe in your trunk, in the glove compartment or under your spare tyre.

GPS antenna position is very important! For external GPS antenna, arrow printed in it must be pointing directly to the sky and internal GPS antenna ceramic side must be upwards too.

STEP 4: Software: Arduino code

In this step we use an Arduino UNO with the GPRS+GPS(SIM908) shield to send GPS coordinates to a mobile with a SMS and through HTTP when you call to the module and your number is correct.

Remember, the serial communication jumpers have to be set on Arduino position.

Identify your phone number and send GPS coordinates

When you call to the module and your phone number is correct, the GPS obtains longitude and latitude, send you a SMS with the position and send the GPS data through the Internet to the php script in your computer.

First step. Load the next sketch into your arduino and then assemble the GPRS+GPS 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. Also, you must set the URL with the IP address of your computer (external IP, not the LAN IP address) or your server's domain.

Code:

/*  
 *  Where is my car? Realtime GPS+GPRS Tracking of Vehicles Using Arduino
 *  
 *  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:           1.0
 *  Design:            David GascĂłn 
 *  Implementation:    Marcos Martinez
 */

int8_t answer;
int onModulePin= 2;
char aux_string[30];
int flag = 0;
char number [20];
char realnumber[9];
char mynumber[9];
int a=0;
int b=0;
int c=0;
//Your phone number
char phone_number[]="012345678";  

char data[100];
int data_size;

char aux_str[30];
char aux;
int x = 0;
char N_S,W_E;

char url[] = "pruebas.libelium.com";
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(){
    mynumber[0]='0';
    mynumber[1]='1';
    mynumber[2]='2';
    mynumber[3]='3';
    mynumber[4]='4';
    mynumber[5]='5';
    mynumber[6]='6';
    mynumber[7]='7';
    mynumber[8]='8';
    

    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);

    // sets APN , user name and password
    sendATcommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"", "OK", 2000);
    sendATcommand("AT+SAPBR=3,1,\"APN\",\"*******\"", "OK", 2000);
    sendATcommand("AT+SAPBR=3,1,\"USER\",\"*******\"", "OK", 2000);
    sendATcommand("AT+SAPBR=3,1,\"PWD\",\"*******\"", "OK", 2000);

    // gets the GPRS bearer
    while (sendATcommand("AT+SAPBR=1,1", "OK", 20000) == 0)
    {
        delay(5000);
    }
    
    delay(1000);
    while(Serial.available() != 0)
    {
      Serial.read();  
    }
}
void loop(){
    
    answer = sendATcommand("", "+CLIP", 1000);
    //Detect incomming call
    if (answer == 1)
    {
        Serial.println("Incoming call");          
          
          if ( flag == 0){
            
              for (int i=0; i<19; i++){
               // read the incoming byte:
               while (Serial.available() == 0)
               {                 
                 delay (50);
               }
               //Stores phone number
               number[i] = Serial.read();  
               
              }
              Serial.flush();
              flag = 1; 
          }          
          //Stores phone calling number
          for (int i=0; i<=14; i++){
            if(number[i]== '"'){
              i++;
              realnumber[0]=number[i];
              i++;
              realnumber[1]=number[i];
              i++;
              realnumber[2]=number[i];
              i++;
              realnumber[3]=number[i];
              i++;
              realnumber[4]=number[i];
              i++;
              realnumber[5]=number[i];
              i++;
              realnumber[6]=number[i];
              i++;
              realnumber[7]=number[i];
              i++;
              realnumber[8]=number[i];
              break;
            }            
    }
    //Check phone number
    for (int i=0;i<9;i++){ 
      if (realnumber[i] == mynumber[i]){
          a++;       
          if( a==9){  
             Serial.println("Correct number");
             sendATcommand("ATH", "OK", 1000);
               if(b==1){
                  b=0;
                }else{                  
                  b=1;
                  c=1;
                    }
                    break;
                  }
                }else{             
                  Serial.println("Wrong number");
                  break;
                 }
              }          
     a=0;
     answer=0;
     flag = 0;     
}
//Send SMS once and position to HTTP                   
if (b==1){
     get_GPS();
     send_HTTP();
     delay(500);                                       
    if (c==1){
      sendSMS();
      delay(100);
      c=0;                   
      }               
     }
}

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 numberFloat=deg; 
    int intPart[10];
    int digit; 
    long newNumber=(long)numberFloat;  
    int size=0;
    
    while(1){
        size=size+1;
        digit=newNumber%10;
        newNumber=newNumber/10;
        intPart[size-1]=digit; 
        if (newNumber==0){
            break;
        }
    }
   
    int index=0;
    if( neg ){
        index++;
        input[0]='-';
    }
    for (int i=size-1; i >= 0; i--)
    {
        input[index]=intPart[i]+'0'; 
        index++;
    }

    input[index]='.';
    index++;

    numberFloat=(numberFloat-(int)numberFloat);
    for (int i=1; i<=6 ; i++)
    {
        numberFloat=numberFloat*10;
        digit= (long)numberFloat;          
        numberFloat=numberFloat-digit;
        input[index]=char(digit)+48;
        index++;
    }
    input[index]='\0';


}

void send_HTTP(){
    
    uint8_t answer=0;
    // Initializes HTTP service
    answer = sendATcommand("AT+HTTPINIT", "OK", 10000);
    if (answer == 1)
    {
        // Sets CID parameter
        answer = sendATcommand("AT+HTTPPARA=\"CID\",1", "OK", 5000);
        if (answer == 1)
        {
            // Sets url 
            sprintf(aux_str, "AT+HTTPPARA=\"URL\",\"http://%s/demo_sim908.php?", url);
            Serial.print(aux_str);
            sprintf(frame, "visor=false&latitude=%s&longitude=%s&altitude=%s&time=%s&satellites=%s&speedOTG=%s&course=%s",
            latitude, longitude, altitude, date, satellites, speedOTG, course);
            Serial.print(frame);
            answer = sendATcommand("\"", "OK", 5000);
            if (answer == 1)
            {
                // Starts GET action
                answer = sendATcommand("AT+HTTPACTION=0", "+HTTPACTION:0,200", 30000);
                if (answer == 1)
                {

                    Serial.println(F("Done!"));
                }
                else
                {
                    Serial.println(F("Error getting url"));
                }

            }
            else
            {
                Serial.println(F("Error setting the url"));
            }
        }
        else
        {
            Serial.println(F("Error setting the CID"));
        }    
    }
    else
    {
        Serial.println(F("Error initializating"));
    }

    sendATcommand("AT+HTTPTERM", "OK", 5000);
    
}

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("Help me! I've been stolen. Find me in:");
        Serial.print("Latitude: ");
              int i = 0;
              while(latitude[i]!=0){
              Serial.print(latitude[i]);
              i++;
              }
              Serial.print(" / 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);
    }

}
        

Second step. When the GPS fix the GPS satellites, the GPRS+GPS shield will connect to the network and it will send the GPS data through the Internet to the php script in your computer.

Code:
<?php

    
if (!empty($_GET['latitude']) && !empty($_GET['longitude']) &&
        !empty(
$_GET['time']) && !empty($_GET['satellites']) &&
        !empty(
$_GET['speedOTG']) && !empty($_GET['course'])) {

        function 
getParameter($par$default null){
            if (isset(
$_GET[$par]) && strlen($_GET[$par])) return $_GET[$par];
            elseif (isset(
$_POST[$par]) && strlen($_POST[$par])) 
                return 
$_POST[$par];
            else return 
$default;
        }

        
$file 'gps.txt';
        
$lat getParameter("latitude");
        
$lon getParameter("longitude");
        
$time getParameter("time");
        
$sat getParameter("satellites");
        
$speed getParameter("speedOTG");
        
$course getParameter("course");
        
$person $lat.",".$lon.",".$time.",".$sat.",".$speed.",".$course."\n";
        
        echo 
"
            DATA:\n
            Latitude: "
.$lat."\n
            Longitude: "
.$lon."\n
            Time: "
.$time."\n
            Satellites: "
.$sat."\n
            Speed OTG: "
.$speed."\n
            Course: "
.$course;

        if (!
file_put_contents($file$personFILE_APPEND LOCK_EX))
            echo 
"\n\t Error saving Data\n";
        else echo 
"\n\t Data Save\n";
    }
    else {

?>

<!DOCTYPE html>
<html>
    
<head>

    <!-- Load Jquery -->

    <script language="JavaScript" type="text/javascript" src="jquery-1.10.1.min.js"></script>

    <!-- Load Google Maps Api -->

    <!-- IMPORTANT: change the API v3 key -->

    <script src="http://maps.googleapis.com/maps/api/js?key=your_key&sensor=false"></script>

    <!-- Initialize Map and markers -->

    <script type="text/javascript">
        var myCenter=new google.maps.LatLng(41.669578,-0.907495);
        var marker;
        var map;
        var mapProp;

        function initialize()
        {
            mapProp = {
              center:myCenter,
              zoom:15,
              mapTypeId:google.maps.MapTypeId.ROADMAP
              };
            setInterval('mark()',5000);
        }

        function mark()
        {
            map=new google.maps.Map(document.getElementById("googleMap"),mapProp);
            var file = "gps.txt";
            $.get(file, function(txt) { 
                var lines = txt.split("\n");
                for (var i=0;i<lines.length;i++){
                    console.log(lines[i]);
                    var words=lines[i].split(",");
                    if ((words[0]!="")&&(words[1]!=""))
                    {
                        marker=new google.maps.Marker({
                              position:new google.maps.LatLng(words[0],words[1]),
                              });
                        marker.setMap(map);
                        map.setCenter(new google.maps.LatLng(words[0],words[1]));
                        document.getElementById('sat').innerHTML=words[3];
                        document.getElementById('speed').innerHTML=words[4];
                        document.getElementById('course').innerHTML=words[5];
                    }
                }
                marker.setAnimation(google.maps.Animation.BOUNCE);
            });

        }

        google.maps.event.addDomListener(window, 'load', initialize);
    </script>
</head>

<body>
    <?php
        
echo '    

        <!-- Draw information table and Google Maps div -->

        <div>
            <center><br />
                <b> SIM908 GPS position DEMO </b><br /><br />
                <div id="superior" style="width:800px;border:1px solid">
                    <table style="width:100%">
                        <tr>
                            <td>Time</td>
                            <td>Satellites</td>
                            <td>Speed OTG</td>
                            <td>Course</td>
                        </tr>
                        <tr>
                            <td id="time">'
date("Y M d - H:m") .'</td>
                            <td id="sat"></td>
                            <td id="speed"></td>
                            <td id="course"></td>
                        </tr>
                </table>
                </div>
                <br /><br />
                <div id="googleMap" style="width:800px;height:700px;"></div>
            </center>
        </div>'
;
    
?>
</body>
</html>

<?php ?>

To use the php script you need an Apache server with php active. You can run the script in a PC installing Apache with php. You can do this easily with the installer from this pages ( or the package manger for linux):

In these websites, you have manuals to help you to install the server and active the php.

Extract the next php script on your computer. When a frame is received, a marker will shown in the map. You must change the Google Maps API v3 key in the php script:

"http://maps.googleapis.com/maps/api/js?key=your_key&sensor=false"

To show the map with the marker you need to access to the next url:

http://your_IP_or_domain/demo_sim908.php

The IP address or server domain must be the same used in the skecth of arduino (In case you are running the demo on your computer, replace "your_IP_or_domain" by "localhost")

Download Demo files

STEP 5: Results: GPS realtime geolocation tracking

SIM908 module identify your phone number when you call it and if it is correct, the GPS fixes the GPS satellites. The GPRS+GPS shield will connect to the network and 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 car. It starts to send the HTTP request every few seconds with data of the position (latitude and longitude).

When you find your car, you only have to reset your arduino and it is ready to work again!

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

Get the kit

GPRS +GPS:



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: