piątek, 16 czerwca 2017

Lokalizator z Arduino (GPS & GSM)

Niestety paczka z elementami do urządzenia które chciałem Wam opisać przez długi weekend będzie dopiero w poniedziałek. Ale przyjdzie też na to czas :)

Dziś chciałbym Wam przedstawić co stworzyłem rok temu. Mianowicie lokalizator GPS&GSM.


Zapewne wielu słyszało o takich urządzeniach, stosuje się je najczęściej w samochodach aby namierzyć skradzione auto. Lecz można też użyć go w celach szpiegowskich :D

Ja od dawna chciałem podziałać z modułem GSM. Pomysł wpadł mi do głowy więc zostało zrealizować go!




Założenia:
-względnie małe rozmiary
-zasilanie bateryjne
-łatwość komunikacji
-przekazywanie współrzędnych nanoszonych na mapę



Po szybkim przeglądnięciu znanego chińskiego targu internetowego :D znalazłem potrzebne mi części:
-Atmega328p + kwarc + kondensatory
-moduł GSM SIM900A
-moduł GPS Neo-6m
-przetwornica step-up MT3608
-3x ogniwa 18650 (tym razem nowe)
-moduł ładowania ogniw z zabezpieczeniem
-płytka uniwersalna, kabelki, złącze śrubowe, włącznik, śrubki dystansowe i koszyk na ogniwa
-termoglut <3



Oczywiście powinienem tutaj wspomnieć że do stworzenia całości natchnął mnie artykuł w Elektronice Praktycznej. Jest on dostępny w linku poniżej :
http://ep.com.pl/files/11526.pdf

Jest tam również opisane jak przystosować moduł Sim900A do naszych sieci, jest do tego potrzebny konwerter USB-UART i chwila cierpliwości :) A warto bo różnica w cenie względem modułu Sim900 to 5$ :D

Podłączenie całości nie powinno sprawić problemów, oba moduły komunikują się z atmega po uarcie (RX,TX), lecz jak wiadomo atmega328 posiada tylko jeden sprzętowy port uart. Drugi stworzyłem wirtualny za pomocą biblioteki SoftwareSerial.

Przetwornica ustawiona jest potencjometrem na wyjściowe napięcie 5V które zasila atmegę oraz dwa moduły. Goła atmega posiada kondensatory 100n między masą a zasilaniem(najlepiej stosować jak najbliżej), oraz kwarc 16MHz.



Proste jak budowa cepa ;)

Co by się dużo nie rozwodzić, przejdźmy do kodu :


