piksi_multi.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 #
4 # Title: piksi_multi.py
5 # Description: ROS Driver for Piksi Multi RTK GPS module
6 # Dependencies: libsbp (https://github.com/swift-nav/libsbp), tested with version = see LIB_SBP_VERSION_MULTI
7 # Based on original work of https://bitbucket.org/Daniel-Eckert/piksi_node
8 #
9 
10 import rospy
11 import math
12 import numpy as np
13 import std_srvs.srv
14 # Import message types
15 from sensor_msgs.msg import NavSatFix, NavSatStatus
16 from piksi_rtk_msgs.msg import (AgeOfCorrections, BaselineEcef, BaselineHeading, BaselineNed, BasePosEcef, BasePosLlh,
17  DeviceMonitor_V2_3_15, DopsMulti, GpsTimeMulti, Heartbeat, ImuRawMulti,
18  InfoWifiCorrections, Log, MagRaw, Observation, PosEcef, PosLlhMulti,
19  ReceiverState_V2_3_15, TrackingState_V2_3_15,
20  UartState_V2_3_15, UtcTimeMulti, VelEcef, VelNed)
21 from piksi_rtk_msgs.srv import *
22 from geometry_msgs.msg import (PoseWithCovarianceStamped, PointStamped, PoseWithCovariance, Point, TransformStamped,
23  Transform)
24 # Import Piksi SBP library
25 from sbp.client.drivers.pyserial_driver import PySerialDriver
26 from sbp.client.drivers.network_drivers import TCPDriver
27 from sbp.client import Handler, Framer
28 from sbp.navigation import *
29 from sbp.logging import *
30 from sbp.system import *
31 from sbp.tracking import * # WARNING: tracking is part of the draft messages, could be removed in future releases of libsbp.
32 from sbp.piksi import * # WARNING: piksi is part of the draft messages, could be removed in future releases of libsbp.
33 from sbp.observation import *
34 from sbp.orientation import * # WARNING: orientation messages are still draft messages.
35 from sbp.settings import *
36 from zope.interface.exceptions import Invalid
37 # Piksi Multi features an IMU
38 from sbp.imu import *
39 # Piksi Multi features a Magnetometer Bosh bmm150 : https://www.bosch-sensortec.com/bst/products/all_products/bmm150
40 from sbp.mag import SBP_MSG_MAG_RAW, MsgMagRaw
41 # At the moment importing 'sbp.version' module causes ValueError: Cannot find the version number!
42 # import sbp.version
43 # networking stuff
44 import UdpHelpers
45 import time
46 import subprocess
47 import re
48 import threading
49 import sys
50 import collections
51 
52 
53 class PiksiMulti:
54  LIB_SBP_VERSION_MULTI = '2.3.15' # SBP version used for Piksi Multi.
55 
56  # Geodetic Constants.
57  kSemimajorAxis = 6378137
58  kSemiminorAxis = 6356752.3142
59  kFirstEccentricitySquared = 6.69437999014 * 0.001
60  kSecondEccentricitySquared = 6.73949674228 * 0.001
61  kFlattening = 1 / 298.257223563
62 
63  def __init__(self):
64 
65  # Print info.
66  rospy.init_node('piksi')
67  rospy.sleep(0.5) # Wait for a while for init to complete before printing.
68  rospy.loginfo(rospy.get_name() + " start")
69 
70  # Check SBP version.
71  if 'sbp.version' in sys.modules:
72  installed_sbp_version = sbp.version.get_git_version()
73  else:
74  installed_sbp_version = self.get_installed_sbp_version()
75 
76  rospy.loginfo("libsbp version currently used: " + installed_sbp_version)
77 
78  # Check for correct SBP library version dependent on Piksi device.
79  if PiksiMulti.LIB_SBP_VERSION_MULTI != installed_sbp_version:
80  rospy.logwarn("Lib SBP version in usage (%s) is different than the one used to test this driver (%s)!\n"
81  "Please run the install script: 'install/install_piksi_multi.sh'" % (
82  installed_sbp_version, PiksiMulti.LIB_SBP_VERSION_MULTI))
83 
84  # Open a connection to SwiftNav receiver.
85  interface = rospy.get_param('~interface', 'serial')
86 
87  if interface == 'tcp':
88  tcp_addr = rospy.get_param('~tcp_addr', '192.168.0.222')
89  tcp_port = rospy.get_param('~tcp_port', 55555)
90  try:
91  self.driver = TCPDriver(tcp_addr, tcp_port)
92  except SystemExit:
93  rospy.logerr("Unable to open TCP connection %s:%s", (tcp_addr, tcp_port))
94  raise
95  else:
96  serial_port = rospy.get_param('~serial_port', '/dev/ttyUSB0')
97  baud_rate = rospy.get_param('~baud_rate', 230400)
98  try:
99  self.driver = PySerialDriver(serial_port, baud=baud_rate)
100  except SystemExit:
101  rospy.logerr("Swift receiver not found on serial port '%s'", serial_port)
102  raise
103 
104  # Create a handler to connect Piksi driver to callbacks.
105  self.driver_verbose = rospy.get_param('~driver_verbose', True)
106  self.framer = Framer(self.driver.read, self.driver.write, verbose=self.driver_verbose)
107  self.handler = Handler(self.framer)
108 
109  self.debug_mode = rospy.get_param('~debug_mode', False)
110  if self.debug_mode:
111  rospy.loginfo("Swift driver started in debug mode, every available topic will be published.")
112  # Debugging parameters.
113  debug_delayed_corrections_stack_size = rospy.get_param('~debug_delayed_corrections_stack_size', 10)
114  # self.received_corrections_fifo_stack = collections.deque([], debug_delayed_corrections_stack_size)
115  # rospy.loginfo("Debug mode: delayed corrections stack size: %d." % debug_delayed_corrections_stack_size)
116  else:
117  rospy.loginfo("Swift driver started in normal mode.")
118 
119  # Corrections over WiFi settings.
120  self.base_station_mode = rospy.get_param('~base_station_mode', False)
121  self.udp_broadcast_addr = rospy.get_param('~broadcast_addr', '255.255.255.255')
122  self.udp_port = rospy.get_param('~broadcast_port', 26078)
124  '~base_station_ip_for_latency_estimation',
125  '192.168.0.1')
126  self.multicaster = []
127  self.multicast_recv = []
128 
129  # Navsatfix settings.
130  self.var_spp = rospy.get_param('~var_spp', [25.0, 25.0, 64.0])
131  self.var_rtk_float = rospy.get_param('~var_rtk_float', [25.0, 25.0, 64.0])
132  self.var_rtk_fix = rospy.get_param('~var_rtk_fix', [0.0049, 0.0049, 0.01])
133  self.var_spp_sbas = rospy.get_param('~var_spp_sbas', [1.0, 1.0, 1.0])
134  self.navsatfix_frame_id = rospy.get_param('~navsatfix_frame_id', 'gps')
135 
136  # Local ENU frame settings.
137  self.origin_enu_set = False
138  self.latitude0 = 0.0
139  self.longitude0 = 0.0
140  self.altitude0 = 0.0
141  self.initial_ecef_x = 0.0
142  self.initial_ecef_y = 0.0
143  self.initial_ecef_z = 0.0
144  self.ecef_to_ned_matrix = np.eye(3)
145  self.enu_frame_id = rospy.get_param('~enu_frame_id', 'enu')
146  self.transform_child_frame_id = rospy.get_param('~transform_child_frame_id', 'gps_receiver')
147 
148  if rospy.has_param('~latitude0_deg') and rospy.has_param('~longitude0_deg') and rospy.has_param(
149  '~altitude0'):
150  latitude0 = rospy.get_param('~latitude0_deg')
151  longitude0 = rospy.get_param('~longitude0_deg')
152  altitude0 = rospy.get_param('~altitude0')
153 
154  # Set origin ENU frame to coordinate specified by rosparam.
155  self.init_geodetic_reference(latitude0, longitude0, altitude0)
156  rospy.loginfo("Origin ENU frame set by rosparam.")
157 
158  # Watchdog timer info
159  self.watchdog_time = rospy.get_rostime()
160  self.messages_started = False
161 
162  # Other parameters.
163  self.publish_raw_imu_and_mag = rospy.get_param('~publish_raw_imu_and_mag', False)
164 
165  # Advertise topics and services.
168 
169  # Create topic callbacks.
171 
172  # Init messages with "memory".
175 
176  # Corrections over wifi message, if we are not the base station.
177  if not self.base_station_mode:
178  # Start new thread to periodically ping base station.
179  threading.Thread(target=self.ping_base_station_over_wifi).start()
180 
181  self.handler.start()
182 
183  # Handle firmware settings services
186  self.last_value_read = []
187 
188  # Only have start-up reset in base station mode
189  if self.base_station_mode:
190  # Things have 30 seconds to start or we will kill node
191  rospy.Timer(rospy.Duration(30), self.cb_watchdog, True)
192 
193  # Spin.
194  rospy.spin()
195 
197  # Callbacks from SBP messages (cb_sbp_*) implemented "manually".
198  self.handler.add_callback(self.cb_sbp_glonass_biases, msg_type=SBP_MSG_GLO_BIASES)
199  self.handler.add_callback(self.cb_sbp_heartbeat, msg_type=SBP_MSG_HEARTBEAT)
200  self.handler.add_callback(self.cb_sbp_pos_llh, msg_type=SBP_MSG_POS_LLH)
201  self.handler.add_callback(self.cb_sbp_base_pos_ecef, msg_type=SBP_MSG_BASE_POS_ECEF)
202  self.handler.add_callback(self.cb_sbp_obs, msg_type=SBP_MSG_OBS)
203  self.handler.add_callback(self.cb_sbp_settings_read_by_index_resp, msg_type=SBP_MSG_SETTINGS_READ_BY_INDEX_RESP)
204  self.handler.add_callback(self.cb_settings_read_resp, msg_type=SBP_MSG_SETTINGS_READ_RESP)
205  self.handler.add_callback(self.cb_sbp_tracking_state, msg_type=SBP_MSG_TRACKING_STATE)
206  self.handler.add_callback(self.cb_sbp_uart_state, msg_type=SBP_MSG_UART_STATE)
207 
208  # Callbacks generated "automatically".
209  self.init_callback('baseline_ecef_multi', BaselineEcef,
210  SBP_MSG_BASELINE_ECEF, MsgBaselineECEF,
211  'tow', 'x', 'y', 'z', 'accuracy', 'n_sats', 'flags')
212  self.init_callback('baseline_ned_multi', BaselineNed,
213  SBP_MSG_BASELINE_NED, MsgBaselineNED,
214  'tow', 'n', 'e', 'd', 'h_accuracy', 'v_accuracy', 'n_sats', 'flags')
215  self.init_callback('dops_multi', DopsMulti,
216  SBP_MSG_DOPS, MsgDops, 'tow', 'gdop', 'pdop', 'tdop', 'hdop', 'vdop', 'flags')
217  self.init_callback('gps_time_multi', GpsTimeMulti,
218  SBP_MSG_GPS_TIME, MsgGPSTime, 'wn', 'tow', 'ns_residual', 'flags')
219  self.init_callback('utc_time_multi', UtcTimeMulti,
220  SBP_MSG_UTC_TIME, MsgUtcTime,
221  'flags', 'tow', 'year', 'month', 'day', 'hours', 'minutes', 'seconds', 'ns')
222  self.init_callback('pos_ecef_multi', PosEcef,
223  SBP_MSG_POS_ECEF, MsgPosECEF,
224  'tow', 'x', 'y', 'z', 'accuracy', 'n_sats', 'flags')
225  self.init_callback('vel_ecef', VelEcef,
226  SBP_MSG_VEL_ECEF, MsgVelECEF,
227  'tow', 'x', 'y', 'z', 'accuracy', 'n_sats', 'flags')
228  self.init_callback('vel_ned', VelNed,
229  SBP_MSG_VEL_NED, MsgVelNED,
230  'tow', 'n', 'e', 'd', 'h_accuracy', 'v_accuracy', 'n_sats', 'flags')
231  self.init_callback('log', Log,
232  SBP_MSG_LOG, MsgLog, 'level', 'text')
233  self.init_callback('baseline_heading', BaselineHeading,
234  SBP_MSG_BASELINE_HEADING, MsgBaselineHeading, 'tow', 'heading', 'n_sats', 'flags')
235  self.init_callback('age_of_corrections', AgeOfCorrections,
236  SBP_MSG_AGE_CORRECTIONS, MsgAgeCorrections, 'tow', 'age')
237  self.init_callback('device_monitor', DeviceMonitor_V2_3_15,
238  SBP_MSG_DEVICE_MONITOR, MsgDeviceMonitor, 'dev_vin', 'cpu_vint', 'cpu_vaux',
239  'cpu_temperature', 'fe_temperature')
240 
241  # Raw IMU and Magnetometer measurements.
242  if self.publish_raw_imu_and_mag:
243  self.init_callback('imu_raw', ImuRawMulti,
244  SBP_MSG_IMU_RAW, MsgImuRaw,
245  'tow', 'tow_f', 'acc_x', 'acc_y', 'acc_z', 'gyr_x', 'gyr_y', 'gyr_z')
246  self.init_callback('mag_raw', MagRaw,
247  SBP_MSG_MAG_RAW, MsgMagRaw, 'tow', 'tow_f', 'mag_x', 'mag_y', 'mag_z')
248 
249  # Only if debug mode
250  if self.debug_mode:
251  self.handler.add_callback(self.cb_sbp_base_pos_llh, msg_type=SBP_MSG_BASE_POS_LLH)
252 
253  # do not publish llh message, prefer publishing directly navsatfix_spp or navsatfix_rtk_fix.
254  # self.init_callback('pos_llh', PosLlh,
255  # SBP_MSG_POS_LLH, MsgPosLLH,
256  # 'tow', 'lat', 'lon', 'height', 'h_accuracy', 'v_accuracy', 'n_sats', 'flags')
257 
258  # Relay "corrections" messages via UDP if in base station mode.
259  if self.base_station_mode:
260  rospy.loginfo("Starting device in Base Station Mode")
262  else:
263  rospy.loginfo("Starting device in Rover Mode")
265 
267  num_wifi_corrections = InfoWifiCorrections()
268  num_wifi_corrections.header.seq = 0
269  num_wifi_corrections.received_corrections = 0
270  num_wifi_corrections.latency = -1
271 
272  return num_wifi_corrections
273 
275  receiver_state_msg = ReceiverState_V2_3_15()
276  receiver_state_msg.num_sat = 0 # Unknown.
277  receiver_state_msg.rtk_mode_fix = False # Unknown.
278  receiver_state_msg.sat = [] # Unknown.
279  receiver_state_msg.cn0 = [] # Unknown.
280  receiver_state_msg.system_error = 255 # Unknown.
281  receiver_state_msg.io_error = 255 # Unknown.
282  receiver_state_msg.swift_nap_error = 255 # Unknown.
283  receiver_state_msg.external_antenna_present = 255 # Unknown.
284  receiver_state_msg.num_gps_sat = 0 # Unknown.
285  receiver_state_msg.cn0_gps = [] # Unknown.
286  receiver_state_msg.num_sbas_sat = 0 # Unknown.
287  receiver_state_msg.cn0_sbas = [] # Unknown.
288  receiver_state_msg.num_glonass_sat = 0 # Unknown.
289  receiver_state_msg.cn0_glonass = [] # Unknown.
290  receiver_state_msg.fix_mode = ReceiverState_V2_3_15.STR_FIX_MODE_UNKNOWN
291 
292  return receiver_state_msg
293 
294  def advertise_topics(self):
295  """
296  Advertise topics.
297  :return: python dictionary, with topic names used as keys and publishers as values.
298  """
299  publishers = {}
300 
301  publishers['rtk_fix'] = rospy.Publisher(rospy.get_name() + '/navsatfix_rtk_fix',
302  NavSatFix, queue_size=10)
303  publishers['spp'] = rospy.Publisher(rospy.get_name() + '/navsatfix_spp',
304  NavSatFix, queue_size=10)
305  publishers['best_fix'] = rospy.Publisher(rospy.get_name() + '/navsatfix_best_fix',
306  NavSatFix, queue_size=10)
307  publishers['heartbeat'] = rospy.Publisher(rospy.get_name() + '/heartbeat',
308  Heartbeat, queue_size=10)
309  publishers['tracking_state'] = rospy.Publisher(rospy.get_name() + '/tracking_state',
310  TrackingState_V2_3_15, queue_size=10)
311  publishers['receiver_state'] = rospy.Publisher(rospy.get_name() + '/debug/receiver_state',
312  ReceiverState_V2_3_15, queue_size=10)
313  # Do not publish llh message, prefer publishing directly navsatfix_spp or navsatfix_rtk_fix.
314  # publishers['pos_llh'] = rospy.Publisher(rospy.get_name() + '/pos_llh',
315  # PosLlh, queue_size=10)
316  publishers['vel_ned'] = rospy.Publisher(rospy.get_name() + '/vel_ned',
317  VelNed, queue_size=10)
318  publishers['log'] = rospy.Publisher(rospy.get_name() + '/log',
319  Log, queue_size=10)
320  publishers['uart_state'] = rospy.Publisher(rospy.get_name() + '/uart_state',
321  UartState_V2_3_15, queue_size=10)
322  publishers['device_monitor'] = rospy.Publisher(rospy.get_name() + '/device_monitor',
323  DeviceMonitor_V2_3_15, queue_size=10)
324  # Points in ENU frame.
325  publishers['enu_pose_fix'] = rospy.Publisher(rospy.get_name() + '/enu_pose_fix',
326  PoseWithCovarianceStamped, queue_size=10)
327  publishers['enu_point_fix'] = rospy.Publisher(rospy.get_name() + '/enu_point_fix',
328  PointStamped, queue_size=10)
329  publishers['enu_transform_fix'] = rospy.Publisher(rospy.get_name() + '/enu_transform_fix',
330  TransformStamped, queue_size=10)
331  publishers['enu_pose_spp'] = rospy.Publisher(rospy.get_name() + '/enu_pose_spp',
332  PoseWithCovarianceStamped, queue_size=10)
333  publishers['enu_point_spp'] = rospy.Publisher(rospy.get_name() + '/enu_point_spp',
334  PointStamped, queue_size=10)
335  publishers['enu_transform_spp'] = rospy.Publisher(rospy.get_name() + '/enu_transform_spp',
336  TransformStamped, queue_size=10)
337  publishers['gps_time_multi'] = rospy.Publisher(rospy.get_name() + '/gps_time',
338  GpsTimeMulti, queue_size=10)
339  publishers['baseline_ned_multi'] = rospy.Publisher(rospy.get_name() + '/baseline_ned',
340  BaselineNed, queue_size=10)
341  publishers['utc_time_multi'] = rospy.Publisher(rospy.get_name() + '/utc_time',
342  UtcTimeMulti, queue_size=10)
343  publishers['baseline_heading'] = rospy.Publisher(rospy.get_name() + '/baseline_heading',
344  BaselineHeading, queue_size=10)
345  publishers['age_of_corrections'] = rospy.Publisher(rospy.get_name() + '/age_of_corrections',
346  AgeOfCorrections, queue_size=10)
347  publishers['enu_pose_best_fix'] = rospy.Publisher(rospy.get_name() + '/enu_pose_best_fix',
348  PoseWithCovarianceStamped, queue_size=10)
349 
350  # Raw IMU and Magnetometer measurements.
351  if self.publish_raw_imu_and_mag:
352  publishers['imu_raw'] = rospy.Publisher(rospy.get_name() + '/imu_raw',
353  ImuRawMulti, queue_size=10)
354  publishers['mag_raw'] = rospy.Publisher(rospy.get_name() + '/mag_raw',
355  MagRaw, queue_size=10)
356 
357  # Topics published only if in "debug mode".
358  if self.debug_mode:
359  publishers['rtk_float'] = rospy.Publisher(rospy.get_name() + '/navsatfix_rtk_float',
360  NavSatFix, queue_size=10)
361  publishers['vel_ecef'] = rospy.Publisher(rospy.get_name() + '/vel_ecef',
362  VelEcef, queue_size=10)
363  publishers['enu_pose_float'] = rospy.Publisher(rospy.get_name() + '/enu_pose_float',
364  PoseWithCovarianceStamped, queue_size=10)
365  publishers['enu_point_float'] = rospy.Publisher(rospy.get_name() + '/enu_point_float',
366  PointStamped, queue_size=10)
367  publishers['enu_transform_float'] = rospy.Publisher(rospy.get_name() + '/enu_transform_float',
368  TransformStamped, queue_size=10)
369  publishers['baseline_ecef_multi'] = rospy.Publisher(rospy.get_name() + '/baseline_ecef',
370  BaselineEcef, queue_size=10)
371  publishers['dops_multi'] = rospy.Publisher(rospy.get_name() + '/dops',
372  DopsMulti, queue_size=10)
373  publishers['pos_ecef_multi'] = rospy.Publisher(rospy.get_name() + '/pos_ecef',
374  PosEcef, queue_size=10)
375  publishers['observation'] = rospy.Publisher(rospy.get_name() + '/observation',
376  Observation, queue_size=10)
377  publishers['base_pos_llh'] = rospy.Publisher(rospy.get_name() + '/base_pos_llh',
378  BasePosLlh, queue_size=10)
379  publishers['base_pos_ecef'] = rospy.Publisher(rospy.get_name() + '/base_pos_ecef',
380  BasePosEcef, queue_size=10)
381  if not self.base_station_mode:
382  publishers['wifi_corrections'] = rospy.Publisher(rospy.get_name() + '/debug/wifi_corrections',
383  InfoWifiCorrections, queue_size=10)
384 
385  return publishers
386 
388  """
389  Advertise service servers.
390  :return: python dictionary, with service names used as keys and servers as values.
391  """
392  servers = {}
393 
394  servers['reset_piksi'] = rospy.Service(rospy.get_name() +
395  '/reset_piksi',
396  std_srvs.srv.SetBool,
398 
399  servers['settings_write'] = rospy.Service(rospy.get_name() +
400  '/settings_write',
401  SettingsWrite,
403 
404  servers['settings_read_req'] = rospy.Service(rospy.get_name() +
405  '/settings_read_req',
406  SettingsReadReq,
408 
409  servers['settings_read_resp'] = rospy.Service(rospy.get_name() +
410  '/settings_read_resp',
411  SettingsReadResp,
413 
414  servers['settings_save'] = rospy.Service(rospy.get_name() +
415  '/settings_save',
416  std_srvs.srv.SetBool,
418 
419  return servers
420 
422  """
423  Ping base station periodically without blocking the driver.
424  """
425  ping_deadline_seconds = 3
426  interval_between_pings_seconds = 5
427 
428  while not rospy.is_shutdown():
429  # Send ping command.
430  command = ["ping",
431  "-w", str(ping_deadline_seconds), # deadline before stopping attempt
432  "-c", "1", # number of pings to send
434  ping = subprocess.Popen(command, stdout=subprocess.PIPE)
435 
436  out, error = ping.communicate()
437  # Search for 'min/avg/max/mdev' round trip delay time (rtt) numbers.
438  matcher = re.compile("(\d+.\d+)/(\d+.\d+)/(\d+.\d+)/(\d+.\d+)")
439 
440  if matcher.search(out) == None:
441  # No ping response within ping_deadline_seconds.
442  # In python write and read operations on built-in type are atomic,
443  # there's no need to use mutex.
444  self.num_wifi_corrections.latency = -1
445  else:
446  groups_rtt = matcher.search(out).groups()
447  avg_rtt = groups_rtt[1]
448  # In python write and read operations on built-in type are atomic,
449  # there's no need to use mutex.
450  self.num_wifi_corrections.latency = float(avg_rtt)
451 
452  time.sleep(interval_between_pings_seconds)
453 
454  def make_callback(self, sbp_type, ros_message, pub, attrs):
455  """
456  Dynamic generator for callback functions for message types from
457  the SBP library.
458  Inputs: 'sbp_type' name of SBP message type.
459  'ros_message' ROS message type with SBP format.
460  'pub' ROS publisher for ros_message.
461  'attrs' array of attributes in SBP/ROS message.
462  Returns: callback function 'callback'.
463  """
464 
465  def callback(msg, **metadata):
466  sbp_message = sbp_type(msg)
467  ros_message.header.stamp = rospy.Time.now()
468  for attr in attrs:
469  if attr == 'flags':
470  # Least significat three bits of flags indicate status.
471  if (sbp_message.flags & 0x07) == 0:
472  return # Invalid message, do not publish it.
473 
474  setattr(ros_message, attr, getattr(sbp_message, attr))
475  pub.publish(ros_message)
476 
477  return callback
478 
479  def init_callback(self, topic_name, ros_datatype, sbp_msg_type, callback_data_type, *attrs):
480  """
481  Initializes the callback function for an SBP
482  message type.
483  Inputs: 'topic_name' name of ROS topic for publisher
484  'ros_datatype' ROS custom message type
485  'sbp_msg_type' name of SBP message type for callback function
486  'callback_data_type' name of SBP message type for SBP library
487  '*attrs' array of attributes in ROS/SBP message
488  """
489  # Check that required topic has been advertised.
490  if topic_name in self.publishers:
491  ros_message = ros_datatype()
492 
493  # Add callback function.
494  pub = self.publishers[topic_name]
495  callback_function = self.make_callback(callback_data_type, ros_message, pub, attrs)
496  self.handler.add_callback(callback_function, msg_type=sbp_msg_type)
497 
498  def cb_sbp_obs(self, msg_raw, **metadata):
499  if self.debug_mode:
500  msg = MsgObs(msg_raw)
501 
502  obs_msg = Observation()
503  obs_msg.header.stamp = rospy.Time.now()
504 
505  obs_msg.tow = msg.header.t.tow
506  obs_msg.ns_residual = msg.header.t.ns_residual
507  obs_msg.wn = msg.header.t.wn
508  obs_msg.n_obs = msg.header.n_obs
509 
510  obs_msg.P = []
511  obs_msg.L_i = []
512  obs_msg.L_f = []
513  obs_msg.D_i = []
514  obs_msg.D_f = []
515  obs_msg.cn0 = []
516  obs_msg.lock = []
517  obs_msg.flags = []
518  obs_msg.sid_sat = []
519  obs_msg.sid_code = []
520 
521  for observation in msg.obs:
522  obs_msg.P.append(observation.P)
523  obs_msg.L_i.append(observation.L.i)
524  obs_msg.L_f.append(observation.L.f)
525  obs_msg.D_i.append(observation.D.i)
526  obs_msg.D_f.append(observation.D.f)
527  obs_msg.cn0.append(observation.cn0)
528  obs_msg.lock.append(observation.lock)
529  obs_msg.flags.append(observation.flags)
530  obs_msg.sid_sat.append(observation.sid.sat)
531  obs_msg.sid_code.append(observation.sid.code)
532 
533  self.publishers['observation'].publish(obs_msg)
534 
535  if self.base_station_mode:
536  self.multicaster.sendSbpPacket(msg_raw)
537 
538  def cb_sbp_base_pos_llh(self, msg_raw, **metadata):
539  if self.debug_mode:
540  msg = MsgBasePosLLH(msg_raw)
541 
542  pose_llh_msg = BasePosLlh()
543  pose_llh_msg.header.stamp = rospy.Time.now()
544 
545  pose_llh_msg.lat = msg.lat
546  pose_llh_msg.lon = msg.lon
547  pose_llh_msg.height = msg.height
548 
549  self.publishers['base_pos_llh'].publish(pose_llh_msg)
550 
551  def cb_sbp_base_pos_ecef(self, msg_raw, **metadata):
552  if self.debug_mode:
553  msg = MsgBasePosECEF(msg_raw)
554 
555  pose_ecef_msg = BasePosEcef()
556  pose_ecef_msg.header.stamp = rospy.Time.now()
557 
558  pose_ecef_msg.x = msg.x
559  pose_ecef_msg.y = msg.y
560  pose_ecef_msg.z = msg.z
561 
562  self.publishers['base_pos_ecef'].publish(pose_ecef_msg)
563 
564  if self.base_station_mode:
565  self.multicaster.sendSbpPacket(msg_raw)
566 
567  def cb_sbp_uart_state(self, msg_raw, **metadata):
568  msg = MsgUartState(msg_raw)
569  uart_state_msg = UartState_V2_3_15()
570 
571  uart_state_msg.latency_avg = msg.latency.avg
572  uart_state_msg.latency_lmin = msg.latency.lmin
573  uart_state_msg.latency_lmax = msg.latency.lmax
574  uart_state_msg.latency_current = msg.latency.current
575  uart_state_msg.obs_period_avg = msg.obs_period.avg
576  uart_state_msg.obs_period_pmin = msg.obs_period.pmin
577  uart_state_msg.obs_period_pmax = msg.obs_period.pmax
578  uart_state_msg.obs_period_current = msg.obs_period.current
579 
580  self.publishers['uart_state'].publish(uart_state_msg)
581 
582  def multicast_callback(self, msg, **metadata):
583  if self.framer:
584 
585  # TODO (marco-tranzatto) probably next commented part should be completely deleted.
586  # if self.debug_mode:
587  # # Test network delay by storing a fixed number of correction messages and retrieving the oldest one.
588  # # TODO (marco-tranzatto) check if we need to store even **metadata or not
589  # # self.received_corrections_fifo_stack.append([msg, **metadata])
590  # # oldest_correction = self.received_corrections_fifo_stack.popleft()
591  # self.received_corrections_fifo_stack.append(msg)
592  # oldest_correction = self.received_corrections_fifo_stack.popleft()
593  # self.framer(oldest_correction, **metadata)
594  # else:
595  # self.framer(msg, **metadata)
596  self.framer(msg, **metadata)
597 
598  # Publish debug message about wifi corrections, if enabled.
599  self.num_wifi_corrections.header.seq += 1
600  self.num_wifi_corrections.header.stamp = rospy.Time.now()
601  self.num_wifi_corrections.received_corrections += 1
602  if not self.base_station_mode:
603  self.publishers['wifi_corrections'].publish(self.num_wifi_corrections)
604 
605  else:
606  rospy.logwarn("Received external SBP msg, but Piksi not connected.")
607 
608  def cb_sbp_glonass_biases(self, msg_raw, **metadata):
609  if self.base_station_mode:
610  self.multicaster.sendSbpPacket(msg_raw)
611 
612  def cb_watchdog(self, event):
613  if ((rospy.get_rostime() - self.watchdog_time).to_sec() > 10.0):
614  rospy.logwarn("Heartbeat failed, watchdog triggered.")
615 
616  if self.base_station_mode:
617  rospy.signal_shutdown("Watchdog triggered, was gps disconnected?")
618 
619  def cb_sbp_pos_llh(self, msg_raw, **metadata):
620  msg = MsgPosLLH(msg_raw)
621 
622  # Invalid messages.
623  if msg.flags == PosLlhMulti.FIX_MODE_INVALID:
624  return
625  # SPP GPS messages.
626  elif msg.flags == PosLlhMulti.FIX_MODE_SPP:
627  self.publish_spp(msg.lat, msg.lon, msg.height, self.var_spp, NavSatStatus.STATUS_FIX)
628  # Differential GNSS (DGNSS)
629  elif msg.flags == PosLlhMulti.FIX_MODE_DGNSS:
630  rospy.logwarn(
631  "[cb_sbp_pos_llh]: case FIX_MODE_DGNSS was not implemented yet." +
632  "Contact the package/repository maintainers.")
633  # TODO what to do here?
634  return
635  # RTK messages.
636  elif msg.flags == PosLlhMulti.FIX_MODE_FLOAT_RTK:
637  # For now publish RTK float only in debug mode.
638  if self.debug_mode:
639  self.publish_rtk_float(msg.lat, msg.lon, msg.height)
640  elif msg.flags == PosLlhMulti.FIX_MODE_FIX_RTK:
641  # Use first RTK fix to set origin ENU frame, if it was not set by rosparam.
642  if not self.origin_enu_set:
643  self.init_geodetic_reference(msg.lat, msg.lon, msg.height)
644 
645  self.publish_rtk_fix(msg.lat, msg.lon, msg.height)
646  # Dead reckoning
647  elif msg.flags == PosLlhMulti.FIX_MODE_DEAD_RECKONING:
648  rospy.logwarn(
649  "[cb_sbp_pos_llh]: case FIX_MODE_DEAD_RECKONING was not implemented yet." +
650  "Contact the package/repository maintainers.")
651  return
652  # SBAS Position
653  elif msg.flags == PosLlhMulti.FIX_MODE_SBAS:
654  self.publish_spp(msg.lat, msg.lon, msg.height, self.var_spp_sbas, NavSatStatus.STATUS_SBAS_FIX)
655  else:
656  rospy.logerr(
657  "[cb_sbp_pos_llh]: Unknown case, you found a bug!" +
658  "Contact the package/repository maintainers." +
659  "Report: 'msg.flags = %d'" % (msg.flags))
660  return
661 
662  # Update debug msg and publish.
663  self.receiver_state_msg.rtk_mode_fix = True if (msg.flags == PosLlhMulti.FIX_MODE_FIX_RTK) else False
664 
665  if msg.flags == PosLlhMulti.FIX_MODE_INVALID:
666  self.receiver_state_msg.fix_mode = ReceiverState_V2_3_15.STR_FIX_MODE_INVALID
667  elif msg.flags == PosLlhMulti.FIX_MODE_SPP:
668  self.receiver_state_msg.fix_mode = ReceiverState_V2_3_15.STR_FIX_MODE_SPP
669  elif msg.flags == PosLlhMulti.FIX_MODE_DGNSS:
670  self.receiver_state_msg.fix_mode = ReceiverState_V2_3_15.STR_FIX_MODE_DGNSS
671  elif msg.flags == PosLlhMulti.FIX_MODE_FLOAT_RTK:
672  self.receiver_state_msg.fix_mode = ReceiverState_V2_3_15.STR_FIX_MODE_FLOAT_RTK
673  elif msg.flags == PosLlhMulti.FIX_MODE_FIX_RTK:
674  self.receiver_state_msg.fix_mode = ReceiverState_V2_3_15.STR_FIX_MODE_FIXED_RTK
675  elif msg.flags == PosLlhMulti.FIX_MODE_DEAD_RECKONING:
676  self.receiver_state_msg.fix_mode = ReceiverState_V2_3_15.FIX_MODE_DEAD_RECKONING
677  elif msg.flags == PosLlhMulti.FIX_MODE_SBAS:
678  self.receiver_state_msg.fix_mode = ReceiverState_V2_3_15.STR_FIX_MODE_SBAS
679  else:
680  self.receiver_state_msg.fix_mode = ReceiverState_V2_3_15.STR_FIX_MODE_UNKNOWN
681 
683 
684  def publish_spp(self, latitude, longitude, height, variance, navsatstatus_fix):
685  self.publish_wgs84_point(latitude, longitude, height, variance, navsatstatus_fix,
686  self.publishers['spp'],
687  self.publishers['enu_pose_spp'], self.publishers['enu_point_spp'],
688  self.publishers['enu_transform_spp'], self.publishers['best_fix'],
689  self.publishers['enu_pose_best_fix'])
690 
691  def publish_rtk_float(self, latitude, longitude, height):
692  self.publish_wgs84_point(latitude, longitude, height, self.var_rtk_float, NavSatStatus.STATUS_GBAS_FIX,
693  self.publishers['rtk_float'],
694  self.publishers['enu_pose_float'], self.publishers['enu_point_float'],
695  self.publishers['enu_transform_float'], self.publishers['best_fix'],
696  self.publishers['enu_pose_best_fix'])
697 
698  def publish_rtk_fix(self, latitude, longitude, height):
699  self.publish_wgs84_point(latitude, longitude, height, self.var_rtk_fix, NavSatStatus.STATUS_GBAS_FIX,
700  self.publishers['rtk_fix'],
701  self.publishers['enu_pose_fix'], self.publishers['enu_point_fix'],
702  self.publishers['enu_transform_fix'], self.publishers['best_fix'],
703  self.publishers['enu_pose_best_fix'])
704 
705  def publish_wgs84_point(self, latitude, longitude, height, variance, navsat_status, pub_navsatfix, pub_pose,
706  pub_point, pub_transform, pub_navsatfix_best_pose, pub_pose_best_fix):
707  # Navsatfix message.
708  navsatfix_msg = NavSatFix()
709  navsatfix_msg.header.stamp = rospy.Time.now()
710  navsatfix_msg.header.frame_id = self.navsatfix_frame_id
711  navsatfix_msg.position_covariance_type = NavSatFix.COVARIANCE_TYPE_APPROXIMATED
712  navsatfix_msg.status.service = NavSatStatus.SERVICE_GPS
713  navsatfix_msg.latitude = latitude
714  navsatfix_msg.longitude = longitude
715  navsatfix_msg.altitude = height
716  navsatfix_msg.status.status = navsat_status
717  navsatfix_msg.position_covariance = [variance[0], 0, 0,
718  0, variance[1], 0,
719  0, 0, variance[2]]
720  # Local Enu coordinate.
721  (east, north, up) = self.geodetic_to_enu(latitude, longitude, height)
722 
723  # Pose message.
724  pose_msg = PoseWithCovarianceStamped()
725  pose_msg.header.stamp = navsatfix_msg.header.stamp
726  pose_msg.header.frame_id = self.enu_frame_id
727  pose_msg.pose = self.enu_to_pose_msg(east, north, up, variance)
728 
729  # Point message.
730  point_msg = PointStamped()
731  point_msg.header.stamp = navsatfix_msg.header.stamp
732  point_msg.header.frame_id = self.enu_frame_id
733  point_msg.point = self.enu_to_point_msg(east, north, up)
734 
735  # Transform message.
736  transform_msg = TransformStamped()
737  transform_msg.header.stamp = navsatfix_msg.header.stamp
738  transform_msg.header.frame_id = self.enu_frame_id
739  transform_msg.child_frame_id = self.transform_child_frame_id
740  transform_msg.transform = self.enu_to_transform_msg(east, north, up)
741 
742  # Publish.
743  pub_navsatfix.publish(navsatfix_msg)
744  pub_pose.publish(pose_msg)
745  pub_point.publish(point_msg)
746  pub_transform.publish(transform_msg)
747  pub_navsatfix_best_pose.publish(navsatfix_msg)
748  pub_pose_best_fix.publish(pose_msg)
749 
750  def cb_sbp_heartbeat(self, msg_raw, **metadata):
751  msg = MsgHeartbeat(msg_raw)
752 
753  # Let watchdag know messages are still arriving
754  self.watchdog_time = rospy.get_rostime()
755 
756  # Start watchdog with 10 second timeout to ensure we keep getting gps
757  if not self.messages_started:
758  self.messages_started = True
759  rospy.Timer(rospy.Duration(10), self.cb_watchdog)
760 
761  heartbeat_msg = Heartbeat()
762  heartbeat_msg.header.stamp = rospy.Time.now()
763  heartbeat_msg.system_error = msg.flags & 0x01
764  heartbeat_msg.io_error = msg.flags & 0x02
765  heartbeat_msg.swift_nap_error = msg.flags & 0x04
766  heartbeat_msg.sbp_minor_version = (msg.flags & 0xFF00) >> 8
767  heartbeat_msg.sbp_major_version = (msg.flags & 0xFF0000) >> 16
768  heartbeat_msg.external_antenna_present = (msg.flags & 0x80000000) >> 31
769 
770  self.publishers['heartbeat'].publish(heartbeat_msg)
771 
772  # Update debug msg and publish.
773  self.receiver_state_msg.system_error = heartbeat_msg.system_error
774  self.receiver_state_msg.io_error = heartbeat_msg.io_error
775  self.receiver_state_msg.swift_nap_error = heartbeat_msg.swift_nap_error
776  self.receiver_state_msg.external_antenna_present = heartbeat_msg.external_antenna_present
778 
779  if self.base_station_mode:
780  self.multicaster.sendSbpPacket(msg_raw)
781 
782  def cb_sbp_tracking_state(self, msg_raw, **metadata):
783  msg = MsgTrackingState(msg_raw)
784 
785  # print "\n\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
786  #
787  # for single_tracking_state in msg.states:
788  # print single_tracking_state
789  # print "--------------------\n"
790 
791  tracking_state_msg = TrackingState_V2_3_15()
792  tracking_state_msg.header.stamp = rospy.Time.now()
793  tracking_state_msg.sat = []
794  tracking_state_msg.code = []
795  tracking_state_msg.fcn = []
796  tracking_state_msg.cn0 = []
797 
798  # Temporary variables for receiver state message.
799  num_gps_sat = 0
800  cn0_gps = []
801  num_sbas_sat = 0
802  cn0_sbas = []
803  num_glonass_sat = 0
804  cn0_glonass = []
805 
806  for single_tracking_state in msg.states:
807 
808  # Use satellites with valid cn0.
809  if single_tracking_state.cn0 > 0.0:
810 
811  tracking_state_msg.sat.append(single_tracking_state.sid.sat)
812  tracking_state_msg.code.append(single_tracking_state.sid.code)
813  tracking_state_msg.fcn.append(single_tracking_state.fcn)
814  tracking_state_msg.cn0.append(single_tracking_state.cn0)
815 
816  # Receiver state fields.
817  code = single_tracking_state.sid.code
818  if code == TrackingState_V2_3_15.CODE_GPS_L1CA or \
819  code == TrackingState_V2_3_15.CODE_GPS_L2CM or \
820  code == TrackingState_V2_3_15.CODE_GPS_L1P or \
821  code == TrackingState_V2_3_15.CODE_GPS_L2P:
822  num_gps_sat += 1
823  cn0_gps.append(single_tracking_state.cn0)
824 
825  if code == TrackingState_V2_3_15.CODE_SBAS_L1CA:
826  num_sbas_sat += 1
827  cn0_sbas.append(single_tracking_state.cn0)
828 
829  if code == TrackingState_V2_3_15.CODE_GLO_L1CA or \
830  code == TrackingState_V2_3_15.CODE_GLO_L1CA:
831  num_glonass_sat += 1
832  cn0_glonass.append(single_tracking_state.cn0)
833 
834  # Publish if there's at least one element in each array.
835  if len(tracking_state_msg.sat) \
836  and len(tracking_state_msg.code) \
837  and len(tracking_state_msg.fcn) \
838  and len(tracking_state_msg.cn0):
839  self.publishers['tracking_state'].publish(tracking_state_msg)
840 
841  # Update debug msg and publish.
842  self.receiver_state_msg.num_sat = num_gps_sat + num_sbas_sat + num_glonass_sat
843  self.receiver_state_msg.sat = tracking_state_msg.sat
844  self.receiver_state_msg.cn0 = tracking_state_msg.cn0
845  self.receiver_state_msg.num_gps_sat = num_gps_sat
846  self.receiver_state_msg.cn0_gps = cn0_gps
847  self.receiver_state_msg.num_sbas_sat = num_sbas_sat
848  self.receiver_state_msg.cn0_sbas = cn0_sbas
849  self.receiver_state_msg.num_glonass_sat = num_glonass_sat
850  self.receiver_state_msg.cn0_glonass = cn0_glonass
851 
853 
855  self.receiver_state_msg.header.stamp = rospy.Time.now()
856  self.publishers['receiver_state'].publish(self.receiver_state_msg)
857 
858  def init_geodetic_reference(self, latitude, longitude, altitude):
859  if self.origin_enu_set:
860  return
861 
862  self.latitude0 = math.radians(latitude)
863  self.longitude0 = math.radians(longitude)
864  self.altitude0 = altitude
865 
866  (self.initial_ecef_x, self.initial_ecef_y, self.initial_ecef_z) = self.geodetic_to_ecef(latitude, longitude,
867  altitude)
868  # Compute ECEF to NED.
869  phiP = math.atan2(self.initial_ecef_z,
870  math.sqrt(math.pow(self.initial_ecef_x, 2) + math.pow(self.initial_ecef_y, 2)))
871  self.ecef_to_ned_matrix = self.n_re(phiP, self.longitude0)
872 
873  self.origin_enu_set = True
874 
875  rospy.loginfo("Origin ENU frame set to: %.6f, %.6f, %.2f" % (latitude, longitude, altitude))
876 
877  def geodetic_to_ecef(self, latitude, longitude, altitude):
878  # Convert geodetic coordinates to ECEF.
879  # http://code.google.com/p/pysatel/source/browse/trunk/coord.py?r=22
880  lat_rad = math.radians(latitude)
881  lon_rad = math.radians(longitude)
882  xi = math.sqrt(1 - PiksiMulti.kFirstEccentricitySquared * math.sin(lat_rad) * math.sin(lat_rad))
883  x = (PiksiMulti.kSemimajorAxis / xi + altitude) * math.cos(lat_rad) * math.cos(lon_rad)
884  y = (PiksiMulti.kSemimajorAxis / xi + altitude) * math.cos(lat_rad) * math.sin(lon_rad)
885  z = (PiksiMulti.kSemimajorAxis / xi * (1 - PiksiMulti.kFirstEccentricitySquared) + altitude) * math.sin(lat_rad)
886 
887  return x, y, z
888 
889  def ecef_to_ned(self, x, y, z):
890  # Converts ECEF coordinate position into local-tangent-plane NED.
891  # Coordinates relative to given ECEF coordinate frame.
892  vect = np.array([0.0, 0.0, 0.0])
893  vect[0] = x - self.initial_ecef_x
894  vect[1] = y - self.initial_ecef_y
895  vect[2] = z - self.initial_ecef_z
896  ret = self.ecef_to_ned_matrix.dot(vect)
897  n = ret[0]
898  e = ret[1]
899  d = -ret[2]
900 
901  return n, e, d
902 
903  def geodetic_to_enu(self, latitude, longitude, altitude):
904  # Geodetic position to local ENU frame
905  (x, y, z) = self.geodetic_to_ecef(latitude, longitude, altitude)
906  (north, east, down) = self.ecef_to_ned(x, y, z)
907 
908  # Return East, North, Up coordinate.
909  return east, north, -down
910 
911  def n_re(self, lat_radians, lon_radians):
912  s_lat = math.sin(lat_radians)
913  s_lon = math.sin(lon_radians)
914  c_lat = math.cos(lat_radians)
915  c_lon = math.cos(lon_radians)
916 
917  ret = np.eye(3)
918  ret[0, 0] = -s_lat * c_lon
919  ret[0, 1] = -s_lat * s_lon
920  ret[0, 2] = c_lat
921  ret[1, 0] = -s_lon
922  ret[1, 1] = c_lon
923  ret[1, 2] = 0.0
924  ret[2, 0] = c_lat * c_lon
925  ret[2, 1] = c_lat * s_lon
926  ret[2, 2] = s_lat
927 
928  return ret
929 
930  def enu_to_pose_msg(self, east, north, up, variance):
931  pose_msg = PoseWithCovariance()
932 
933  # Fill covariance using variance parameter of GPS.
934  pose_msg.covariance[6 * 0 + 0] = variance[0]
935  pose_msg.covariance[6 * 1 + 1] = variance[1]
936  pose_msg.covariance[6 * 2 + 2] = variance[2]
937 
938  # Fill pose section.
939  pose_msg.pose.position.x = east
940  pose_msg.pose.position.y = north
941  pose_msg.pose.position.z = up
942 
943  # GPS points do not have orientation
944  pose_msg.pose.orientation.x = 0.0
945  pose_msg.pose.orientation.y = 0.0
946  pose_msg.pose.orientation.z = 0.0
947  pose_msg.pose.orientation.w = 1.0
948 
949  return pose_msg
950 
951  def enu_to_point_msg(self, east, north, up):
952  point_msg = Point()
953 
954  # Fill pose section.
955  point_msg.x = east
956  point_msg.y = north
957  point_msg.z = up
958 
959  return point_msg
960 
961  def enu_to_transform_msg(self, east, north, up):
962  transform_msg = Transform()
963 
964  # Fill message.
965  transform_msg.translation.x = east
966  transform_msg.translation.y = north
967  transform_msg.translation.z = up
968 
969  # Set orientation to unit quaternion as it does not really metter.
970  transform_msg.rotation.x = 0.0
971  transform_msg.rotation.y = 0.0
972  transform_msg.rotation.z = 0.0
973  transform_msg.rotation.w = 1.0
974 
975  return transform_msg
976 
977  def reset_piksi_service_callback(self, request):
978  response = std_srvs.srv.SetBoolResponse()
979 
980  if request.data:
981  # Send reset message.
982  reset_sbp = SBP(SBP_MSG_RESET)
983  reset_sbp.payload = ''
984  reset_msg = reset_sbp.pack()
985  self.driver.write(reset_msg)
986 
987  rospy.logwarn("Swift receiver hard reset via rosservice call.")
988 
989  # Init messages with "memory".
992 
993  response.success = True
994  response.message = "Swift receiver reset command sent."
995  else:
996  response.success = False
997  response.message = "Swift receiver reset command not sent."
998 
999  return response
1000 
1001  def settings_write_server(self, request):
1002  response = SettingsWriteResponse()
1003 
1004  self.settings_write(request.section_setting, request.setting, request.value)
1005  response.success = True
1006  response.message = "Settings written. Please use service 'settings_read_req' if you want to double check."
1007 
1008  return response
1009 
1010  def settings_read_req_server(self, request):
1011  response = SettingsReadReqResponse()
1012 
1013  # Make sure we do not have any old setting in memory.
1015  self.settings_read_req(request.section_setting, request.setting)
1016  response.success = True
1017  response.message = "Read-request sent. Please use 'settings_read_resp' to get the response."
1018 
1019  return response
1020 
1021  def settings_read_resp_server(self, request):
1022  response = SettingsReadRespResponse()
1023 
1025  response.success = True
1026  response.message = ""
1027  response.section_setting = self.last_section_setting_read
1028  response.setting = self.last_setting_read
1029  response.value = self.last_value_read
1030  else:
1031  response.success = False
1032  response.message = "Please trigger a new 'settings_read_req' via service call."
1033  response.section_setting = []
1034  response.setting = []
1035  response.value = []
1036 
1038 
1039  return response
1040 
1041  def settings_save_callback(self, request):
1042  response = std_srvs.srv.SetBoolResponse()
1043 
1044  if request.data:
1045  self.settings_save()
1046  response.success = True
1047  response.message = "Swift receiver settings have been saved to flash."
1048  else:
1049  response.success = False
1050  response.message = "Please pass 'true' to this service call to explicitly save to flash the local settings."
1051 
1052  return response
1053 
1055  command = ["pip", "show", "sbp"]
1056  pip_show_output = subprocess.Popen(command, stdout=subprocess.PIPE)
1057  out, error = pip_show_output.communicate()
1058 
1059  # Search for version number, output assumed in the form "Version: X.X.X"
1060  version_output = re.search("Version: \d+.\d+.\d+", out)
1061 
1062  if version_output is None:
1063  # No version found
1064  rospy.logfatal("No SBP library found. Please install it by using script in 'install' folder.")
1065  rospy.signal_shutdown("No SBP library found. Please install it by using script in 'install' folder.")
1066  return -1
1067  else:
1068  # extract version number
1069  version_output_string = version_output.group()
1070  version_number = re.search("\d+.\d+.\d+", version_output_string)
1071  return version_number.group()
1072 
1073  def settings_write(self, section_setting, setting, value):
1074  """
1075  Write the defined configuration to Swift receiver.
1076  """
1077  setting_string = '%s\0%s\0%s\0' % (section_setting, setting, value)
1078  write_msg = MsgSettingsWrite(setting=setting_string)
1079  self.framer(write_msg)
1080 
1081  def settings_save(self):
1082  """
1083  Save settings message persists the device's current settings
1084  configuration to its on-board flash memory file system.
1085  """
1086  save_msg = MsgSettingsSave()
1087  self.framer(save_msg)
1088 
1089  def settings_read_req(self, section_setting, setting):
1090  """
1091  Request a configuration value to Swift receiver.
1092  """
1093  setting_string = '%s\0%s\0' % (section_setting, setting)
1094  read_req_msg = MsgSettingsReadReq(setting=setting_string)
1095  self.framer(read_req_msg)
1096 
1097  def cb_settings_read_resp(self, msg_raw, **metadata):
1098  """
1099  Response to a settings_read_req.
1100  """
1101  msg = MsgSettingsReadResp(msg_raw)
1102  setting_string = msg.setting.split('\0')
1103  self.last_section_setting_read = setting_string[0]
1104  self.last_setting_read = setting_string[1]
1105  self.last_value_read = setting_string[2]
1106 
1107  def settings_read_by_index_req(self, index):
1108  """
1109  Request a configuration value to Swift receiver by parameter index number.
1110  """
1111  read_req_by_index_msg = MsgSettingsReadByIndexReq(index=index)
1112  self.framer(read_req_by_index_msg)
1113 
1114  def cb_sbp_settings_read_by_index_resp(self, msg_raw, **metadata):
1115  """
1116  Response to a settings_read_by_index_req.
1117  """
1118  msg = MsgSettingsReadByIndexResp(msg_raw)
1119  setting_string = msg.setting.split('\0')
1120  self.last_section_setting_read = setting_string[0]
1121  self.last_setting_read = setting_string[1]
1122  self.last_value_read = setting_string[2]
1123 
1125  self.last_section_setting_read = []
1126  self.last_setting_read = []
1127  self.last_value_read = []
def cb_sbp_heartbeat(self, msg_raw, metadata)
Definition: piksi_multi.py:750
def publish_rtk_fix(self, latitude, longitude, height)
Definition: piksi_multi.py:698
def enu_to_point_msg(self, east, north, up)
Definition: piksi_multi.py:951
def init_callback(self, topic_name, ros_datatype, sbp_msg_type, callback_data_type, attrs)
Definition: piksi_multi.py:479
def cb_settings_read_resp(self, msg_raw, metadata)
def reset_piksi_service_callback(self, request)
Definition: piksi_multi.py:977
def settings_read_req_server(self, request)
def geodetic_to_enu(self, latitude, longitude, altitude)
Definition: piksi_multi.py:903
def enu_to_pose_msg(self, east, north, up, variance)
Definition: piksi_multi.py:930
def publish_rtk_float(self, latitude, longitude, height)
Definition: piksi_multi.py:691
def publish_wgs84_point(self, latitude, longitude, height, variance, navsat_status, pub_navsatfix, pub_pose, pub_point, pub_transform, pub_navsatfix_best_pose, pub_pose_best_fix)
Definition: piksi_multi.py:706
def cb_sbp_uart_state(self, msg_raw, metadata)
Definition: piksi_multi.py:567
def cb_sbp_pos_llh(self, msg_raw, metadata)
Definition: piksi_multi.py:619
def cb_sbp_base_pos_ecef(self, msg_raw, metadata)
Definition: piksi_multi.py:551
def enu_to_transform_msg(self, east, north, up)
Definition: piksi_multi.py:961
def cb_sbp_settings_read_by_index_resp(self, msg_raw, metadata)
def cb_sbp_obs(self, msg_raw, metadata)
Definition: piksi_multi.py:498
def cb_sbp_glonass_biases(self, msg_raw, metadata)
Definition: piksi_multi.py:608
def cb_sbp_tracking_state(self, msg_raw, metadata)
Definition: piksi_multi.py:782
def cb_sbp_base_pos_llh(self, msg_raw, metadata)
Definition: piksi_multi.py:538
def multicast_callback(self, msg, metadata)
Definition: piksi_multi.py:582
def settings_read_req(self, section_setting, setting)
def settings_write(self, section_setting, setting, value)
def settings_read_resp_server(self, request)
def make_callback(self, sbp_type, ros_message, pub, attrs)
Definition: piksi_multi.py:454
def publish_spp(self, latitude, longitude, height, variance, navsatstatus_fix)
Definition: piksi_multi.py:684
def init_geodetic_reference(self, latitude, longitude, altitude)
Definition: piksi_multi.py:858
def geodetic_to_ecef(self, latitude, longitude, altitude)
Definition: piksi_multi.py:877
def n_re(self, lat_radians, lon_radians)
Definition: piksi_multi.py:911


piksi_multi_rtk
Author(s):
autogenerated on Mon Jun 10 2019 13:08:19