Forum >Position error with GPS/GSM v3
Position error with GPS/GSM v3

Hi,
I have been trying to fix the position reported by the dfrobot gsm, gps unit. Everything else is working but it keeps reporting the wrong position. I have the unit connected to a 12V 1A power supply, I am outside in a field and I am using the source code directly from the wiki:
http://www.dfrobot.com/wiki/index.php/G ... KU:TEL0051)
I found a post on a similar sounding problem, but it seems to be a parsing bug with the seconds part of the coordinate where as mine seems to be a problem with the minutes and seconds:
http://forum.arduino.cc/index.php?topic=269950.0
Here are two examples of the errors: I have attached images showing the distance on a map:
Actual:
53.368396, -6.260327
predicted:
53.2210502 -6.156313
difference:
.147346, .1040136
http://imgur.com/g3YsinB
53.573537, -6.448472
Recorded:
53.3443641, -6.2690668
difference:
.229173, .1794052
http://imgur.com/J5sBYIg
I have linked two images showing the error. The error seems to be in the same direction but of a different magnitude.
I looked at the raw serial data and it looks like this:
5322.09864, 0615.61676
and the previous post says that the format is:
DDmm.ddddd
so the datatransfer function is converting it like this:
5322.09864, 0615.61676 -> 53.2210502 -6.156313
if we just look at the minutes first, 22 minutes are being passed in and it is saying the decimal value is 22.
If I divide 22 by 60 I get .36 which is much closer to the actual decimal coordinate of 53.368396,
the same is correct if I divide the minutes on the longitude:
raw: 0615.61676
minutes = 15
decimalised = .25
actual longitude minutes = .26
So it looks like the data-transfer function is parsing it incorrectly. I am still trying to work out how to fix the seconds so any help would be appreciated.
I have been trying to fix the position reported by the dfrobot gsm, gps unit. Everything else is working but it keeps reporting the wrong position. I have the unit connected to a 12V 1A power supply, I am outside in a field and I am using the source code directly from the wiki:
http://www.dfrobot.com/wiki/index.php/G ... KU:TEL0051)
I found a post on a similar sounding problem, but it seems to be a parsing bug with the seconds part of the coordinate where as mine seems to be a problem with the minutes and seconds:
http://forum.arduino.cc/index.php?topic=269950.0
Here are two examples of the errors: I have attached images showing the distance on a map:
Actual:
53.368396, -6.260327
predicted:
53.2210502 -6.156313
difference:
.147346, .1040136
http://imgur.com/g3YsinB
53.573537, -6.448472
Recorded:
53.3443641, -6.2690668
difference:
.229173, .1794052
http://imgur.com/J5sBYIg
I have linked two images showing the error. The error seems to be in the same direction but of a different magnitude.
I looked at the raw serial data and it looks like this:
5322.09864, 0615.61676
and the previous post says that the format is:
DDmm.ddddd
so the datatransfer function is converting it like this:
5322.09864, 0615.61676 -> 53.2210502 -6.156313
if we just look at the minutes first, 22 minutes are being passed in and it is saying the decimal value is 22.
If I divide 22 by 60 I get .36 which is much closer to the actual decimal coordinate of 53.368396,
the same is correct if I divide the minutes on the longitude:
raw: 0615.61676
minutes = 15
decimalised = .25
actual longitude minutes = .26
So it looks like the data-transfer function is parsing it incorrectly. I am still trying to work out how to fix the seconds so any help would be appreciated.
2022-01-14 23:46:42 hi ítvan!
After I change the code like yours, my arduino gives error like this\\
C:\Program Files (x86)\Arduino\libraries\DFRobot_SIM808-master\DFRobot_sim808.cpp:1018:49: error: no 'double DFRobot_SIM808::decimalgps(double)' member function declared in class 'DFRobot_SIM808'
double DFRobot_SIM808::decimalgps(double rawdata)
^
C:\Program Files (x86)\Arduino\libraries\DFRobot_SIM808-master\DFRobot_sim808.cpp: In member function 'bool DFRobot_SIM808::getGPS()':
C:\Program Files (x86)\Arduino\libraries\DFRobot_SIM808-master\DFRobot_sim808.cpp:1078:20: error: 'decimalgps' was not declared in this scope
float latitude = decimalgps(newlat);
^~~~~~~~~~
Let me know what I need to do next, your help will be greatly appreciated!
vankienyt3
After I change the code like yours, my arduino gives error like this\\
C:\Program Files (x86)\Arduino\libraries\DFRobot_SIM808-master\DFRobot_sim808.cpp:1018:49: error: no 'double DFRobot_SIM808::decimalgps(double)' member function declared in class 'DFRobot_SIM808'
double DFRobot_SIM808::decimalgps(double rawdata)
^
C:\Program Files (x86)\Arduino\libraries\DFRobot_SIM808-master\DFRobot_sim808.cpp: In member function 'bool DFRobot_SIM808::getGPS()':
C:\Program Files (x86)\Arduino\libraries\DFRobot_SIM808-master\DFRobot_sim808.cpp:1078:20: error: 'decimalgps' was not declared in this scope
float latitude = decimalgps(newlat);
^~~~~~~~~~
Let me know what I need to do next, your help will be greatly appreciated!