#include <SoftwareSerial.h>
#include <TinyGPS++.h>
TinyGPSPlus gps;
SoftwareSerial ss(3, 4);
//---zmienne - komunikacja-----------------------------
String gsmBuffer;
int gsmComplete;
int command_delay;
int gsm_step;
int pos;
int end_pos;
String command;
int param;
//---zmienne - siec------------------------------------
int sygnal;
//---zmienne- sms-------------------------------------- 
String string_param;
String string_number;
String string_sms;
//---setup---------------------------------------------
void setup() {
  //konfigurowanie interfejsu szeregowego 
  ss.begin(9600);  //do komunikacji z modułem GPS
  Serial.begin(9600);   //do komunikacji z modułem GSM
  //początkowe wartości zmiennych
  sygnal = 0;
  gsmComplete = 11;
  //czas dla wystartowania modułu GSM
  command_delay = -600;
  delay(1000);
}
//---main----------------------------------------------
void loop() { 
    while (ss.available() > 0) // jezeli cos przychodzi na ss port to czyta i odkoduje
    {
    gps.encode(ss.read());
    }
  //odliczanie czasu do następnej komendy
  if (command_delay <= 300) command_delay++;
  //czas miną - następna komenda
  if (command_delay > 300) {
    command_delay = 0;  
    gsmBuffer = "";
    //wybór komendy dla modułu GSM
    switch (gsm_step) {
      case 0: {
        //wyłącza echo
        Serial.print("ATE0\r");
      } break;
      case 1: {
        //zezwala na logowanie do sieci GSM
        Serial.print("AT+CREG=1\r");
      } break;
      case 2: {
        //sprawdza stan zalogowania do sieci GSM
        Serial.print("AT+CREG?\r");      
      } break;
      case 3: {
        //kasuje wszystkie smsy
        Serial.print("AT+CMGDA=\"DEL ALL\"\r"); 
      } break;
      case 4: {
        //określa tekstowy tryb odczytu SMS
        Serial.print("AT+CMGF=1\r");
      } break;
      case 5: {
        //sprawdza siłę sygnału sieci GSM
        Serial.println("AT+CSCS=\"GSM\"");      
      } break;      
      case 6: {
        //odczytuje SMS z pozycji 1
        Serial.print("AT+CMGR=1\r");      
      } break;
      case 7: {
        //odpisuje sms na numer który przysłał wiadomość
        while(!gps.location.isValid())// dopoki dane z gps'a nie sa dostepne wykonuje fukcje czytam
        {
          czytam();
        }
        if(gps.location.isValid()){
        Serial.println("AT+CMGS=\"NUMER_TELEFONU\"");
        delay(1000);
        Serial.print("https://www.google.pl/maps/place/");
        Serial.print(gps.location.lat(), 6);
        Serial.print("N+");
        Serial.print(gps.location.lng(), 6);
        Serial.print("E");
        Serial.write(0x1A);
        }
      } break;
      case 8: {
        //kasuje wszystkie sms
        Serial.print("AT+CMGDA=\"DEL ALL\"\r"); 
      } break;          
    }
  }
  //odpieranie z UART
  gsmReceive();
  //czeka na odebranie pakietu danych
  //pakiet konczy sie przerwą w odbieraniu danych
  if (gsmComplete <= 10) gsmComplete++;  
  if (gsmComplete == 10) {
    //wybiera akcję w zalezności od komendy
    switch (gsm_step) {
      case 0: {                   //ATE0
          OkGet();
          if (command == "OK") gsm_step++;           
          command_delay = 200;
      } break;
      case 1: {                   //AT+CREG=1\r"
          OkGet();
          gsm_step=3;           
          command_delay = 200;
      } break;    
      case 2: {                   //AT+CREG?
        CommandGet();
        ParamGet(2);
        if (param == 1) {
          gsm_step++;
        }
      } break;
      case 3: {                   //AT+CMGDA="DEL ALL"
          OkGet();
          gsm_step++;           
          command_delay = 200;     
      } break;
      case 4: {                   //AT+CMGF=1
          OkGet();
          gsm_step++;           
          command_delay = 200;
     } break;
      case 5: {                   //AT+CSQ
          OkGet();
          Serial.println("AT+CMGS=\"NUMER_TELEFONU\"");
          delay(300);
          Serial.print("GSM DZIALA");      
          Serial.write(0x1A);
          gsm_step++;           
          command_delay = 200;
      } break;
      case 6: {                   //AT+CMGR=1
          CommandGet();
          //jeśli odczytano SMS 
          if (command == "CMGR") {         
            //nastepny etap - kasowanie SMS
            gsm_step = 8;            
            //jeśli SMS zawiera treść
            if (StringSmsGet() > 0) { 
              //określa numer nadawcy
              StringParamGet(2);             
              string_number = string_param;
              //jesli polecenie załaczenia 
              if (string_sms == "gdzie jestes") {
                //nastepny etap - wysyłanie potw.
                gsm_step = 7;
              }
            }
          //jesli nie ma SMS
          } else {
            OkGet();
            //wróć do sprawdzania nowego SMS'a
            gsm_step = 6;
          }
      } break;
      case 7: {                   //"AT+CMGS=
          CommandGet();
          if (command == "CMGS") gsm_step++;           
      } break; 
      case 8: {                   //AT+CMGD=1
          OkGet();
          gsm_step = 6;           
      } break; 
    }
    //na koniec wyczyść bufor odebranych danych
    gsmBuffer = "";
  }
  //przerwa pętli głównej  
  delay(20);
}
//odbieranie danych z GSM
void gsmReceive()
{
  while (Serial.available()) {          //jeśli coś odebrane
    char inData = (char)Serial.read();  //odbierz dane
    gsmBuffer += inData;                 //i umieść w buforze
    gsmComplete = 0;                     //pakiet w trakcie
    command_delay = 0;                   //zaczekaj z komendą
  }
}
//uzyskuje nazwę komendy z odebranego pakietu
int CommandGet(void) {
    command = "---";
    pos = gsmBuffer.indexOf("+");
    if (pos > 0) {
      pos = pos + 1;
      end_pos = gsmBuffer.indexOf(":", pos);
      command = gsmBuffer.substring(pos, end_pos);    
    }
  }
//uzyskuje potwierdzeie OK z odebranego pakietu
int OkGet(void) {
    command = "---";
    pos = gsmBuffer.indexOf("\n");
    if (pos > 0) {
      pos = pos + 1;
      end_pos = gsmBuffer.indexOf("\r", pos);
      command = gsmBuffer.substring(pos, end_pos);    
    }
  }
