⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 garminnmea.cc

📁 机器人仿真软件
💻 CC
📖 第 1 页 / 共 2 页
字号:
/* *  Player - One Hell of a Robot Server *  Copyright (C) 2000-2003  Brian Gerkey gerkey@usc.edu *                           Andrew Howard ahoward@usc.edu * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * *//* * $Id: garminnmea.cc,v 1.24 2006/02/23 02:21:49 gerkey Exp $ *//** @ingroup drivers *//** @{ *//** @defgroup driver_garminnmea garminnmea * @brief Garmin GPS unit %Device driver for the Garmin geko 201 handheld GPS unit.  Interacts withthe unit by speaking NMEA over a serial line.  As such, this driver maywork with other Garmin units, and (likely with some modification) otherNMEA-compliant GPS units. The driver may also attempt to read DGPS RTCM corrections from amulti-cast network address, and forward these corrections to theGPS unit.  The @ref util_dgps_server utility may be used to gatherand broadcast the DGPS RTCM corrections. NMEA and proprietary Garmin codes can be found athttp://home.mira.net/~gnb/gps/nmea.html@par Compile-time dependencies- none@par Requires- none@par Provides- @ref interface_gps@par Configuration requests- none@par Configuration file options- port (string)  - Default: "/dev/ttyS0"  - Serial port where the GPS unit is connected- baud (integer)  - Default: 4800  - Speed of serial connection to the GPS unit- dgps_enable (integer)  - Default: 1  - Enable/disable listening for DGPS corrections via UDP multicast    (use @ref util_dgps_server to send the corrections)- dgps_group (string)  - Default: "225.0.0.43"  - Multicast group on which to listen for DGPS corrections</td></tr>- dgps_port (integer)  - Default: 7778  - UDP port on which to listen for DGPS corrections@par Example@verbatimdriver(  name "garminnmea"  provides ["gps:0"]  port "/dev/ttyS1")@endverbatim@authors Brian Gerkey, Andrew Howard*//** @} */#ifdef HAVE_CONFIG_H  #include "config.h"#endif#include <fcntl.h>#include <math.h>#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <termios.h>#include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>  // for htons(3)#include <arpa/inet.h> // inet_addr#include <errno.h>#include <libplayercore/playercore.h>#include <replace/replace.h>#define DEFAULT_GPS_PORT "/dev/ttyS0"#define DEFAULT_DGPS_GROUP "225.0.0.43"#define DEFAULT_DGPS_PORT 7778// time that we'll wait to get the first round of data from the unit.// currently 1s#define GPS_STARTUP_CYCLE_USEC 100000#define GPS_STARTUP_CYCLES 10// these are the standard NMEA sentences that come // out of the geko 201#define NMEA_GPRMB "GPRMB"#define NMEA_GPRMC "GPRMC"#define NMEA_GPGGA "GPGGA"#define NMEA_GPGSA "GPGSA"#define NMEA_GPGSV "GPGSV"#define NMEA_GPGLL "GPGLL"#define NMEA_GPBOD "GPBOD"#define NMEA_GPRTE "GPRTE"// these are the proprietary NMEA sentences that // come out of the geko 201#define NMEA_PGRME "PGRME"#define NMEA_PGRMZ "PGRMZ"#define NMEA_PSLIB "PSLIB"// spec says 82, but that done mean squat. Make it big#define NMEA_MAX_SENTENCE_LEN 83#define NMEA_START_CHAR '$'#define NMEA_END_CHAR '\n'#define NMEA_CHKSUM_CHAR '*'// WGS84 Parameters#define WGS84_A		6378137.0		// major axis#define WGS84_B		6356752.31424518	// minor axis#define WGS84_F		0.0033528107		// ellipsoid flattening#define WGS84_E		0.0818191908		// first eccentricity#define WGS84_EP	0.0820944379		// second eccentricity// UTM Parameters#define UTM_K0		0.9996			// scale factor#define UTM_FE		500000.0		// false easting#define UTM_FN_N	0.0			// false northing on north hemisphere#define UTM_FN_S	10000000.0		// false northing on south hemisphere#define UTM_E2		(WGS84_E*WGS84_E)	// e^2#define UTM_E4		(UTM_E2*UTM_E2)		// e^4#define UTM_E6		(UTM_E4*UTM_E2)		// e^6#define UTM_EP2		(UTM_E2/(1-UTM_E2))	// e'^2class GarminNMEA:public Driver {  private:    // string name of serial port to use    const char* gps_serial_port;    // GPS baud rate    int gps_baud;    // file descriptor for the gps unit    int gps_fd;      // Enable DGPS corrections?    int dgps_enable;      // Port number for DGPS RTCM corrections    const char *dgps_group;    int dgps_port;    // file descriptor for the DGPS UDP socket    int dgps_fd;    bool gps_fd_blocking;      char nmea_buf[NMEA_MAX_SENTENCE_LEN+1];    size_t nmea_buf_len;    // Status    int read_count;    // Filtered GPS geodetic coords; for outlier rejection    double filter_a, filter_thresh;    double filter_lat, filter_lon;    bool filter_good;      // Current GPS data packet    player_gps_data_t data;    int SetupSerial();    void ShutdownSerial();      int SetupSocket();    void ShutdownSocket();    int ReadSentence(char* buf, size_t len);    int WriteSentence(const char *buf, size_t len);    int ReadSocket(char *buf, size_t len);    int FillBuffer();    int ParseSentence(const char* buf);    int ParseGPGGA(const char *buf);    int ParseGPRMC(const char *buf);    int ParsePGRME(const char *buf);    char* GetNextField(char* field, size_t len, const char* ptr);    // utility functions to convert geodetic to UTM position    void UTM(double lat, double lon, double *x, double *y);  public:    GarminNMEA( ConfigFile* cf, int section);    virtual int Setup();    virtual int Shutdown();    virtual void Main();};///////////////////////////////////////////////////////////////////////////// initialization functionDriver* GarminNMEA_Init( ConfigFile* cf, int section){  return((Driver*)(new GarminNMEA( cf, section)));}///////////////////////////////////////////////////////////////////////////// a driver registration functionvoid GarminNMEA_Register(DriverTable* table){  table->AddDriver("garminnmea",  GarminNMEA_Init);}///////////////////////////////////////////////////////////////////////////GarminNMEA::GarminNMEA( ConfigFile* cf, int section) : Driver(cf, section, false, PLAYER_MSGQUEUE_DEFAULT_MAXLEN, PLAYER_GPS_CODE){  memset(&data,0,sizeof(data));  gps_fd = -1;  gps_serial_port = cf->ReadString(section, "port", DEFAULT_GPS_PORT);  gps_baud = cf->ReadInt(section, "baud", 4800);  read_count = 0;    filter_a = 0.80;  filter_thresh = 1.0;  filter_lat = 0;  filter_lon = 0;  dgps_enable = cf->ReadInt(section, "dgps_enable", 1);  dgps_group = cf->ReadString(section, "dgps_group", DEFAULT_DGPS_GROUP);  dgps_port = cf->ReadInt(section, "dgps_port", DEFAULT_DGPS_PORT);  return;}///////////////////////////////////////////////////////////////////////////intGarminNMEA::Setup(){  // Set up the serial port to talk to the GPS unit  if (SetupSerial() != 0)    return -1;  // Set up the UDP port to get DGPS corrections  if (SetupSocket() != 0)    return -1;    puts("Done.");    // start the thread to talk with the GPS unit  StartThread();  return(0);}///////////////////////////////////////////////////////////////////////////intGarminNMEA::Shutdown(){  StopThread();  ShutdownSocket();  ShutdownSerial();  return(0);}///////////////////////////////////////////////////////////////////////////// Initialize the serial portintGarminNMEA::SetupSerial(){  struct termios term;  int flags;  int attempt;  int maxattempts=10;  printf("GPS connection initializing (%s)...", gps_serial_port);  fflush(stdout);  // open it.  non-blocking at first, in case there's no gps unit.  if((gps_fd = open(gps_serial_port,                     O_RDWR | O_SYNC | O_NONBLOCK, S_IRUSR | S_IWUSR )) < 0)  {    PLAYER_ERROR1("open(): %s\n", strerror(errno));    return(-1);  }    gps_fd_blocking = false;   if(tcflush(gps_fd, TCIFLUSH ) < 0 )  {    PLAYER_ERROR1("tcflush(): %s\n", strerror(errno));    close(gps_fd);    gps_fd = -1;    return(-1);  }  if(tcgetattr(gps_fd, &term) < 0 )  {    PLAYER_ERROR1("tcgetattr(): %s\n", strerror(errno));    close(gps_fd);    gps_fd = -1;    return(-1);  }    cfmakeraw(&term);  if (gps_baud == 9600)  {    cfsetispeed(&term, B9600);    cfsetospeed(&term, B9600);  }  else if (gps_baud == 19200)  {    cfsetispeed(&term, B19200);    cfsetospeed(&term, B19200);  }  else if (gps_baud == 38400)  {    cfsetispeed(&term, B38400);    cfsetospeed(&term, B38400);  }  else  {    cfsetispeed(&term, B4800);    cfsetospeed(&term, B4800);  }    if(tcsetattr(gps_fd, TCSAFLUSH, &term) < 0 )  {    PLAYER_ERROR1("tcsetattr(): %s\n", strerror(errno));    close(gps_fd);    gps_fd = -1;    return(-1);  }  printf("filling buffer\n");  fflush(stdout);    memset(nmea_buf,0,sizeof(nmea_buf));  nmea_buf_len=0;  /* try to read some data, just to make sure we actually have a gps unit */  for(attempt=0;attempt<maxattempts;attempt++)  {    if(!FillBuffer())      break;  }  if(attempt==maxattempts)  {    PLAYER_ERROR1("Couldn't connect to GPS unit, most likely because the \n"                  "unit is not connected or is connected not to %s\n",                     gps_serial_port);    close(gps_fd);    gps_fd = -1;    return(-1);  }  printf("done filling buffer\n");  fflush(stdout);  /* ok, we got data, so now set NONBLOCK, and continue */  if((flags = fcntl(gps_fd, F_GETFL)) < 0)  {    PLAYER_ERROR1("fcntl(): %s\n", strerror(errno));    close(gps_fd);    gps_fd = -1;    return(1);  }  if(fcntl(gps_fd, F_SETFL, flags ^ O_NONBLOCK) < 0)  {    PLAYER_ERROR1("fcntl(): %s\n", strerror(errno));    close(gps_fd);    gps_fd = -1;    return(1);  }  gps_fd_blocking = true;  return 0;}///////////////////////////////////////////////////////////////////////////// Shutdown the serial portvoidGarminNMEA::ShutdownSerial(){  close(gps_fd);  gps_fd=-1;  return;}///////////////////////////////////////////////////////////////////////////// Initialise the UDP socket for recieving DGPS correctionsintGarminNMEA::SetupSocket(){  sockaddr_in addr;  struct ip_mreq mreq;  if (!this->dgps_enable)    return 0;    // Set up the read socket  this->dgps_fd = socket(PF_INET, SOCK_DGRAM, 0);  if (this->dgps_fd == -1)  {    PLAYER_ERROR1("error initializing socket : %s", strerror(errno));    return 1;  }  // Set socket options to allow sharing of port  u_int share = 1;  if (setsockopt(this->dgps_fd, SOL_SOCKET, SO_REUSEADDR,                 (const char*)&share, sizeof(share)) < 0)  {    PLAYER_ERROR1("error initializing socket : %s", strerror(errno));    return 1;  }      // Bind socket to port  memset(&addr, 0, sizeof(addr));  addr.sin_family = AF_INET;  addr.sin_addr.s_addr = htonl(INADDR_ANY);  addr.sin_port = htons(this->dgps_port);  if (bind(this->dgps_fd, (sockaddr*) &addr, sizeof(addr)) < 0)  {    PLAYER_ERROR1("error initializing socket : %s", strerror(errno));    return 1;  }  // Join the multi-cast group  mreq.imr_multiaddr.s_addr = inet_addr(this->dgps_group);  mreq.imr_interface.s_addr = htonl(INADDR_ANY);  if (setsockopt(this->dgps_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != 0)  {    PLAYER_ERROR1("error joining multicast group : %s", strerror(errno));    return 1;  }  return 0;}/* * Shutdown the DGPS socket */voidGarminNMEA::ShutdownSocket(){  if (!this->dgps_enable)    return;  close(this->dgps_fd);  return;}/* * Driver thread runs here.  We have to poll on both the serial port * and the UDP socket. */voidGarminNMEA::Main(){  int len;  char buf[NMEA_MAX_SENTENCE_LEN];  char rtcm_buf[1024];  struct pollfd fds[2];  int fd_count;  fd_count = 0;    fds[fd_count].fd = this->gps_fd;  fds[fd_count].events = POLLIN | POLLPRI | POLLERR | POLLHUP;  fd_count++;  if (this->dgps_enable)  {    fds[fd_count].fd = this->dgps_fd;    fds[fd_count].events = POLLIN | POLLPRI | POLLERR | POLLHUP;    fd_count++;  }  pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);  for(;;)  {    pthread_testcancel();    if (poll(fds, fd_count, 100) < 0)    {      PLAYER_ERROR1("poll returned [%s]", strerror(errno));      continue;    }    // Read incoming data from the GPS    if (fds[0].revents)    {      if(ReadSentence(buf,sizeof(buf)))      {        PLAYER_ERROR("while reading from GPS unit; bailing");        pthread_exit(NULL);      }      ParseSentence((const char*)buf);    }    // Read incoming DGPS corrections from the socket    if (this->dgps_enable)    {      if (fds[1].revents)      {        len = ReadSocket(rtcm_buf, sizeof(rtcm_buf));        if (len < 0)          pthread_exit(NULL);        printf("got udp packet of length %d\n", len);        fflush(stdout);              // Write the DGPS sentence to the GPS unit        if (WriteSentence(rtcm_buf, len) != 0)          pthread_exit(NULL);      }    }  }  return;}/* * Find a complete NMEA sentence and copy it into 'buf', which should be of * length 'len'.  This function will call FillBuffer() as necessary to get * enough data into 'nmea_buf' to form a complete sentence. 'buf' will be * NULL-terminated. * */intGarminNMEA::ReadSentence(char* buf, size_t len){  char* ptr;  char* ptr2;  size_t sentlen;  char tmp[8];  int chksum;  int oursum;   //printf("reading sentence\n");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -