33 """Parsing functions for NMEA sentence strings.""" 42 logger = logging.getLogger(
'rosout')
46 """Convert field to a float. 49 field: The field (usually a str) to convert to float. 52 The float value represented by field or NaN if float conversion throws a ValueError. 61 """Convert field to an int. 64 field: The field (usually a str) to convert to int. 67 The int value represented by field or 0 if int conversion throws a ValueError. 76 """Convert a latitude string to floating point decimal degrees. 79 field (str): Latitude string, expected to be formatted as DDMM.MMM, where 80 DD is the latitude degrees, and MM.MMM are the minutes latitude. 83 Floating point latitude in decimal degrees. 89 """Convert a longitude string to floating point decimal degrees. 92 field (str): Longitude string, expected to be formatted as DDDMM.MMM, where 93 DDD is the longitude degrees, and MM.MMM are the minutes longitude. 96 Floating point latitude in decimal degrees. 102 """Extract time info from a NMEA UTC time string and use it to generate a UNIX epoch time. 104 Time information (hours, minutes, seconds) is extracted from the given string and augmented 105 with the date, which is taken from the current system time on the host computer (i.e. UTC now). 106 The date ambiguity is resolved by adding a day to the current date if the host time is more than 107 12 hours behind the NMEA time and subtracting a day from the current date if the host time is 108 more than 12 hours ahead of the NMEA time. 111 nmea_utc (str): NMEA UTC time string to convert. The expected format is HHMMSS.SS where 112 HH is the number of hours [0,24), MM is the number of minutes [0,60), 113 and SS.SS is the number of seconds [0,60) of the time in UTC. 116 tuple(int, int): 2-tuple of (unix seconds, nanoseconds) if the sentence contains valid time. 117 tuple(float, float): 2-tuple of (NaN, NaN) if the sentence does not contain valid time. 120 if not nmea_utc[0:2]
or not nmea_utc[2:4]
or not nmea_utc[4:6]:
121 return (float(
'NaN'), float(
'NaN'))
124 utc_time = datetime.datetime.utcnow()
125 hours = int(nmea_utc[0:2])
126 minutes = int(nmea_utc[2:4])
127 seconds = int(nmea_utc[4:6])
128 nanosecs = int(nmea_utc[7:]) * pow(10, 9 - len(nmea_utc[7:]))
131 day_offset = int((utc_time.hour - hours)/12.0)
132 utc_time += datetime.timedelta(day_offset)
133 utc_time.replace(hour=hours, minute=minutes, second=seconds)
135 unix_secs = calendar.timegm(utc_time.timetuple())
136 return (unix_secs, nanosecs)
140 """Convert a NMEA RMC date string and time string to UNIX epoch time. 143 date_str (str): NMEA UTC date string to convert, formatted as DDMMYY. 144 nmea_utc (str): NMEA UTC time string to convert. The expected format is HHMMSS.SS where 145 HH is the number of hours [0,24), MM is the number of minutes [0,60), 146 and SS.SS is the number of seconds [0,60) of the time in UTC. 149 tuple(int, int): 2-tuple of (unix seconds, nanoseconds) if the sentence contains valid time. 150 tuple(float, float): 2-tuple of (NaN, NaN) if the sentence does not contain valid time. 153 if not time_str[0:2]
or not time_str[2:4]
or not time_str[4:6]:
154 return (float(
'NaN'), float(
'NaN'))
156 pc_year = datetime.date.today().year
160 example 1: utc_year = 99, pc_year = 2100 161 years = 2100 + int((2100 % 100 - 99) / 50.0) = 2099 162 example 2: utc_year = 00, pc_year = 2099 163 years = 2099 + int((2099 % 100 - 00) / 50.0) = 2100 165 utc_year = int(date_str[4:6])
166 years = pc_year + int((pc_year % 100 - utc_year) / 50.0)
168 months = int(date_str[2:4])
169 days = int(date_str[0:2])
171 hours = int(time_str[0:2])
172 minutes = int(time_str[2:4])
173 seconds = int(time_str[4:6])
174 nanosecs = int(time_str[7:]) * pow(10, 9 - len(time_str[7:]))
176 unix_secs = calendar.timegm((years, months, days, hours, minutes, seconds))
177 return (unix_secs, nanosecs)
181 """Convert a NMEA RMB/RMC status flag to bool. 184 status_flag (str): NMEA status flag, which should be "A" or "V" 187 True if the status_flag is "A" for Active. 189 if status_flag ==
"A":
191 elif status_flag ==
"V":
198 """Convert a speed in knots to meters per second. 201 knots (float, int, or str): Speed in knots. 204 The value of safe_float(knots) converted from knots to meters/second. 210 """Convert an angle in degrees to radians. 212 This wrapper is needed because math.radians doesn't accept non-numeric inputs. 215 degs (float, int, or str): Angle in degrees 218 The value of safe_float(degs) converted from degrees to radians. 225 (
"fix_type", int, 6),
226 (
"latitude", convert_latitude, 2),
227 (
"latitude_direction", str, 3),
228 (
"longitude", convert_longitude, 4),
229 (
"longitude_direction", str, 5),
230 (
"altitude", safe_float, 9),
231 (
"mean_sea_level", safe_float, 11),
232 (
"hdop", safe_float, 8),
233 (
"num_satellites", safe_int, 7),
234 (
"utc_time", convert_time, 1),
237 (
"fix_valid", convert_status_flag, 2),
238 (
"latitude", convert_latitude, 3),
239 (
"latitude_direction", str, 4),
240 (
"longitude", convert_longitude, 5),
241 (
"longitude_direction", str, 6),
242 (
"speed", convert_knots_to_mps, 7),
243 (
"true_course", convert_deg_to_rads, 8),
246 (
"utc_time", convert_time, 1),
247 (
"ranges_std_dev", safe_float, 2),
248 (
"semi_major_ellipse_std_dev", safe_float, 3),
249 (
"semi_minor_ellipse_std_dev", safe_float, 4),
250 (
"semi_major_orientation", safe_float, 5),
251 (
"lat_std_dev", safe_float, 6),
252 (
"lon_std_dev", safe_float, 7),
253 (
"alt_std_dev", safe_float, 8),
256 (
"heading", safe_float, 1),
259 (
"true_course", safe_float, 1),
260 (
"speed", convert_knots_to_mps, 5)
263 """A dictionary that maps from sentence identifier string (e.g. "GGA") to a list of tuples. 264 Each tuple is a three-tuple of (str: field name, callable: conversion function, int: field index). 265 The parser splits the sentence into comma-delimited fields. The string value of each field is passed 266 to the appropriate conversion function based on the field index.""" 270 """Parse a NMEA sentence string into a dictionary. 273 nmea_sentence (str): A single NMEA sentence of one of the types in parse_maps. 276 A dict mapping string field names to values for each field in the NMEA sentence or 277 False if the sentence could not be parsed. 282 r'(^\$GP|^\$GN|^\$GL|^\$IN).*\*[0-9A-Fa-f]{2}$', nmea_sentence):
284 "Regex didn't match, sentence not valid NMEA? Sentence was: %s" %
287 fields = [field.strip(
',')
for field
in nmea_sentence.split(
',')]
290 sentence_type = fields[0][3:]
292 if sentence_type
not in parse_maps:
293 logger.debug(
"Sentence type %s not in parse map, ignoring." 294 % repr(sentence_type))
297 parse_map = parse_maps[sentence_type]
300 for entry
in parse_map:
301 parsed_sentence[entry[0]] = entry[1](fields[entry[2]])
303 if sentence_type ==
"RMC":
306 return {sentence_type: parsed_sentence}
def convert_time_rmc(date_str, time_str)
def convert_status_flag(status_flag)
def convert_time(nmea_utc)
def convert_deg_to_rads(degs)
def parse_nmea_sentence(nmea_sentence)
def convert_latitude(field)
def convert_longitude(field)
def convert_knots_to_mps(knots)