2019-01-08 14:23:41 Hi all,
I noticed the same accuracy problem with my DFRobot SIM808 board (I'm testing in Hungary and here the rounding problem resulted approx 3 km difference from the expected result) Based on the code posted by Byrne I made some modifications on DFRobot_sim808.cpp , now it returns accurate GPS coordinates. I'm posting the modified function, perhaps it will be useful to others.
Csaba
horvath.csaba.istvan
I noticed the same accuracy problem with my DFRobot SIM808 board (I'm testing in Hungary and here the rounding problem resulted approx 3 km difference from the expected result) Based on the code posted by Byrne I made some modifications on DFRobot_sim808.cpp , now it returns accurate GPS coordinates. I'm posting the modified function, perhaps it will be useful to others.
Csaba
Code: Select all
//HCS insert correction begin double DFRobot_SIM808::decimalgps(double rawdata) { int degrees = (int)(rawdata / 100); double minutes = rawdata - (degrees*100); double mindecimal = minutes / 60.0; double total = degrees + mindecimal; // Serial.println("degrees:"); // Serial.println(degrees,5); // Serial.println("minutes:"); // Serial.println(minutes,5); // Serial.println("final:"); // Serial.println(total,5); return total; } //HCS insert correction end bool DFRobot_SIM808::getGPS() { if(!getGPRMC()) //没有得到$GPRMC字符串开头的GPS信息 return false; // Serial.println(receivedStack); if(!parseGPRMC(receivedStack)) //不是$GPRMC字符串开头的GPS信息 return false; // skip mode char *tok = strtok(receivedStack, ","); //起始引导符 if (! tok) return false; // grab time //<1> UTC时间,格式为hhmmss.sss; // tok = strtok(NULL, ","); char *time = strtok(NULL, ","); if (! time) return false; uint32_t newTime = (uint32_t)parseDecimal(time); getTime(newTime); // skip fix tok = strtok(NULL, ","); //<2> 定位状态,A=有效定位,V=无效定位 if (! tok) return false; // grab the latitude char *latp = strtok(NULL, ","); //<3> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输) if (! latp) return false; // grab latitude direction // <4> 纬度半球N(北半球)或S(南半球) char *latdir = strtok(NULL, ","); if (! latdir) return false; // grab longitude //<5> 经度dddmm.mmmm(度分)格式(前面的0也将被传输) char *longp = strtok(NULL, ","); if (! longp) return false; // grab longitude direction //<6> 经度半球E(东经)或W(西经) char *longdir = strtok(NULL, ","); if (! longdir) return false; //HCS insert corrections begin double newlat = atof(latp); double newlon = atof(longp); float latitude = decimalgps(newlat); float longitude = decimalgps(newlon); GPSdata.lat = latitude; GPSdata.lon= longitude; //HCS insert corrections end /* HCS remove begin float latitude = atof(latp); float longitude = atof(longp); GPSdata.lat = latitude/100; // convert longitude from minutes to decimal GPSdata.lon= longitude/100; HCS remove end */ // only grab speed if needed //<7> 地面速率(000.0~999.9节,前面的0也将被传输) // if (speed_kph != NULL) { // grab the speed in knots char *speedp = strtok(NULL, ","); if (! speedp) return false; // convert to kph //*speed_kph = atof(speedp) * 1.852; GPSdata.speed_kph= atof(speedp) * 1.852; // } // only grab heading if needed // if (heading != NULL) { // grab the speed in knots char *coursep = strtok(NULL, ","); if (! coursep) return false; //*heading = atof(coursep); GPSdata.heading = atof(coursep); // } // grab date char *date = strtok(NULL, ","); if (! date) return false; uint32_t newDate = atol(date); getDate(newDate); // no need to continue // if (altitude == NULL){ // return true; //} return true; }

2016-05-07 08:23:49 thanks Mr. Byrne Jonathan, I was try your code and thats work correctly..
but can you help me how to send the location to the server with this code?
I was trying to mix your code with the other one that can send via URL to the server, but didn't work, I think that because I use the GPRS function (using AT Command too), and your code not work properly..
Edited:
I alredy know how to solve my problem.. thanks before.. your function really cool..
putu.adhi.purwanto
but can you help me how to send the location to the server with this code?
I was trying to mix your code with the other one that can send via URL to the server, but didn't work, I think that because I use the GPRS function (using AT Command too), and your code not work properly..
Edited:
I alredy know how to solve my problem.. thanks before.. your function really cool..

2015-09-30 03:33:08 No problem! I have tried it again and it is giving me 10 metre accuracy, I am going to try a different location today to see if it works. I have attached my new source code that prints google maps friendly coordinates, you might have to change a minus to a plus depending which hemisphere you are in:
byrne jonathan
Code: Select all
// Product name: GPS/GPRS/GSM Module V3.0
// # Product SKU : TEL0051
// # Version : 1.2
// # Description:
// # The sketch for driving the gps mode via the Arduino board
// # Steps:
// # 1. Turn the S1 switch to the Prog(right side)
// # 2. Turn the S2 switch to the Arduino side(left side)
// # 3. Set the UART select switch to middle one.
// # 4. Upload the sketch to the Arduino board
// # 5. Turn the S1 switch to the comm(left side)
// # 6. RST the board
// # If you get 'inf' values, go outdoors and wait until it is connected.
// # wiki link- https://www.dfrobot.com/wiki/index.php/GPS/GPRS/GSM_Module_V3.0_(SKU:TEL0051)
double Datatransfer(char *data_buf,char num)//convert the data to the float type
{ //*data_buf:the data array
double temp=0.0; //the number of the right of a decimal point
unsigned char i,j;
if(data_buf[0]=='-')
{
i=1;
//process the data array
while(data_buf[i]!='.')
temp=temp*10+(data_buf[i++]-0x30);
for(j=0;j<num;j++)
temp=temp*10+(data_buf[++i]-0x30);
//convert the int type to the float type
for(j=0;j<num;j++)
temp=temp/10;
//convert to the negative numbe
temp=0-temp;
}
else//for the positive number
{
i=0;
while(data_buf[i]!='.')
temp=temp*10+(data_buf[i++]-0x30);
for(j=0;j<num;j++)
temp=temp*10+(data_buf[++i]-0x30);
for(j=0;j<num;j++)
temp=temp/10 ;
}
return temp;
}
char ID()//Match the ID commands
{
char i=0;
char value[6]={
'$','G','P','G','G','A' };//match the gps protocol
char val[6]={
'0','0','0','0','0','0' };
while(1)
{
if(Serial.available())
{
val[i] = Serial.read();//get the data from the serial interface
if(val[i]==value[i]) //Match the protocol
{
i++;
if(i==6)
{
i=0;
return 1;//break out after get the command
}
}
else
i=0;
}
}
}
void comma(char num)//get ','
{
char val;
char count=0;//count the number of ','
while(1)
{
if(Serial.available())
{
val = Serial.read();
if(val==',')
count++;
}
if(count==num)//if the command is right, run return
return;
}
}
void UTC()//get the UTC data -- the time
{
char i;
char time[9]={
'0','0','0','0','0','0','0','0','0'
};
double t=0.0;
if( ID())//check ID
{
comma(1);//remove 1 ','
//get the datas after headers
while(1)
{
if(Serial.available())
{
time[i] = Serial.read();
i++;
}
if(i==9)
{
i=0;
t=Datatransfer(time,2);//convert data
//t=t-30000.00;//convert to the chinese time GMT+8 Time zone
long time=t;
int h=time/10000;
int m=(time/100)%100;
int s=time%100;
if(h>=24) //UTC+
{
h-=24;
}
// if (h<0) //UTC-
// {
// h+=24;
// }
Serial.print(h);
Serial.print("h");
Serial.print(m);
Serial.print("m");
Serial.print(s);
Serial.println("s");
//Serial.println(t);//Print data
return;
}
}
}
}
double decimalgps(double rawdata)
{
int degrees = (int)(rawdata / 100);
double minutes = rawdata - (degrees*100);
double mindecimal = minutes / 60.0;
double total = degrees + mindecimal;
// Serial.println("degrees:");
// Serial.println(degrees,5);
// Serial.println("minutes:");
// Serial.println(minutes,5);
// Serial.println("final:");
// Serial.println(total,5);
return total;
}
float latitude()//get latitude
{
char i;
char lat[10]={
'0','0','0','0','0','0','0','0','0','0'
};
if( ID())
{
comma(2);
while(1)
{
if(Serial.available())
{
lat[i] = Serial.read();
i++;
}
if(i==10)
{
i=0;
double newlat = Datatransfer(lat,5);
float corrected = decimalgps(newlat);
return corrected;
}
}
}
}
float longitude()//get longitude
{
char i;
char lon[11]={
'0','0','0','0','0','0','0','0','0','0','0'
};
if( ID())
{
comma(4);
while(1)
{
if(Serial.available())
{
lon[i] = Serial.read();
i++;
}
if(i==11)
{
i=0;
double newlon = Datatransfer(lon,5);
float corrected = decimalgps(newlon);
return corrected;
}
}
}
}
void altitude()//get altitude data
{
char i,flag=0;
char alt[8]={
'0','0','0','0','0','0','0','0'
};
if( ID())
{
comma(9);
while(1)
{
if(Serial.available())
{
alt[i] = Serial.read();
if(alt[i]==',')
flag=1;
else
i++;
}
if(flag)
{
i=0;
Serial.println(Datatransfer(alt,1),1);//print altitude data
return;
}
}
}
}
void setup()
{
pinMode(3,OUTPUT);//The default digital driver pins for the GSM and GPS mode
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
digitalWrite(5,HIGH);
delay(1500);
digitalWrite(5,LOW);
digitalWrite(3,LOW);//Enable GSM mode
digitalWrite(4,HIGH);//Disable GPS mode
delay(2000);
Serial.begin(9600);
delay(5000);//GPS ready
Serial.println("AT");
delay(2000);
//turn on GPS power supply
Serial.println("AT+CGPSPWR=1");
delay(1000);
//reset GPS in autonomy mode
Serial.println("AT+CGPSRST=1");
delay(1000);
digitalWrite(4,LOW);//Enable GPS mode
digitalWrite(3,HIGH);//Disable GSM mode
delay(2000);
Serial.println("$GPGGA statement information: ");
}
void loop()
{
while(1)
{
Serial.print("UTC:");
UTC();
float lat = latitude();
float lon = longitude();
Serial.println("coordinates:");
Serial.print(lat,5);
Serial.print(", ");
Serial.println(-lon,5);
Serial.print("Alt:");
altitude();
Serial.println(' ');
Serial.println(' ');
}
}

2015-09-28 22:14:14 Woah, terrific! Thanks for your wonderful job!
So the 5320.12345 means: 53° 20' 7.407"( 0.12345*60), and the 53.33539 can be used as Google map API data.
Besides, I also had a try around my buiding, but the result is not very accurate, the error is about 500 meters! Maybe it's because my test ppsition is between two narrow buildings~ I will have a test in an open field days later. But the method to deal with the raw data is correct!
Leff
So the 5320.12345 means: 53° 20' 7.407"( 0.12345*60), and the 53.33539 can be used as Google map API data.
Besides, I also had a try around my buiding, but the result is not very accurate, the error is about 500 meters! Maybe it's because my test ppsition is between two narrow buildings~ I will have a test in an open field days later. But the method to deal with the raw data is correct!

2015-09-28 08:08:55 Okay I figured it out. The raw gps information from the serial is in the form:
DDmm.mmmmm
so if the raw information is: 5320.12345 then it is:
53 degress and 20.12345 minutes. In order to convert it to decimal coordinates you divide the minutes by 60.
20.12345 / 60 = .33539
decimal result:
53.33539
byrne jonathan
DDmm.mmmmm
so if the raw information is: 5320.12345 then it is:
53 degress and 20.12345 minutes. In order to convert it to decimal coordinates you divide the minutes by 60.
20.12345 / 60 = .33539
decimal result:
53.33539

2015-09-24 23:42:01 No problem at all, I have coded up my 3 datapoints into a python dictionary so I can play around with it and see what error I am getting.
meatherror = {'name':"meath",
'actual':[53.573537, -6.448472],
'prediction': [53.3443641, -6.2690668],
'raw': [5334.43659, 0626.90668],
'difference':[.229173, .1794052]}
botanicerror = {'name':"botanic",
'actual':[53.368396, -6.260327],
'prediction': [53.2209854, -6.1561679],
'raw': [5322.09864, 0615.61676],
'difference':[]}
ucderror = {'name':"ucd",
'actual':[53.309376, -6.233880],
'prediction': [53.1857910, 6.1401019],
'raw': [5318.57866, 0614.01021],
'difference':[]}
byrne jonathan
meatherror = {'name':"meath",
'actual':[53.573537, -6.448472],
'prediction': [53.3443641, -6.2690668],
'raw': [5334.43659, 0626.90668],
'difference':[.229173, .1794052]}
botanicerror = {'name':"botanic",
'actual':[53.368396, -6.260327],
'prediction': [53.2209854, -6.1561679],
'raw': [5322.09864, 0615.61676],
'difference':[]}
ucderror = {'name':"ucd",
'actual':[53.309376, -6.233880],
'prediction': [53.1857910, 6.1401019],
'raw': [5318.57866, 0614.01021],
'difference':[]}

2015-09-24 20:43:32 Hello,
Welcome!
I've received your email yesterday! And I noticed that you said you are in outside. So assume the data was correct, and then let's disguss the data-transfer function, I am not so sure.
Here is one method which is what I already known: e.g. (From a Chinese website)
raw: 3612.432314 > 36.12432314
degree = 36°
minutes = "< 0.12432314×60=7.4593884> =7'
second = "<0.4593884×60=27.5639304> = 27"
Then, it's 36°7'27"
Tried on your raw: 5322.09864 > 53°13'15.55"
If it's possible the 13' is the real tested place? and would you mind use it to get a group of data to analyse?What do you think of it
Leff
Welcome!
I've received your email yesterday! And I noticed that you said you are in outside. So assume the data was correct, and then let's disguss the data-transfer function, I am not so sure.
Here is one method which is what I already known: e.g. (From a Chinese website)
raw: 3612.432314 > 36.12432314
degree = 36°
minutes = "< 0.12432314×60=7.4593884> =7'
second = "<0.4593884×60=27.5639304> = 27"
Then, it's 36°7'27"
Tried on your raw: 5322.09864 > 53°13'15.55"
If it's possible the 13' is the real tested place? and would you mind use it to get a group of data to analyse?What do you think of it

