对于项目,我正在关注如何跟踪位置并使用带有this SIM908盾牌的 Arduino 来输出GPS数据的this教程。 Arduino 正确地将GPS数据发送到数据库。但是,坐标都完全相同,似乎已经四舍五入。
例如:
Latitude: 52.216667
Longitude: 5.483333
这不是因为PHP
脚本,它所做的只是将它接收的数据放在数据库中。我的猜测是它与转换函数convert2Degrees
有关。
这是我们在 Arduino 上运行的代码:
int8_t answer;
int onModulePin= 2;
char data[100];
int data_size;
char aux_str[100];
char aux;
int x = 0;
char N_S,W_E;
char url[] = "informatica-corlaer.nl";
char frame[200];
char pin[]="0000";
char apn[]="mmm.nl";
char user_name[]="";
char password[]="";
char latitude[15];
char longitude[15];
char altitude[10];
char date[16];
char time[7];
char satellites[3];
char speedOTG[10];
char course[10];
void setup(){
pinMode(onModulePin, OUTPUT);
Serial.begin(115200);
Serial.println("Starting...");
power_on();
delay(3000);
//sets the PIN code
snprintf(aux_str, sizeof(aux_str), "AT+CPIN=%s", pin);
sendATcommand(aux_str, "OK", 2000);
delay(3000);
// starts the GPS and waits for signal
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);
snprintf(aux_str, sizeof(aux_str), "AT+SAPBR=3,1,\"APN\",\"%s\"", apn);
sendATcommand(aux_str, "OK", 2000);
snprintf(aux_str, sizeof(aux_str), "AT+SAPBR=3,1,\"USER\",\"%s\"", user_name);
sendATcommand(aux_str, "OK", 2000);
snprintf(aux_str, sizeof(aux_str), "AT+SAPBR=3,1,\"PWD\",\"%s\"", password);
sendATcommand(aux_str, "OK", 2000);
// gets the GPRS bearer
while (sendATcommand("AT+SAPBR=1,1", "OK", 20000) == 0)
{
delay(5000);
}
}
void loop(){
// gets GPS data
get_GPS();
// sends GPS data to the script
send_HTTP();
delay(5000);
}
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';
// 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<=10 ; 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/vehicleLocationTransmitter.php?", url);
Serial.print(aux_str);
sprintf(frame, "vehicleID=1&latitude=%s&longitude=%s&altitude=%s&time=%s&satellites=%s",
latitude, longitude, altitude, date, satellites);
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);
}
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;
}
答案 0 :(得分:1)
为有疑问的函数编写测试用例(convert2Degrees())
来自评论:“DD°MM.mmm中的参数'符号为DD.dddddd°”:
如果您输入:52°27.123
然后预期的输出应为:52.45205
计算:52°27.123 = 52 + 27.123 / 60.0 =
= 52.45205
此外,您应该在此处发布输入convert2Degrees()
的值答案 1 :(得分:0)
您对strtok
的使用不正确,convert2degrees
存在重大问题。
这是从NeoGPS派生的东西,它不使用昂贵的(在AVR上)除法或模运算:
//.................................................
// A special divide-by-3 function that avoids division.
// From http://www.hackersdelight.org/divcMore.pdf
static uint32_t divu3( uint32_t n )
{
uint32_t q = (n >> 2) + (n >> 4); // q = n*0.0101 (approx).
q = q + (q >> 4); // q = n*0.01010101.
q = q + (q >> 8);
q = q + (q >> 16);
uint32_t r = n - q*3; // 0 <= r <= 15.
return q + (11*r >> 5); // Returning q + r/3.
}
//------------------------------------------------------------
// Parse the NMEA "DDDMM.mmmm" format for lat and lon.
//
// returns degrees * 10^7
uint32_t parseDDMMmmmm( char *input )
{
uint8_t digits = 0;
uint8_t sixth_digit = 0;
char chr;
// Find the decimal point
while (isdigit( input[digits] ))
digits++;
// All but the last two are degrees.
uint32_t val = 0;
while (digits > 2) {
chr = *input++;
val = val*10 + (chr - '0');
digits--;
}
// convert from degrees to minutes
val *= 60;
// Add in the last 2 minutes digits
uint8_t minutes = 0;
while (digits > 0) {
chr = *input++;
minutes = minutes*10 + (chr - '0');
digits--;
}
val += minutes;
// Decimal point?
chr = *input++;
if (chr == '.') {
chr = *input++;
// Parse up to 6 digits of the fractional minutes.
while ((digits++ < 5) && isdigit( chr )) {
val = val*10 + (chr - '0');
chr = *input++;
}
if ((digits == 6) && isdigit(chr)) {
sixth_digit = chr - '0';
digits++;
}
// Scale the value up to minutes x 1000000.
while (digits < 4) {
val *= 10;
digits++;
}
}
// convert from minutes x 1000000 to degrees x 10000000.
val += divu3( val*2 + 1 ); // same as 10 * (val+30)/60 without truncation
if (digits >= 6) {
if (sixth_digit >= 9)
val += 2;
else if (sixth_digit >= 4)
val += 1;
}
return val;
} // parseDDMMmmmm
...和一个浮点版本:
double parseDDMMmmmm_f( char *input )
{
uint8_t digits = 0;
char chr;
// Find the decimal point
while (isdigit( input[digits] ))
digits++;
// All but the last two are degrees.
double val = 0.0;
while (digits > 2) {
chr = *input++;
val = val*10 + (chr - '0');
digits--;
}
// convert from degrees to minutes
val *= 60;
// Add in the last 2 minutes digits
uint8_t minutes = 0;
while (digits > 0) {
chr = *input++;
minutes = minutes*10 + (chr - '0');
digits--;
}
val += minutes;
// Decimal point?
chr = *input++;
if (chr == '.') {
chr = *input++;
// Parse the fractional "mmmm" minutes.
while (isdigit( chr ) && (digits++ <= 4)) {
val = val*10 + (chr - '0');
chr = *input++;
}
// Scale the value up to minutes x 1000000.
while (digits < 4) {
val *= 10;
digits++;
}
}
// convert from minutes x 1000000 to degrees.
val *= 10.0/1000000.0 * 1.0/60.0;
return val;
} // parseDDMMmmmm_f
如果你使用这些函数,你还需要在AT字符串前面弹出' - ',并否定返回的值:
bool south = (latitude[0] == '-');
if (south)
latitude++;
float lat = parseDDMMmmmm_f( latitude );
if (south)
lat = -lat;
convert2Degrees(longitude);
bool west = (longitude[0] == '-');
if (west)
longitude++;
float lon = parseDDMMmmmm_f( longitude );
if (west)
lon = -lon;[/code]