gps-sim.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. #!/usr/bin/python
  2. #
  3. # Copyright (c) 2019 Clementine Computing LLC.
  4. #
  5. # This file is part of PopuFare.
  6. #
  7. # PopuFare is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU Affero General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # PopuFare is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU Affero General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Affero General Public License
  18. # along with PopuFare. If not, see <https://www.gnu.org/licenses/>.
  19. #
  20. # Script to test GPS positioning by simulating output of a GPS module.
  21. #
  22. # Outputs to stdout
  23. #
  24. import getopt
  25. import sys
  26. import time
  27. import math
  28. import datetime
  29. DT = 0.5
  30. DS = 2
  31. DTUPDATE = 2.0
  32. ITER_COUNT = -1
  33. LOCK_DELAY = 0
  34. DSTEP = 16
  35. argv = sys.argv
  36. def show_help(ofp):
  37. ofp.write("\nusage: gps-sim.py [-dt dt] [-ds ds] [-p lat0,lon0] [-p lat1,lon1]\n")
  38. ofp.write("\n")
  39. ofp.write(" -dt dt time between waypoints (default " + str(DT) + "seconds)\n")
  40. ofp.write(" -ds ds time to stop at waypoint (default" + str(DS) + "seconds)\n")
  41. ofp.write(" -p lat,lon[,dt[,ds]] latitudie, longitude of waypoint with optional dt, ds (can specify multiple times)\n")
  42. ofp.write(" -f fn file containing lat,lon positions\n")
  43. ofp.write(" -t t time between print updates (default " + str(DTUPDATE) + " seconds)\n")
  44. ofp.write(" -n n number of iterations (<0 for infinite, default " + str(ITER_COUNT) + ")\n")
  45. ofp.write(" --lock-delay d time to delay before inital gps lock (default " + str(LOCK_DELAY) + ")\n")
  46. ofp.write("\n")
  47. def parse_latlon(s):
  48. v = s.strip("\n").split(",")
  49. if len(v) < 2: return []
  50. if len(v) > 4: return []
  51. lat = float(v[0])
  52. lon = float(v[1])
  53. dt = DT
  54. ds = DS
  55. if len(v) > 2:
  56. dt = float(v[2])
  57. if len(v) > 3:
  58. ds = float(v[3])
  59. return [lat, lon, dt, ds]
  60. def load_latlon_csv(fn):
  61. latlon = []
  62. with open(fn) as fp:
  63. for line in fp:
  64. v = parse_latlon(line)
  65. latlon.append(v)
  66. return latlon
  67. def nmea_checksum(msg):
  68. cksum = 0
  69. for idx in range(len(msg)):
  70. c = ord(msg[idx])
  71. cksum = cksum ^ (c & 0xff)
  72. return ("%02X" % cksum)
  73. #tstmsg = [ "$GPGSV,3,1,12,17,43,264,38,08,12,066,38,28,65,320,35,11,57,059,32*73",
  74. # "$GPGSV,3,2,12,07,23,180,32,19,21,254,32,01,59,075,31,13,08,275,25*7C",
  75. # "$GPGSV,3,3,12,22,18,106,25,30,47,210,15,18,38,053,,04,,,*44",
  76. # "$GPGSV,4,4,13,04,,,*7F",
  77. # "$GPGGA,040341.1,4226.692702,N,07630.419493,W,1,07,1.0,117.5,M,0,M,,*6D",
  78. # "$GPVTG,NaN,T,,M,0.0,N,0.0,K,A*42",
  79. # "$GPRMC,040341.1,A,4226.692702,N,07630.419493,W,0.0,0.0,050500,,,A*75",
  80. # "$GPGSA,A,3,01,07,08,11,17,19,28,,,,,,1.5,1.0,1.2*3E",
  81. # "$GPGSV,3,1,12,08,12,066,38,17,43,264,38,28,65,320,35,11,57,059,33*72",
  82. # "$GPGSV,3,2,12,07,23,180,32,01,59,075,32,19,21,254,32,22,18,106,26*78",
  83. # "$GPGSV,3,3,12,13,08,275,25,30,47,210,17,18,38,053,,04,,,*42",
  84. # "$GPGSV,4,4,13,04,,,*7F",
  85. # "$GPGGA,040344.1,4226.692722,N,07630.419464,W,1,07,1.0,117.3,M,0,M,,*64",
  86. # "$GPVTG,NaN,T,,M,0.0,N,0.0,K,A*42",
  87. # "$GPRMC,040344.1,A,4226.692722,N,07630.419464,W,0.0,0.0,050500,,,A*7A",
  88. # "$GPGSA,A,3,01,07,08,11,17,19,28,,,,,,1.5,1.0,1.2*3E" ]
  89. #
  90. #for msg in tstmsg:
  91. # s = msg[1:-3]
  92. # print s, "(", msg, ")"
  93. # print " >>", nmea_checksum(s)
  94. #
  95. #sys.exit(0)
  96. def print_gps_nmea_messages(ofp, lat, lon, utc_str = ""):
  97. if len(utc_str) == 0:
  98. n = datetime.datetime.utcnow()
  99. utc_str = n.strftime("%H") + n.strftime("%M") + n.strftime("%S") + "." + n.strftime("%f")[0:1]
  100. ofp.write("$GPGSV,4,1,13,08,12,066,38,28,65,320,36,17,43,264,36,01,59,075,32*79\n")
  101. ofp.write("$$GPGSV,4,2,13,11,57,059,32,07,23,180,31,19,21,254,29,22,18,106,29*79\n")
  102. ofp.write("$GPGSV,4,3,13,13,08,275,23,03,09,127,20,30,47,210,20,18,38,053,*7E\n")
  103. ofp.write("$GPGSV,4,4,13,04,,,*7F\n")
  104. latdir = 'N'
  105. if lat < 0.0: latdir = 'S'
  106. londir = 'E'
  107. if lon < 0.0: londir = 'W'
  108. msg = "GPGGA," + utc_str + "," + str(abs(lat)) + "," + latdir + "," + str(abs(lon)) + "," + londir + ",1,08,0.9,116.9,M,0,M,,"
  109. ofp.write("$" + msg + "*" + nmea_checksum(msg) + "\n")
  110. ofp.write("$GPVTG,NaN,T,,M,0.0,N,0.0,K,A*42\n")
  111. msg = "GPRMC," + utc_str + ",A," + str(abs(lat)) + "," + latdir + "," + str(abs(lon)) + "," + londir + ",0.0,0.0,050500,,,A"
  112. ofp.write("$" + msg + "*" + nmea_checksum(msg) + "\n")
  113. ofp.write("$GPGSA,A,3,01,07,08,11,17,19,22,28,,,,,1.5,0.9,1.1*35\n")
  114. latlon = []
  115. noarg = True
  116. ifn = ""
  117. argvv = []
  118. av = []
  119. for p in range(len(argv[1:])):
  120. if (p%2) == 0:
  121. av = [argv[p+1]]
  122. else:
  123. av.append(argv[p+1])
  124. argvv.append(av)
  125. av = []
  126. for argval in argvv:
  127. arg = argval[0]
  128. val = argval[1]
  129. if arg in ("-h", "--help"):
  130. show_help(sys.stdout)
  131. sys.exit(0)
  132. noarg = False
  133. elif arg in ("-dt"):
  134. DT = int(val)
  135. noarg = False
  136. elif arg in ("-ds"):
  137. DS = int(val)
  138. noarg = False
  139. elif arg in ("-p"):
  140. x = parse_latlon(val)
  141. latlon.append(x)
  142. noarg = False
  143. elif arg in ("-f"):
  144. ifn = val
  145. noarg = False
  146. elif arg in ("-n"):
  147. ITER_COUNT = int(val)
  148. elif arg in ("-t"):
  149. DTUPDATE = float(val)
  150. elif arg in ("--lock-delay"):
  151. LOCK_DELAY = float(val)
  152. if len(ifn)>0:
  153. latlon = load_latlon_csv(ifn)
  154. if len(latlon)==0:
  155. sys.stderr.write("Provide input file or lat/lon points\n")
  156. show_help(sys.stderr)
  157. sys.exit(-1)
  158. if noarg:
  159. show_help(sys.stderr)
  160. sys.exit(1)
  161. print "# dt,ds,t:", DT, DS, DTUPDATE
  162. print "# latlon:", latlon
  163. print "# iter_count:", ITER_COUNT
  164. print "# ifn:", ifn
  165. print "# lock_delay:", LOCK_DELAY
  166. curiter = 0
  167. if ITER_COUNT<0: curiter = ITER_COUNT-1
  168. lastupdate_sec = 0.0
  169. curidx = 0
  170. nidx = len(latlon)
  171. while curiter < ITER_COUNT:
  172. curpos = latlon[curidx]
  173. nxtpos = latlon[ (curidx+1)%nidx ]
  174. dlat = curpos[1] - curpos[0]
  175. dlon = curpos[1] - curpos[0]
  176. dpos = math.sqrt( (dlat*dlat) + (dlon*dlon) )
  177. for _step in range(DSTEP):
  178. _p = float(_step) / float(DSTEP)
  179. _pos = [ curpos[0] + _p*(nxtpos[0] - curpos[0]), curpos[1] + _p*(nxtpos[1] - curpos[1]) ]
  180. cursec = float(time.time())
  181. if (cursec - lastupdate_sec) > DTUPDATE:
  182. lastupdate_sec = cursec
  183. #sys.stdout.write(str(_pos[0]) + " " + str(_pos[1]) + "\n")
  184. print_gps_nmea_messages(sys.stdout, _pos[0], _pos[1])
  185. sys.stdout.flush()
  186. time.sleep(DS)
  187. curidx = (curidx + 1)%nidx
  188. time.sleep(DT)
  189. if ITER_COUNT>=0: curiter+=1