//uzyskuje wartość określonego parametru z pakietu
int ParamGet(int index) {
    param = 0;
    pos = gsmBuffer.indexOf(":");
    if (pos > 0) {
      pos = pos + 2;
      if (index > 1) {
        pos = gsmBuffer.indexOf(",", pos);    
        pos = pos + 1;    
      }
      if (index > 2) {
        pos = gsmBuffer.indexOf(",", pos);    
        pos = pos + 1;    
      }
      param = (gsmBuffer.charAt(pos) - '0');
      pos = pos + 1;
      if ((gsmBuffer.charAt(pos) >= '0') && (gsmBuffer.charAt(pos) <= '9')) {
        param *= 10;
        param += (gsmBuffer.charAt(pos) - '0');
      }
    }    
}
//uzyskuje parametr typu String z pakietu
int StringParamGet(int index) {
    string_param = "---";
    pos = gsmBuffer.indexOf(":");
    if (pos > 0) {
      pos = pos + 2;        //skip :_
      if (index > 1) {
        pos = gsmBuffer.indexOf(",", pos);    
        pos = pos + 1;      //skip ,
      }
      if (index > 2) {
        pos = gsmBuffer.indexOf(",", pos);    
        pos = pos + 1;      //skip ,
      }
      pos = pos + 1;        //skip "
      end_pos = gsmBuffer.indexOf(34, pos);   //find second "
      string_param = gsmBuffer.substring(pos, end_pos); 
    }   
}
//uzyskuje tresc SMSa z pakietu
int StringSmsGet(void) {
    pos = gsmBuffer.indexOf(":");
    if (pos > 0) {
      pos = gsmBuffer.indexOf("\n", pos);  
      pos = pos + 1;
      end_pos = gsmBuffer.indexOf("\r", pos);
      string_sms = gsmBuffer.substring(pos, end_pos);
      return 1;
    } else {
      string_sms = "";
      return -1;
    }
}
void czytam() // pobiera dane z gps
{
    while (Serial.available() > 0) {
    gps.encode(Serial.read());}
}
Kod to przerobiony przeze mnie program z Elektroniki Praktycznej o którym pisałem wcześniej. Mam nadzieję że komentarze są na tyle jasne, że każdy go zrozumie. W razie niejasności piszcie komentarze :)

No ale jak to działa w praktyce :
-Po włączeniu i sprawdzeniu komunikacji gps&gsm arduino wysyła sms'a do zadeklarowanego numeru "GSM DZIALA"
-Jeśli otrzyma sms'a od zadeklarowanego numeru o treści "gdzie jestes" to pobiera współrzędne geograficzne z modułu GPS i skleja je w link do google maps'a który wysyła sms'em


Taka opcja jest bardzo wygodna bo mając "smartfona" z internetem można od razu mieć zaznaczoną na mapie lokalizację urządzenia.


Testowałem urządzenie kilkukrotnie, zostawione w bagażniku auta odpytywałem o lokalizację co jakiś czas i baterie pozwoliły na działanie przez 52 godziny co daje nam 2 dni i 4 godziny co jest wg mnie dobrym wynikiem.



Jeśli miałbym coś zmienić to dodałbym ładowanie baterii z samochodowego akumulatora kiedy silnik pracuje. Konstrukcja nie wygląda ale latała po bagażniku i nic się nie uszkodziło. Można zastosować rzep jako przytwierdzenie całości lub przyssawkę.

Koszt urządzenia to około 100-120zł zamawiając wszystko poza ogniwami u skośnokich przyjaciół :)
Zapraszam do komentowania i udostępniania dalej tego wpisu !


// Biblioteki :
https://drive.google.com/open?id=0B0smkZD6bk_1RWMtYnRJQm1XYjg

6 komentarzy:

  1. Wada tych lokalizatorów to bez wątpienia fakt, że kartę SIM trzeba regularnie doładowywać, żeby mogła wysłać SMSa... Jak nie doładujesz w porę to może się okazać, że ktoś Ci gwizdnie autko a Ty i tak nie otrzymasz jego lokalizacji ;/ Poza tym jak zasilanie padnie to też trochę kicha.

    OdpowiedzUsuń
    Odpowiedzi
    1. Zarejestrowałem kartę w pewnej sieci i mam konto ważne rok, po każdym doładowaniu też. Sms jest tani więc doładowanie za 5zł starcza na bardzo długo, a przecież nie odpytujemy lokalizacji co godzinę codziennie :)

      Usuń
  2. "Morning Sir..I have try,but still no such file or directory Tinygps++.h.I am using ide 168 and 101.Any sugestion to resolve t

    OdpowiedzUsuń
    Odpowiedzi
    1. Did You try files from this link ? https://drive.google.com/open?id=0B0smkZD6bk_1RWMtYnRJQm1XYjg

      Usuń
  3. W firma logistycznych często jest taki monitoring gps wykorzystywany https://www.gpsguardian.pl/, dzięki temu oprócz oczywiście kwestii bezpieczeństwa, pracodawca ma możliwość spoglądania jak użytkowany jest samochód oraz czy kierowca nie jeździ za firmowe paliwo tam gdzie nie powinien.

    OdpowiedzUsuń
  4. Fajna rzecz tylko brakuje mi w tym przekaźnika sterowanego SMS-em odcinającego zapłon.

    OdpowiedzUsuń