基本思路: 物体速度 = 两点的坐标差 / 定位时间差
也就是说,按照1Hz的频率采集GPS数据,就能算出物体运动速度

一、硬件结构

  • Arduino UNO
  • EC20 USB DongleA(GNSS)模块
    具有4G和GPS功能

androidgps强弱 android gps测速_嵌入式


如图按照TX->RX,RX->TX,GND->GND,5V->5V接线即可

二、方案验证

EC20模块USB接口连接PC,可以看到三个串口:AT port用于发送AT指令,NMEA
port用于接收GNSS数据。但我们最终需要连接MCU使用,所以这里要测试串口,此串口引出的是AT功能。

androidgps强弱 android gps测速_arduino_02

1.GPS功能验证步骤

  • 因为使用了UART,所以配置数据输出到串口:AT+QGPSCFG="outport","uartdebug" ,另外两种为输出到USB或无输出
  • 使能GPS功能AT+QGPS=1
  • 将NMEA数据输出到AT口AT+QGPSCFG="nmeasrc",1
  • 输出NMEA中GGA这条数据AT+QGPSGNMEA="GGA"
  • androidgps强弱 android gps测速_androidgps强弱_03

  • $GPGGA,,,,,,0,,,,,,,,*66中无有效数据是因为在室内没有GPS信号,可以按照GPGGA标准格式解析出定位、海拔高等信息。

2.GPRS功能验证步骤

(1)使用GPRS功能的目的是连接服务器,发送数据,看一下官方文档TCP部分

androidgps强弱 android gps测速_arduino_04


androidgps强弱 android gps测速_gps_05


(2) 按照上图顺序发送AT指令

androidgps强弱 android gps测速_arduino_06


(3)串口助手输出如下:

androidgps强弱 android gps测速_arduino_07


(4) 服务器收到的16进制ASCII码消息如下:

androidgps强弱 android gps测速_gprs_08

3.至此,我们PC与EC20模块UART的通信验证完成,接下来我们可以用MCU代替PC了,逻辑如下:

androidgps强弱 android gps测速_gprs_09

三、编程实现

1.设备(MCU+EC20)与服务器间tcp通信

(1)代码实现

#include <SoftwareSerial.h>
SoftwareSerial ATserial(12, 13);//RX,TX 创建模拟串口
enum{
    CPIN=0,
    COPS,
    CREG,
    CGREG,
    QICSGP,
    QIACT,
    QIOPEN
}AT;

void setup()
{
  delay(5000);
  pinMode(0,  INPUT_PULLUP); 
  pinMode(1,  INPUT_PULLUP); 
  Serial.begin(115200); 
  while (!Serial) {}
  	Serial.println("serial ok!");
  ATserial.begin(115200);
  while (!ATserial) {}
  	Serial.println("ATserial ok!");
  	
  ATserial.listen();
  ATserial.println("AT");
  delay(300);
  if(ATserial.find("OK")){
    Serial.println("EC20 is ready!");
  }
  clear_serial();
  
  AT = CPIN;
  switch(AT)//状态机
  {
  case CPIN:  
    cpin();
  case COPS:
    cops();
  case CREG:
    creg();
  case CGREG:
    cgreg();
  case QICSGP:
    qicsgp();
  case QIACT:
   qiact();
  case QIOPEN:
    qiopen();
  break;
  default:
  break;  
  }
}
void loop() {
	at_send();//发送测试数据
}

