Dear colleagues,
Here is my geofencing code, with some explanation.
//GEOFENCING by Dacha011
// Works only north of the equator, and West of the prime meridian. (only positive GPS coordinates)
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
TinyGPSPlus gps; //GPS Object
SoftwareSerial SerialPort(3, 2);
long latitude; //Latitude (North - South)
long longitude; //Longitude (East - West)
long scale = 10000000UL; //10 milion. Why ? This technique is called - integer scaling. Please see below
long long timer = millis(); //timer
unsigned int interval = 4000; //interval
void setup() {
Serial.begin(9600);
SerialPort.begin(9600);
pinMode(7,OUTPUT); //buzzer
}
void loop() {
gpsTelemetrija();
}
void gpsTelemetrija() { // this function will take GPS data from the module, and compare it with some points on the map that I predefined
if (millis() - timer > interval ) // check once in 4 sec
{
while (SerialPort.available() > 0) { //
gps.encode(SerialPort.read()); //
if (gps.location.isUpdated()) { //
latitude = gps.location.rawLat().deg * scale + gps.location.rawLat().billionths / 100UL;
longitude = gps.location.rawLng().deg * scale + gps.location.rawLng().billionths / 100UL;
/*
The GPS Module is givin you raw LAT and LNG data. LAT and LNG are given in degrees and billionths, as two separate values.
The raw data won't be given to you in a decimal format such as 50.123456, but reather as 50 degrees and 1234567895 billionths.
You want to store LAT (or LGN) in one variable (and not two, the virst variable for degrees, the other one for billionts).
If you save it as a float number, it will be preceise only up to 5 decimal places.
So here comes the important trick - you will store all the degrees and billionth values in a long data type variable.
Degrees will be multiplied with the variable scale(10 milion) - e.g. 30 degrees N * 10000000UL = 300000000 (9 digits)
Billionths will be devided by 100UL. Why ? To get a 7 digits number, that will be added to the 9 digits degree value
(You want to leave alone the first 2 digits of your degrees value. Billionths should begin from the third digit)
This technique is called integer scaleing.
note: UL should be added at the end of every long data type value. i.e. long = 12657854UL;
*/
Serial.println(" - - - - - ");
Serial.print("Current coordinates: ");
Serial.print (latitude);
Serial.print (" - ");
Serial.println (longitude);
timer = millis(); //reset timer
if (compare(448073075UL, 448068685UL, 205191775UL, 205187295UL, latitude, longitude, " Parking ") == true) {
zvono(1); //beep once
}
else if (compare(448096755UL, 448093755UL, 205156795UL, 205153305UL, latitude, longitude, " Church ") == true) {
zvono(2);
}
else if (compare(448087235UL, 448082105UL, 205135965UL, 205126365UL, latitude, longitude, " Gas pump") == true) {
zvono(3);
}
else if (compare(448040065UL, 448036235UL, 205205835UL, 205200315UL, latitude, longitude, " Crossroad ") == true) {
zvono(4); //beep 4 times
}
else
Serial.println("Not in a predefined zone");
}
}
}
}
bool compare (long Latmax, long Latmin, long Lngmax, long Lngmin, long latit, long longitude, String place) { //Analyze if the GPS module is within the predefined boundries
/* Let's say you want to know when your gps module is near a supermarket.
Open a map on your browser and define a rectangle/square around your target. Save the next 4 values of your square/rectangle:
Upper left corner LAT and LGN (Latmax and Lngmin)
Bottom left corner LAT (Latmin)
Upper right corner LGN (Lngmax)
IMPORTANT NOTE: Latmin/max and Lngminmax must have 9 digits. So add the 9th digit, in case your browser map gives you only 8 numbers.
i.e. 57.123456 N will be 571234565UL (I added 5 at the end, and then UL)
*/
if ((latitude > Latmin) and (latitude < Latmax)) { //if latitude is between lat max and lat min
if ((longitude > Lngmin) and (longitude < Lngmax) ) { //if yes, check longitude
Serial.print("Location: "); //if both lat and lgn are within the zone - BINGO ! Print the name of the zone
Serial.print(place);
return true;
}
}
else {
// zero
return 0;
}
Serial.println (" ----------------- ");
}
void zvono (int x) { //buzzer. The argument is the number of time the buzzer should ring
for (int a = 0; a < x; a++) {
tone(7, 22, 30);
delay(200);
}
}
It works perfectly. The buzzer beeps as soon as I enter in the predefined zone.
A few observations :
-
I'm sure there are simpler and more elegant geofencing codes around. I wrote this one, and it works ok for me.
-
This code is probably an overkill because it's storing 7 digital places (0.11 m precision, while the NEO 6 module has an error of 5-10+m in ideal conditions), but at least you will learn the integer scaling method
You might need it tomorrow
-
It's possible to store the lat and lgn details as a float (5DPs will give you 1m precision), but I decided to go for a more precise solution.
-
LAT and LGN can also be stored as strings, and then those strings can be compared, but I wanted to explore the code @jremington wrote me.
-
I'm certain someone who's good with math can write a function that has 3 arguments - the LAT and LNG of a point, and a DIAMETER, so that the geofenced zone will be a circle, and you just have to define the center point and diameter.
I'm not that good with math 
Fell free to criticize my code, or suggest some improvement (that will not radical change my code) 
Thanks again guys, without you the path to the solution would be miles longer.
Cheers ! <3