void cpin()
{
  ATserial.println("AT+CPIN?");
  delay(300);
  if(ATserial.find("OK")){
      Serial.println("AT+CPIN,ok");
    AT = COPS;
  }
  clear_serial();
}
void cops()
{
  ATserial.println("AT+COPS?");
  delay(500);
  if(ATserial.find("OK")){
      Serial.println("AT+COPS,ok");
    AT = CREG;
  }
  clear_serial();
}
void creg()
{
  ATserial.println("AT+CREG?");
  delay(300);
  if(ATserial.find("OK")){
      Serial.println("AT+CREG,ok");
    AT = CGREG;
  }
  clear_serial();
}
void cgreg()
{
  ATserial.println("AT+CGREG?");
  delay(300);
  if(ATserial.find("OK")){
      Serial.println("AT+CGREG,ok");
    AT = QICSGP;
  }
  clear_serial();
}
void qicsgp()
{
  ATserial.println("AT+QICSGP=1,1,\"CMNET\",\"\",\"\",1");
  delay(300);
  if(ATserial.find("OK")){
      Serial.println("AT+QICSGP,ok");
    AT = QIACT;
  }
  clear_serial();
}
void qiact()
{
  ATserial.println("AT+QIDEACT=1");
  delay(300);
  clear_serial();
  ATserial.println("AT+QIACT=1");
  delay(300);
  if(ATserial.find("OK")){
      Serial.println("AT+QIACT,ok");
    AT = QIOPEN;
  }
  clear_serial();
}
void qiopen()
{
  ATserial.println("AT+QIOPEN=1,0,\"TCP\",\"180.97.81.180\",54501,0,0");
  delay(1000);
  if(ATserial.find("OK")){
      Serial.println("AT+QIOPEN,ok");
  }
  clear_serial();
}
void at_send()
{
  ATserial.println("AT+QISENDEX=0,\"3132333435\"");
  delay(1000);
  if(ATserial.find("OK")){
      Serial.println("AT+QISENDEX,ok");
  }
  clear_serial();
}
void clear_serial()//清除串口缓存,否则每次都能检测到"OK"
{
  while(ATserial.read() >= 0){}
  while(Serial.read() >= 0){}
  
}

(2)Arduino串口监控器输出LOG如下

androidgps强弱 android gps测速_gprs_10


(3)TCP服务器收到数据

androidgps强弱 android gps测速_嵌入式_11

2.发送GPS数据

(1)代码实现
模块gps功能初始化函数,在setup()中调用

void gps_init()
{
  //AT+QGPSCFG="outport","uartdebug"
  //AT+QGPS=1
  //AT+QGPSCFG="nmeasrc",1
  ATserial.println("AT+QGPSCFG=\"outport\",\"uartdebug\"");
  delay(300);
  if(ATserial.find("OK")){
      Serial.println("AT+QGPSCFG_outport,ok");
  }
  clear_serial();
  ATserial.println("AT+QGPS=1");
  delay(300);
  if(ATserial.find("OK")){
      Serial.println("AT+QGPS,ok");
  }
  clear_serial();
  ATserial.println("AT+QGPSCFG=\"nmeasrc\",1");
  delay(300);
  if(ATserial.find("OK")){
      Serial.println("AT+QGPSCFG_nmeasrc,ok");
  }
  clear_serial();
}

定位获取和发送写在loop()中

void loop(){
  clear_serial();
  ATserial.println("AT+QGPSGNMEA=\"GGA\"");
  delay(300);
  if(ATserial.find("GGA")){
      String comdata = "";//缓存清零
      Serial.println("GPGGA消息:
      while (ATserial.available() > 0)//循环串口是否有数据
      {
       comdata += char(ATserial.read());//叠加数据到comdata
       delay(4);//延时等待响应
      }
      Serial.println(comdata);

      ATserial.println("AT+QISWTMD=0,2");
      delay(300);
      if(ATserial.find("CONNECT")){
        Serial.println("++++++++进入透传模式++++++++++");
        clear_serial();
        ATserial.println(comdata);
        delay(300);
        if(ATserial.find("OK")){
        Serial.println("send,ok");
        }
      }
  }
  delay(1000);
  ATserial.print("+++");//退出透传模式
  delay(1000);
}

(2)Arduino监控串口输出

androidgps强弱 android gps测速_androidgps强弱_12


(3)服务器接收到GNSS数据,到这里基本功能就完成了

androidgps强弱 android gps测速_gps_13

可以透传到服务器供后端解析,也可以在本地解析通过经纬度和时间戳计算设备速度(v=s/t),这个很简单就不展开了

3.说明

(1)这里只是一个测试mode,理论可行,但与事实相去甚远(实际项目已采用其他方案)
(2)理论上2G或者NB更便宜,但是没有采用,因为在2G的频段,由于多普勒效应,如果物体高速运动,2G会发生频移,导致信号很差,丢包严重,谨记