src/xsens_driver/mtdevice.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 from __future__ import print_function
3 
4 import serial
5 import struct
6 import sys
7 import time
8 import glob
9 
10 from xsens_driver.mtdef import MID, OutputMode, OutputSettings, MTException, \
11  Baudrates, XDIGroup, getMIDName, DeviceState, DeprecatedMID, \
12  MTErrorMessage, MTTimeoutException
13 
14 
15 def _byte(b):
16  """Convert the given character or byte to a byte."""
17  if sys.version_info[0] == 2:
18  return ord(b)
19  if isinstance(b, bytearray):
20  return b[0]
21  return b
22 
23 
24 
27 class MTDevice(object):
28  """XSens MT device communication object."""
29 
30  def __init__(self, port, baudrate=115200, timeout=0.002, autoconf=True,
31  config_mode=False, verbose=False, initial_wait=0.1):
32  """Open device."""
33  self.verbose = verbose
34  # serial interface to the device
35  try:
36  self.device = serial.Serial(port, baudrate, timeout=timeout,
37  writeTimeout=timeout)
38  except IOError:
39  # FIXME with pyserial3 we might need some specific flags
40  self.device = serial.Serial(port, baudrate, timeout=timeout,
41  writeTimeout=timeout, rtscts=True,
42  dsrdtr=True)
43  time.sleep(initial_wait) # open returns before device is ready
44  self.device.flushInput()
45  self.device.flushOutput()
46  # timeout for communication
47  self.timeout = 100*timeout
48  # state of the device
49  self.state = None
50  if autoconf:
51  self.auto_config_legacy()
52  else:
53  # mode parameter of the IMU
54  self.mode = None
55  # settings parameter of the IMU
56  self.settings = None
57  # length of the MTData message
58  self.length = None
59  # header of the MTData message
60  self.header = None
61  if config_mode:
62  self.GoToConfig()
63 
64 
67  def write_msg(self, mid, data=b''):
68  """Low-level message sending function."""
69  length = len(data)
70  if length > 254:
71  lendat = b'\xFF' + struct.pack('!H', length)
72  else:
73  lendat = struct.pack('!B', length)
74  packet = b'\xFA\xFF' + struct.pack('!B', mid) + lendat + data
75  packet += struct.pack('!B', 0xFF & (-(sum(map(_byte, packet[1:])))))
76  msg = packet
77  start = time.time()
78  while ((time.time()-start) < self.timeout) and self.device.read():
79  pass
80  try:
81  self.device.write(msg)
82  except serial.serialutil.SerialTimeoutException:
83  raise MTTimeoutException("writing message")
84  if self.verbose:
85  print("MT: Write message id 0x%02X (%s) with %d data bytes: "
86  "[%s]" % (mid, getMIDName(mid), length,
87  ' '.join("%02X" % _byte(v) for v in data)))
88 
89  def waitfor(self, size=1):
90  """Get a given amount of data."""
91  buf = bytearray()
92  for _ in range(100):
93  buf.extend(self.device.read(size-len(buf)))
94  if len(buf) == size:
95  return buf
96  if self.verbose:
97  print("waiting for %d bytes, got %d so far: [%s]" %
98  (size, len(buf), ' '.join('%02X' % v for v in buf)))
99  raise MTTimeoutException("waiting for message")
100 
101  def read_data_msg(self, buf=bytearray()):
102  """Low-level MTData receiving function.
103  Take advantage of known message length.
104  """
105  start = time.time()
106  if self.length <= 254:
107  totlength = 5 + self.length
108  else:
109  totlength = 7 + self.length
110  while (time.time()-start) < self.timeout:
111  buf.extend(self.waitfor(totlength - len(buf)))
112  preamble_ind = buf.find(self.header)
113  if preamble_ind == -1: # not found
114  # discard unexploitable data
115  if self.verbose:
116  sys.stderr.write("MT: discarding (no preamble).\n")
117  del buf[:-3]
118  continue
119  elif preamble_ind: # found but not at start
120  # discard leading bytes
121  if self.verbose:
122  sys.stderr.write("MT: discarding (before preamble).\n")
123  del buf[:preamble_ind]
124  # complete message for checksum
125  buf.extend(self.waitfor(totlength-len(buf)))
126  if 0xFF & sum(buf[1:]):
127  if self.verbose:
128  sys.stderr.write("MT: invalid checksum; discarding data "
129  "and waiting for next message.\n")
130  del buf[:buf.find(self.header)-2]
131  continue
132  data = str(buf[-self.length-1:-1])
133  del buf[:]
134  return data
135  else:
136  raise MTException("could not find MTData message.")
137 
138  def read_msg(self):
139  """Low-level message receiving function."""
140  start = time.time()
141  while (time.time()-start) < self.timeout:
142  # first part of preamble
143  if _byte(self.waitfor()) != 0xFA:
144  continue
145  # second part of preamble
146  if _byte(self.waitfor()) != 0xFF: # we assume no timeout anymore
147  continue
148  # read message id and length of message
149  mid, length = struct.unpack('!BB', self.waitfor(2))
150  if length == 255: # extended length
151  length, = struct.unpack('!H', self.waitfor(2))
152  # read contents and checksum
153  buf = self.waitfor(length+1)
154  checksum = buf[-1]
155  data = struct.unpack('!%dB' % length, buf[:-1])
156  # check message integrity
157  if 0xFF & sum(data, 0xFF+mid+length+checksum):
158  if self.verbose:
159  sys.stderr.write("invalid checksum; discarding data and "
160  "waiting for next message.\n")
161  continue
162  if self.verbose:
163  print("MT: Got message id 0x%02X (%s) with %d data bytes: "
164  "[%s]" % (mid, getMIDName(mid), length,
165  ' '.join("%02X" % v for v in data)))
166  if mid == MID.Error:
167  raise MTErrorMessage(data[0])
168  return (mid, buf[:-1])
169  else:
170  raise MTException("could not find message.")
171 
172  def write_ack(self, mid, data=b'', n_resend=30, n_read=25):
173  """Send a message and read confirmation."""
174  for _ in range(n_resend):
175  self.write_msg(mid, data)
176  for _ in range(n_read):
177  mid_ack, data_ack = self.read_msg()
178  if mid_ack == (mid+1):
179  break
180  elif self.verbose:
181  print("ack (0x%02X) expected, got 0x%02X instead" %
182  (mid+1, mid_ack))
183  else: # inner look not broken
184  continue # retry (send+wait)
185  break # still no luck
186  else:
187  n_retries = n_resend*n_read
188  raise MTException("Ack (0x%02X) expected, MID 0x%02X received "
189  "instead (after %d retries)." % (mid+1, mid_ack,
190  n_retries))
191  return data_ack
192 
194  """Switch device to config state if necessary."""
195  if self.state != DeviceState.Config:
196  self.GoToConfig()
197 
199  """Switch device to measurement state if necessary."""
200  if self.state != DeviceState.Measurement:
201  self.GoToMeasurement()
202 
203 
206  def Reset(self, go_to_config=False):
207  """Reset MT device.
208 
209  If go_to_config then send WakeUpAck in order to leave the device in
210  config mode.
211  """
212  self.write_ack(MID.Reset)
213  if go_to_config:
214  time.sleep(0.01)
215  mid, _ = self.read_msg()
216  if mid == MID.WakeUp:
217  self.write_msg(MID.WakeUpAck)
218  self.state = DeviceState.Config
219  else:
220  self.state = DeviceState.Measurement
221 
222  def GoToConfig(self):
223  """Place MT device in configuration mode."""
224  self.write_ack(MID.GoToConfig)
225  self.state = DeviceState.Config
226 
227  def GoToMeasurement(self):
228  """Place MT device in measurement mode."""
229  self._ensure_config_state()
230  self.write_ack(MID.GoToMeasurement)
231  self.state = DeviceState.Measurement
232 
233  def GetDeviceID(self):
234  """Get the device identifier."""
235  self._ensure_config_state()
236  data = self.write_ack(MID.ReqDID)
237  deviceID, = struct.unpack('!I', data)
238  return deviceID
239 
240  def GetProductCode(self):
241  """Get the product code."""
242  self._ensure_config_state()
243  data = self.write_ack(MID.ReqProductCode)
244  return str(data).strip()
245 
247  """Get the hardware version."""
248  self._ensure_config_state()
249  data = self.write_ack(MID.ReqHardwareVersion)
250  major, minor = struct.unpack('!BB', data)
251  return (major, minor)
252 
253  def GetFirmwareRev(self):
254  """Get the firmware version."""
255  self._ensure_config_state()
256  data = self.write_ack(MID.ReqFWRev)
257  if len(data) == 3:
258  major, minor, revision = struct.unpack('!BBB', data)
259  return (major, minor, revision)
260  else:
261  # TODO check buildnr/svnrev not sure unsigned
262  major, minor, rev, buildnr, svnrev = struct.unpack('!BBBII', data)
263  return (major, minor, rev, buildnr, svnrev)
264 
265  def RunSelfTest(self):
266  """Run the built-in self test."""
267  self._ensure_config_state()
268  data = self.write_ack(MID.RunSelfTest)
269  bit_names = ['accX', 'accY', 'accZ', 'gyrX', 'gyrY', 'gyrZ',
270  'magX', 'magY', 'magZ']
271  self_test_results = []
272  for i, name in enumerate(bit_names):
273  self_test_results.append((name, (data >> i) & 1))
274  return self_test_results
275 
276  def GetBaudrate(self):
277  """Get the current baudrate id of the device."""
278  self._ensure_config_state()
279  data = self.write_ack(MID.SetBaudrate)
280  return data[0]
281 
282  def SetBaudrate(self, brid):
283  """Set the baudrate of the device using the baudrate id."""
284  self._ensure_config_state()
285  self.write_ack(MID.SetBaudrate, (brid,))
286 
287  def GetErrorMode(self):
288  """Get the current error mode of the device."""
289  self._ensure_config_state()
290  data = self.write_ack(MID.SetErrorMode)
291  error_mode, = struct.unpack('!H', data)
292  return error_mode
293 
294  def SetErrorMode(self, error_mode):
295  """Set the error mode of the device.
296 
297  The error mode defines the way the device deals with errors (expect
298  message errors):
299  0x0000: ignore any errors except message handling errors,
300  0x0001: in case of missing sampling instance: increase sample
301  counter and do not send error message,
302  0x0002: in case of missing sampling instance: increase sample
303  counter and send error message,
304  0x0003: in case of non-message handling error, an error message is
305  sent and the device will go into Config State.
306  """
307  self._ensure_config_state()
308  data = struct.pack('!H', error_mode)
309  self.write_ack(MID.SetErrorMode, data)
310 
311  def GetOptionFlags(self):
312  """Get the option flags (MTi-1 series)."""
313  self._ensure_config_state()
314  data = self.write_ack(MID.SetOptionFlags)
315  flags, = struct.unpack('!I', data)
316  return flags
317 
318  def SetOptionFlags(self, set_flags, clear_flags):
319  """Set the option flags (MTi-1 series)."""
320  self._ensure_config_state()
321  data = struct.pack('!II', set_flags, clear_flags)
322  self.write_ack(MID.SetOptionFlags, data)
323 
324  def GetLocationID(self):
325  """Get the location ID of the device."""
326  self._ensure_config_state()
327  data = self.write_ack(MID.SetLocationID)
328  location_id, = struct.unpack('!H', data)
329  return location_id
330 
331  def SetLocationID(self, location_id):
332  """Set the location ID of the device (arbitrary)."""
333  self._ensure_config_state()
334  data = struct.pack('!H', location_id)
335  self.write_ack(MID.SetLocationID, data)
336 
338  """Restore MT device configuration to factory defaults (soft version).
339  """
340  self._ensure_config_state()
341  self.write_ack(MID.RestoreFactoryDef)
342 
343  def GetTransmitDelay(self):
344  """Get the transmission delay (only RS485)."""
345  self._ensure_config_state()
346  data = self.write_ack(MID.SetTransmitDelay)
347  transmit_delay, = struct.unpack('!H', data)
348  return transmit_delay
349 
350  def SetTransmitDelay(self, transmit_delay):
351  """Set the transmission delay (only RS485)."""
352  self._ensure_config_state()
353  data = struct.pack('!H', transmit_delay)
354  self.write_ack(MID.SetTransmitDelay, data)
355 
356  def GetSyncSettings(self):
357  """Get the synchronisation settings."""
358  self._ensure_config_state()
359  data = self.write_ack(MID.SetSyncSettings)
360  sync_settings = [struct.unpack('!BBBBHHHH', data[o:o+12])
361  for o in range(0, len(data), 12)]
362  return sync_settings
363 
364  def SetSyncSettings(self, sync_settings):
365  """Set the synchronisation settings (mark IV)"""
366  self._ensure_config_state()
367  data = b''.join(struct.pack('!BBBBHHHH', *sync_setting)
368  for sync_setting in sync_settings)
369  self.write_ack(MID.SetSyncSettings, data)
370 
371  def GetConfiguration(self):
372  """Ask for the current configuration of the MT device."""
373  self._ensure_config_state()
374  config = self.write_ack(MID.ReqConfiguration)
375  try:
376  masterID, period, skipfactor, _, _, _, date, time, num, deviceID,\
377  length, mode, settings =\
378  struct.unpack('!IHHHHI8s8s32x32xHIHHI8x', config)
379  except struct.error:
380  raise MTException("could not parse configuration.")
381  self.mode = mode
382  self.settings = settings
383  self.length = length
384  if self.length <= 254:
385  self.header = b'\xFA\xFF\x32' + struct.pack('!B', self.length)
386  else:
387  self.header = b'\xFA\xFF\x32\xFF' + struct.pack('!H', self.length)
388  conf = {'output-mode': mode,
389  'output-settings': settings,
390  'length': length,
391  'period': period,
392  'skipfactor': skipfactor,
393  'Master device ID': masterID,
394  'date': date,
395  'time': time,
396  'number of devices': num,
397  'device ID': deviceID}
398  return conf
399 
401  """Get the output configuration of the device (mark IV)."""
402  self._ensure_config_state()
403  data = self.write_ack(MID.SetOutputConfiguration)
404  output_configuration = [struct.unpack('!HH', data[o:o+4])
405  for o in range(0, len(data), 4)]
406  return output_configuration
407 
408  def SetOutputConfiguration(self, output_configuration):
409  """Set the output configuration of the device (mark IV)."""
410  self._ensure_config_state()
411  data = b''.join(struct.pack('!HH', *output)
412  for output in output_configuration)
413  self.write_ack(MID.SetOutputConfiguration, data)
414 
416  """Get the NMEA data output configuration."""
417  self._ensure_config_state()
418  data = self.write_ack(MID.SetStringOutputType)
419  string_output_type, = struct.unpack('!H', data)
420  return string_output_type
421 
422  def SetStringOutputType(self, string_output_type):
423  """Set the configuration of the NMEA data output."""
424  self._ensure_config_state()
425  data = struct.pack('!H', string_output_type)
426  self.write_ack(MID.SetStringOutputType, data)
427 
428  def GetPeriod(self):
429  """Get the sampling period."""
430  self._ensure_config_state()
431  data = self.write_ack(MID.SetPeriod)
432  period, = struct.unpack('!H', data)
433  return period
434 
435  def SetPeriod(self, period):
436  """Set the sampling period."""
437  self._ensure_config_state()
438  data = struct.pack('!H', period)
439  self.write_ack(MID.SetPeriod, data)
440 
441  def GetAlignmentRotation(self, parameter):
442  """Get the object alignment.
443 
444  parameter indicates the desired alignment quaternion:
445  0 for sensor alignment (RotSensor),
446  1 for local alignment (RotLocal).
447  """
448  self._ensure_config_state()
449  data = struct.pack('!B', parameter)
450  data = self.write_ack(MID.SetAlignmentRotation, data)
451  if len(data) == 16: # fix for older firmwares
452  q0, q1, q2, q3 = struct.unpack('!ffff', data)
453  return parameter, (q0, q1, q2, q3)
454  elif len(data) == 17:
455  param, q0, q1, q2, q3 = struct.unpack('!Bffff', data)
456  return param, (q0, q1, q2, q3)
457  else:
458  raise MTException('Could not parse ReqAlignmentRotationAck message:'
459  ' wrong size of message (%d instead of either 16 '
460  'or 17).' % len(data))
461 
462  def SetAlignmentRotation(self, parameter, quaternion):
463  """Set the object alignment.
464 
465  parameter indicates the desired alignment quaternion:
466  0 for sensor alignment (RotSensor),
467  1 for local alignment (RotLocal).
468  """
469  self._ensure_config_state()
470  data = struct.pack('!Bffff', parameter, *quaternion)
471  self.write_ack(MID.SetAlignmentRotation, data)
472 
473  def GetOutputMode(self):
474  """Get current output mode."""
475  self._ensure_config_state()
476  data = self.write_ack(MID.SetOutputMode)
477  self.mode, = struct.unpack('!H', data)
478  return self.mode
479 
480  def SetOutputMode(self, mode):
481  """Select which information to output."""
482  self._ensure_config_state()
483  data = struct.pack('!H', mode)
484  self.write_ack(MID.SetOutputMode, data)
485  self.mode = mode
486 
487  def GetExtOutputMode(self):
488  """Get current extended output mode (for alternative UART)."""
489  self._ensure_config_state()
490  data = self.write_ack(MID.SetExtOutputMode)
491  ext_mode, = struct.unpack('!H', data)
492  return ext_mode
493 
494  def SetExtOutputMode(self, ext_mode):
495  """Set extended output mode (for alternative UART)."""
496  self._ensure_config_state()
497  data = struct.pack('!H', ext_mode)
498  self.write_ack(MID.SetExtOutputMode, data)
499 
500  def GetOutputSettings(self):
501  """Get current output mode."""
502  self._ensure_config_state()
503  data = self.write_ack(MID.SetOutputSettings)
504  self.settings, = struct.unpack('!I', data)
505  return self.settings
506 
507  def SetOutputSettings(self, settings):
508  """Select how to output the information."""
509  self._ensure_config_state()
510  data = struct.pack('!I', settings)
511  self.write_ack(MID.SetOutputSettings, data)
512  self.settings = settings
513 
514  def SetOutputSkipFactor(self, skipfactor): # deprecated
515  """Set the output skip factor."""
516  self._ensure_config_state()
517  data = struct.pack('!H', skipfactor)
518  self.write_ack(DeprecatedMID.SetOutputSkipFactor, data)
519 
520  def ReqDataLength(self): # deprecated
521  """Get data length for mark III devices."""
522  self._ensure_config_state()
523  try:
524  data = self.write_ack(DeprecatedMID.ReqDataLength)
525  except MTErrorMessage as e:
526  if e.code == 0x04:
527  sys.stderr.write("ReqDataLength message is deprecated and not "
528  "recognised by your device.")
529  return
530  raise e
531  self.length, = struct.unpack('!H', data)
532  if self.length <= 254:
533  self.header = b'\xFA\xFF\x32' + struct.pack('!B', self.length)
534  else:
535  self.header = b'\xFA\xFF\x32\xFF' + struct.pack('!H', self.length)
536  return self.length
537 
538  def GetLatLonAlt(self):
539  """Get the stored position of the device.
540  It is used internally for local magnetic declination and local gravity.
541  """
542  self._ensure_config_state()
543  data = self.write_ack(MID.SetLatLonAlt)
544  if len(data) == 24:
545  lat, lon, alt = struct.unpack('!ddd', data)
546  elif len(data) == 12:
547  lat, lon, alt = struct.unpack('!fff', data)
548  else:
549  raise MTException('Could not parse ReqLatLonAltAck message: wrong'
550  'size of message.')
551  return (lat, lon, alt)
552 
553  def SetLatLonAlt(self, lat, lon, alt):
554  """Set the position of the device.
555  It is used internally for local magnetic declination and local gravity.
556  """
557  self._ensure_config_state()
558  data = struct.pack('!ddd', lat, lon, alt)
559  self.write_ack(MID.SetLatLonAlt, data)
560 
562  """Get the available XKF scenarios on the device."""
563  self._ensure_config_state()
564  data = self.write_ack(MID.ReqAvailableScenarios)
565  scenarios = []
566  try:
567  for i in range(len(data)//22):
568  scenario_type, version, label =\
569  struct.unpack('!BB20s', data[22*i:22*(i+1)])
570  scenarios.append((scenario_type, version, label.strip()))
571  # available XKF scenarios
572  self.scenarios = scenarios
573  except struct.error:
574  raise MTException("could not parse the available XKF scenarios.")
575  return scenarios
576 
578  """Get the ID of the currently used XKF scenario."""
579  self._ensure_config_state()
580  data = self.write_ack(MID.SetCurrentScenario)
581  _, self.scenario_id = struct.unpack('!BB', data) # version, id
582  return self.scenario_id
583 
584  def SetCurrentScenario(self, scenario_id):
585  """Set the XKF scenario to use."""
586  self._ensure_config_state()
587  data = struct.pack('!BB', 0, scenario_id) # version, id
588  self.write_ack(MID.SetCurrentScenario, data)
589 
590  # New names in mk5
591  GetAvailableFilterProfiles = GetAvailableScenarios
592  GetFilterProfile = GetCurrentScenario
593  SetFilterProfile = SetCurrentScenario
594 
595  def GetGnssPlatform(self):
596  """Get the current GNSS navigation filter settings."""
597  self._ensure_config_state()
598  data = self.write_ack(MID.SetGnssPlatform)
599  platform, = struct.unpack('!H', data)
600  return platform
601 
602  def SetGnssPlatform(self, platform):
603  """Set the GNSS navigation filter settings."""
604  self._ensure_config_state()
605  data = struct.pack('!H', platform)
606  self.write_ack(MID.SetGnssPlatform, data)
607 
608  def ResetOrientation(self, code):
609  """Reset the orientation.
610 
611  Code can take several values:
612  0x0000: store current settings (only in config mode),
613  0x0001: heading reset (NOT supported by MTi-G),
614  0x0003: object reset.
615  """
616  data = struct.pack('!H', code)
617  self.write_ack(MID.ResetOrientation, data)
618 
619  def SetNoRotation(self, duration):
620  """Initiate the "no rotation" procedure to estimate gyro biases."""
622  data = struct.pack('!H', duration)
623  self.write_ack(MID.SetNoRotation, data)
624 
625  def GetUTCTime(self):
626  """Get UTC time from device."""
627  self._ensure_config_state()
628  data = self.write_ack(MID.SetUTCTime)
629  ns, year, month, day, hour, minute, second, flag = \
630  struct.unpack('!IHBBBBBB', data)
631  return (ns, year, month, day, hour, minute, second, flag)
632 
633  def SetUTCTime(self, ns, year, month, day, hour, minute, second, flag):
634  """Set UTC time on the device."""
635  self._ensure_config_state()
636  data = struct.pack('!IHBBBBBB', ns, year, month, day, hour, minute,
637  second, flag) # no clue what setting flag can mean
638  self.write_ack(MID.SetUTCTime, data)
639 
640  def AdjustUTCTime(self, ticks):
641  """Adjust UTC Time of device using correction ticks (0.1 ms)."""
642  self._ensure_config_state()
643  data = struct.pack('!i', ticks)
644  self.write(MID.AdjustUTCTime, data) # no ack mentioned in the doc
645 
646  def IccCommand(self, command):
647  """Command of In-run Compass Calibration (ICC)."""
648  if command not in (0, 1, 2, 3):
649  raise MTException("unknown ICC command 0x%02X" % command)
650  cmd_data = struct.pack('!B', command)
651  res_data = self.write_ack(MID.IccCommand, cmd_data)
652  cmd_ack = struct.unpack('!B', res_data[:1])
653  payload = res_data[1:]
654  if cmd_ack != command:
655  raise MTException("expected ack of command 0x%02X; got 0x%02X "
656  "instead" % (command, cmd_ack))
657  if cmd_ack == 0:
658  return
659  elif cmd_ack == 1:
660  ddt_value, dimension, status = struct.unpack('!fBB', payload)
661  return ddt_value, dimension, status
662  elif cmd_ack == 2:
663  return
664  elif cmd_ack == 3:
665  state = struct.unpack('!B', payload)
666  return state
667 
668 
671  def configure_legacy(self, mode, settings, period=None, skipfactor=None):
672  """Configure the mode and settings of the MT device in legacy mode."""
673  try:
674  # switch mark IV devices to legacy mode
675  self.SetOutputConfiguration([(0x0000, 0)])
676  except MTErrorMessage as e:
677  if e.code == 0x04:
678  # mark III device
679  pass
680  else:
681  raise
682  except MTException as e:
683  if self.verbose:
684  print("no ack received while switching from MTData2 to MTData.")
685  pass # no ack???
686  self.SetOutputMode(mode)
687  self.SetOutputSettings(settings)
688  if period is not None:
689  self.SetPeriod(period)
690  if skipfactor is not None:
691  self.SetOutputSkipFactor(skipfactor)
692  self.GetConfiguration()
693 
695  """Read configuration from device in legacy mode."""
696  self.GetConfiguration()
697  return self.mode, self.settings, self.length
698 
699  def read_measurement(self, mode=None, settings=None):
701  # getting data
702  # data = self.read_data_msg()
703  mid, data = self.read_msg()
704  if mid == MID.MTData:
705  return self.parse_MTData(data, mode, settings)
706  elif mid == MID.MTData2:
707  return self.parse_MTData2(data)
708  else:
709  raise MTException("unknown data message: mid=0x%02X (%s)." %
710  (mid, getMIDName(mid)))
711 
712  def parse_MTData2(self, data):
713  # Functions to parse each type of packet
714  def parse_temperature(data_id, content, ffmt):
715  o = {}
716  if (data_id & 0x00F0) == 0x10: # Temperature
717  o['Temp'], = struct.unpack('!'+ffmt, content)
718  else:
719  raise MTException("unknown packet: 0x%04X." % data_id)
720  return o
721 
722  def parse_timestamp(data_id, content, ffmt):
723  o = {}
724  if (data_id & 0x00F0) == 0x10: # UTC Time
725  o['ns'], o['Year'], o['Month'], o['Day'], o['Hour'],\
726  o['Minute'], o['Second'], o['Flags'] =\
727  struct.unpack('!LHBBBBBB', content)
728  elif (data_id & 0x00F0) == 0x20: # Packet Counter
729  o['PacketCounter'], = struct.unpack('!H', content)
730  elif (data_id & 0x00F0) == 0x30: # Integer Time of Week
731  o['TimeOfWeek'], = struct.unpack('!L', content)
732  elif (data_id & 0x00F0) == 0x40: # GPS Age # deprecated
733  o['gpsAge'], = struct.unpack('!B', content)
734  elif (data_id & 0x00F0) == 0x50: # Pressure Age # deprecated
735  o['pressureAge'], = struct.unpack('!B', content)
736  elif (data_id & 0x00F0) == 0x60: # Sample Time Fine
737  o['SampleTimeFine'], = struct.unpack('!L', content)
738  elif (data_id & 0x00F0) == 0x70: # Sample Time Coarse
739  o['SampleTimeCoarse'], = struct.unpack('!L', content)
740  elif (data_id & 0x00F0) == 0x80: # Frame Range
741  o['startFrame'], o['endFrame'] = struct.unpack('!HH', content)
742  else:
743  raise MTException("unknown packet: 0x%04X." % data_id)
744  return o
745 
746  def parse_orientation_data(data_id, content, ffmt):
747  o = {}
748  if (data_id & 0x000C) == 0x00: # ENU
749  o['frame'] = 'ENU'
750  elif (data_id & 0x000C) == 0x04: # NED
751  o['frame'] = 'NED'
752  elif (data_id & 0x000C) == 0x08: # NWU
753  o['frame'] = 'NWU'
754  if (data_id & 0x00F0) == 0x10: # Quaternion
755  o['Q0'], o['Q1'], o['Q2'], o['Q3'] = struct.unpack('!'+4*ffmt,
756  content)
757  elif (data_id & 0x00F0) == 0x20: # Rotation Matrix
758  o['a'], o['b'], o['c'], o['d'], o['e'], o['f'], o['g'],\
759  o['h'], o['i'] = struct.unpack('!'+9*ffmt, content)
760  elif (data_id & 0x00F0) == 0x30: # Euler Angles
761  o['Roll'], o['Pitch'], o['Yaw'] = struct.unpack('!'+3*ffmt,
762  content)
763  else:
764  raise MTException("unknown packet: 0x%04X." % data_id)
765  return o
766 
767  def parse_pressure(data_id, content, ffmt):
768  o = {}
769  if (data_id & 0x00F0) == 0x10: # Baro pressure
770  o['Pressure'], = struct.unpack('!L', content)
771  else:
772  raise MTException("unknown packet: 0x%04X." % data_id)
773  return o
774 
775  def parse_acceleration(data_id, content, ffmt):
776  o = {}
777  if (data_id & 0x000C) == 0x00: # ENU
778  o['frame'] = 'ENU'
779  elif (data_id & 0x000C) == 0x04: # NED
780  o['frame'] = 'NED'
781  elif (data_id & 0x000C) == 0x08: # NWU
782  o['frame'] = 'NWU'
783  if (data_id & 0x00F0) == 0x10: # Delta V
784  o['Delta v.x'], o['Delta v.y'], o['Delta v.z'] = \
785  struct.unpack('!'+3*ffmt, content)
786  elif (data_id & 0x00F0) == 0x20: # Acceleration
787  o['accX'], o['accY'], o['accZ'] = \
788  struct.unpack('!'+3*ffmt, content)
789  elif (data_id & 0x00F0) == 0x30: # Free Acceleration
790  o['freeAccX'], o['freeAccY'], o['freeAccZ'] = \
791  struct.unpack('!'+3*ffmt, content)
792  elif (data_id & 0x00F0) == 0x40: # AccelerationHR
793  o['accX'], o['accY'], o['accZ'] = \
794  struct.unpack('!'+3*ffmt, content)
795  else:
796  raise MTException("unknown packet: 0x%04X." % data_id)
797  return o
798 
799  def parse_position(data_id, content, ffmt):
800  o = {}
801  if (data_id & 0x000C) == 0x00: # ENU
802  o['frame'] = 'ENU'
803  elif (data_id & 0x000C) == 0x04: # NED
804  o['frame'] = 'NED'
805  elif (data_id & 0x000C) == 0x08: # NWU
806  o['frame'] = 'NWU'
807  if (data_id & 0x00F0) == 0x10: # Altitude MSL # deprecated
808  o['altMsl'], = struct.unpack('!'+ffmt, content)
809  elif (data_id & 0x00F0) == 0x20: # Altitude Ellipsoid
810  o['altEllipsoid'], = struct.unpack('!'+ffmt, content)
811  elif (data_id & 0x00F0) == 0x30: # Position ECEF
812  o['ecefX'], o['ecefY'], o['ecefZ'] = \
813  struct.unpack('!'+3*ffmt, content)
814  elif (data_id & 0x00F0) == 0x40: # LatLon
815  o['lat'], o['lon'] = struct.unpack('!'+2*ffmt, content)
816  else:
817  raise MTException("unknown packet: 0x%04X." % data_id)
818  return o
819 
820  def parse_GNSS(data_id, content, ffmt):
821  o = {}
822  if (data_id & 0x00F0) == 0x10: # GNSS PVT data
823  o['itow'], o['year'], o['month'], o['day'], o['hour'],\
824  o['min'], o['sec'], o['valid'], o['tAcc'], o['nano'],\
825  o['fixtype'], o['flags'], o['numSV'], o['lon'], o['lat'],\
826  o['height'], o['hMSL'], o['hAcc'], o['vAcc'], o['velN'],\
827  o['velE'], o['velD'], o['gSpeed'], o['headMot'],\
828  o['sAcc'], o['headAcc'], o['headVeh'], o['gdop'],\
829  o['pdop'], o['tdop'], o['vdop'], o['hdop'], o['ndop'],\
830  o['edop'] =\
831  struct.unpack('!IHBBBBBBIiBBBxiiiiIIiiiiiIIiHHHHHHH',
832  content)
833  # scaling correction
834  o['lon'] *= 1e-7
835  o['lat'] *= 1e-7
836  o['headMot'] *= 1e-5
837  o['headVeh'] *= 1e-5
838  o['gdop'] *= 0.01
839  o['pdop'] *= 0.01
840  o['tdop'] *= 0.01
841  o['vdop'] *= 0.01
842  o['hdop'] *= 0.01
843  o['ndop'] *= 0.01
844  o['edop'] *= 0.01
845  elif (data_id & 0x00F0) == 0x20: # GNSS satellites info
846  o['iTOW'], o['numSvs'] = struct.unpack('!LBxxx', content[:8])
847  svs = []
848  ch = {}
849  for i in range(o['numSvs']):
850  ch['gnssId'], ch['svId'], ch['cno'], ch['flags'] = \
851  struct.unpack('!BBBB', content[8+4*i:12+4*i])
852  svs.append(ch)
853  o['svs'] = svs
854  else:
855  raise MTException("unknown packet: 0x%04X." % data_id)
856  return o
857 
858  def parse_angular_velocity(data_id, content, ffmt):
859  o = {}
860  if (data_id & 0x000C) == 0x00: # ENU
861  o['frame'] = 'ENU'
862  elif (data_id & 0x000C) == 0x04: # NED
863  o['frame'] = 'NED'
864  elif (data_id & 0x000C) == 0x08: # NWU
865  o['frame'] = 'NWU'
866  if (data_id & 0x00F0) == 0x20: # Rate of Turn
867  o['gyrX'], o['gyrY'], o['gyrZ'] = \
868  struct.unpack('!'+3*ffmt, content)
869  elif (data_id & 0x00F0) == 0x30: # Delta Q
870  o['Delta q0'], o['Delta q1'], o['Delta q2'], o['Delta q3'] = \
871  struct.unpack('!'+4*ffmt, content)
872  elif (data_id & 0x00F0) == 0x40: # RateOfTurnHR
873  o['gyrX'], o['gyrY'], o['gyrZ'] = \
874  struct.unpack('!'+3*ffmt, content)
875  else:
876  raise MTException("unknown packet: 0x%04X." % data_id)
877  return o
878 
879  def parse_GPS(data_id, content, ffmt):
880  o = {}
881  if (data_id & 0x00F0) == 0x30: # DOP
882  o['iTOW'], g, p, t, v, h, n, e = \
883  struct.unpack('!LHHHHHHH', content)
884  o['gDOP'], o['pDOP'], o['tDOP'], o['vDOP'], o['hDOP'], \
885  o['nDOP'], o['eDOP'] = 0.01*g, 0.01*p, 0.01*t, \
886  0.01*v, 0.01*h, 0.01*n, 0.01*e
887  elif (data_id & 0x00F0) == 0x40: # SOL
888  o['iTOW'], o['fTOW'], o['Week'], o['gpsFix'], o['Flags'], \
889  o['ecefX'], o['ecefY'], o['ecefZ'], o['pAcc'], \
890  o['ecefVX'], o['ecefVY'], o['ecefVZ'], o['sAcc'], \
891  o['pDOP'], o['numSV'] = \
892  struct.unpack('!LlhBBlllLlllLHxBx', content)
893  # scaling correction
894  o['pDOP'] *= 0.01
895  elif (data_id & 0x00F0) == 0x80: # Time UTC
896  o['iTOW'], o['tAcc'], o['nano'], o['year'], o['month'], \
897  o['day'], o['hour'], o['min'], o['sec'], o['valid'] = \
898  struct.unpack('!LLlHBBBBBB', content)
899  elif (data_id & 0x00F0) == 0xA0: # SV Info
900  o['iTOW'], o['numCh'] = struct.unpack('!LBxxx', content[:8])
901  channels = []
902  ch = {}
903  for i in range(o['numCh']):
904  ch['chn'], ch['svid'], ch['flags'], ch['quality'], \
905  ch['cno'], ch['elev'], ch['azim'], ch['prRes'] = \
906  struct.unpack('!BBBBBbhl', content[8+12*i:20+12*i])
907  channels.append(ch)
908  o['channels'] = channels
909  else:
910  raise MTException("unknown packet: 0x%04X." % data_id)
911  return o
912 
913  def parse_SCR(data_id, content, ffmt):
914  o = {}
915  if (data_id & 0x00F0) == 0x10: # ACC+GYR+MAG+Temperature
916  o['accX'], o['accY'], o['accZ'], o['gyrX'], o['gyrY'], \
917  o['gyrZ'], o['magX'], o['magY'], o['magZ'], o['Temp'] = \
918  struct.unpack("!9Hh", content)
919  elif (data_id & 0x00F0) == 0x20: # Gyro Temperature
920  o['tempGyrX'], o['tempGyrY'], o['tempGyrZ'] = \
921  struct.unpack("!hhh", content)
922  else:
923  raise MTException("unknown packet: 0x%04X." % data_id)
924  return o
925 
926  def parse_analog_in(data_id, content, ffmt): # deprecated
927  o = {}
928  if (data_id & 0x00F0) == 0x10: # Analog In 1
929  o['analogIn1'], = struct.unpack("!H", content)
930  elif (data_id & 0x00F0) == 0x20: # Analog In 2
931  o['analogIn2'], = struct.unpack("!H", content)
932  else:
933  raise MTException("unknown packet: 0x%04X." % data_id)
934  return o
935 
936  def parse_magnetic(data_id, content, ffmt):
937  o = {}
938  if (data_id & 0x000C) == 0x00: # ENU
939  o['frame'] = 'ENU'
940  elif (data_id & 0x000C) == 0x04: # NED
941  o['frame'] = 'NED'
942  elif (data_id & 0x000C) == 0x08: # NWU
943  o['frame'] = 'NWU'
944  if (data_id & 0x00F0) == 0x20: # Magnetic Field
945  o['magX'], o['magY'], o['magZ'] = \
946  struct.unpack("!3"+ffmt, content)
947  else:
948  raise MTException("unknown packet: 0x%04X." % data_id)
949  return o
950 
951  def parse_velocity(data_id, content, ffmt):
952  o = {}
953  if (data_id & 0x000C) == 0x00: # ENU
954  o['frame'] = 'ENU'
955  elif (data_id & 0x000C) == 0x04: # NED
956  o['frame'] = 'NED'
957  elif (data_id & 0x000C) == 0x08: # NWU
958  o['frame'] = 'NWU'
959  if (data_id & 0x00F0) == 0x10: # Velocity XYZ
960  o['velX'], o['velY'], o['velZ'] = \
961  struct.unpack("!3"+ffmt, content)
962  else:
963  raise MTException("unknown packet: 0x%04X." % data_id)
964  return o
965 
966  def parse_status(data_id, content, ffmt):
967  o = {}
968  if (data_id & 0x00F0) == 0x10: # Status Byte
969  o['StatusByte'], = struct.unpack("!B", content)
970  elif (data_id & 0x00F0) == 0x20: # Status Word
971  o['StatusWord'], = struct.unpack("!L", content)
972  elif (data_id & 0x00F0) == 0x40: # RSSI # deprecated
973  o['RSSI'], = struct.unpack("!b", content)
974  else:
975  raise MTException("unknown packet: 0x%04X." % data_id)
976  return o
977 
978  # data object
979  output = {}
980  while len(data) > 0:
981  try:
982  data_id, size = struct.unpack('!HB', data[:3])
983  if (data_id & 0x0003) == 0x3:
984  float_format = 'd'
985  elif (data_id & 0x0003) == 0x0:
986  float_format = 'f'
987  else:
988  raise MTException("fixed point precision not supported.")
989  content = data[3:3+size]
990  data = data[3+size:]
991  group = data_id & 0xF800
992  ffmt = float_format
993  if group == XDIGroup.Temperature:
994  output.setdefault('Temperature', {}).update(
995  parse_temperature(data_id, content, ffmt))
996  elif group == XDIGroup.Timestamp:
997  output.setdefault('Timestamp', {}).update(
998  parse_timestamp(data_id, content, ffmt))
999  elif group == XDIGroup.OrientationData:
1000  output.setdefault('Orientation Data', {}).update(
1001  parse_orientation_data(data_id, content, ffmt))
1002  elif group == XDIGroup.Pressure:
1003  output.setdefault('Pressure', {}).update(
1004  parse_pressure(data_id, content, ffmt))
1005  elif group == XDIGroup.Acceleration:
1006  output.setdefault('Acceleration', {}).update(
1007  parse_acceleration(data_id, content, ffmt))
1008  elif group == XDIGroup.Position:
1009  output.setdefault('Position', {}).update(
1010  parse_position(data_id, content, ffmt))
1011  elif group == XDIGroup.GNSS:
1012  output.setdefault('GNSS', {}).update(
1013  parse_GNSS(data_id, content, ffmt))
1014  elif group == XDIGroup.AngularVelocity:
1015  output.setdefault('Angular Velocity', {}).update(
1016  parse_angular_velocity(data_id, content, ffmt))
1017  elif group == XDIGroup.GPS:
1018  output.setdefault('GPS', {}).update(
1019  parse_GPS(data_id, content, ffmt))
1020  elif group == XDIGroup.SensorComponentReadout:
1021  output.setdefault('SCR', {}).update(
1022  parse_SCR(data_id, content, ffmt))
1023  elif group == XDIGroup.AnalogIn: # deprecated
1024  output.setdefault('Analog In', {}).update(
1025  parse_analog_in(data_id, content, ffmt))
1026  elif group == XDIGroup.Magnetic:
1027  output.setdefault('Magnetic', {}).update(
1028  parse_magnetic(data_id, content, ffmt))
1029  elif group == XDIGroup.Velocity:
1030  output.setdefault('Velocity', {}).update(
1031  parse_velocity(data_id, content, ffmt))
1032  elif group == XDIGroup.Status:
1033  output.setdefault('Status', {}).update(
1034  parse_status(data_id, content, ffmt))
1035  else:
1036  raise MTException("unknown XDI group: 0x%04X." % group)
1037  except struct.error:
1038  raise MTException("couldn't parse MTData2 message (data_id: "
1039  "0x%04X, size: %d)." % (data_id, size))
1040  return output
1041 
1042  def parse_MTData(self, data, mode=None, settings=None):
1043  """Read and parse a legacy measurement packet."""
1044  # getting mode
1045  if mode is None:
1046  mode = self.mode
1047  if settings is None:
1048  settings = self.settings
1049  # data object
1050  output = {}
1051  try:
1052  # raw IMU first
1053  if mode & OutputMode.RAW:
1054  o = {}
1055  o['accX'], o['accY'], o['accZ'], o['gyrX'], o['gyrY'], \
1056  o['gyrZ'], o['magX'], o['magY'], o['magZ'], o['temp'] =\
1057  struct.unpack('!10H', data[:20])
1058  data = data[20:]
1059  output['RAW'] = o
1060  # raw GPS second
1061  if mode & OutputMode.RAWGPS:
1062  o = {}
1063  o['Press'], o['bPrs'], o['ITOW'], o['LAT'], o['LON'],\
1064  o['ALT'], o['VEL_N'], o['VEL_E'], o['VEL_D'], o['Hacc'],\
1065  o['Vacc'], o['Sacc'], o['bGPS'] =\
1066  struct.unpack('!HBI6i3IB', data[:44])
1067  data = data[44:]
1068  output['RAWGPS'] = o
1069  # temperature
1070  if mode & OutputMode.Temp:
1071  temp, = struct.unpack('!f', data[:4])
1072  data = data[4:]
1073  output['Temp'] = temp
1074  # calibrated data
1075  if mode & OutputMode.Calib:
1076  o = {}
1077  if (settings & OutputSettings.Coordinates_NED):
1078  o['frame'] = 'NED'
1079  else:
1080  o['frame'] = 'ENU'
1081  if not (settings & OutputSettings.CalibMode_GyrMag):
1082  o['accX'], o['accY'], o['accZ'] = struct.unpack('!3f',
1083  data[:12])
1084  data = data[12:]
1085  if not (settings & OutputSettings.CalibMode_AccMag):
1086  o['gyrX'], o['gyrY'], o['gyrZ'] = struct.unpack('!3f',
1087  data[:12])
1088  data = data[12:]
1089  if not (settings & OutputSettings.CalibMode_AccGyr):
1090  o['magX'], o['magY'], o['magZ'] = struct.unpack('!3f',
1091  data[:12])
1092  data = data[12:]
1093  output['Calib'] = o
1094  # orientation
1095  if mode & OutputMode.Orient:
1096  o = {}
1097  if (settings & OutputSettings.Coordinates_NED):
1098  o['frame'] = 'NED'
1099  else:
1100  o['frame'] = 'ENU'
1101  if settings & OutputSettings.OrientMode_Euler:
1102  o['roll'], o['pitch'], o['yaw'] = struct.unpack('!3f',
1103  data[:12])
1104  data = data[12:]
1105  elif settings & OutputSettings.OrientMode_Matrix:
1106  a, b, c, d, e, f, g, h, i = struct.unpack('!9f',
1107  data[:36])
1108  data = data[36:]
1109  o['matrix'] = ((a, b, c), (d, e, f), (g, h, i))
1110  else: # OutputSettings.OrientMode_Quaternion:
1111  q0, q1, q2, q3 = struct.unpack('!4f', data[:16])
1112  data = data[16:]
1113  o['quaternion'] = (q0, q1, q2, q3)
1114  output['Orient'] = o
1115  # auxiliary
1116  if mode & OutputMode.Auxiliary:
1117  o = {}
1118  if not (settings & OutputSettings.AuxiliaryMode_NoAIN1):
1119  o['Ain_1'], = struct.unpack('!H', data[:2])
1120  data = data[2:]
1121  if not (settings & OutputSettings.AuxiliaryMode_NoAIN2):
1122  o['Ain_2'], = struct.unpack('!H', data[:2])
1123  data = data[2:]
1124  output['Auxiliary'] = o
1125  # position
1126  if mode & OutputMode.Position:
1127  o = {}
1128  o['Lat'], o['Lon'], o['Alt'] = struct.unpack('!3f', data[:12])
1129  data = data[12:]
1130  output['Pos'] = o
1131  # velocity
1132  if mode & OutputMode.Velocity:
1133  o = {}
1134  if (settings & OutputSettings.Coordinates_NED):
1135  o['frame'] = 'NED'
1136  else:
1137  o['frame'] = 'ENU'
1138  o['Vel_X'], o['Vel_Y'], o['Vel_Z'] = struct.unpack('!3f',
1139  data[:12])
1140  data = data[12:]
1141  output['Vel'] = o
1142  # status
1143  if mode & OutputMode.Status:
1144  status, = struct.unpack('!B', data[:1])
1145  data = data[1:]
1146  output['Stat'] = status
1147  # sample counter
1148  if settings & OutputSettings.Timestamp_SampleCnt:
1149  TS, = struct.unpack('!H', data[:2])
1150  data = data[2:]
1151  output['Sample'] = TS
1152  # UTC time
1153  if settings & OutputSettings.Timestamp_UTCTime:
1154  o = {}
1155  o['ns'], o['Year'], o['Month'], o['Day'], o['Hour'],\
1156  o['Minute'], o['Second'], o['Flags'] = struct.unpack(
1157  '!ihbbbbb', data[:12])
1158  data = data[12:]
1159  output['Timestamp'] = o
1160  # TODO at that point data should be empty
1161  except struct.error as e:
1162  raise MTException("could not parse MTData message.")
1163  if len(data) > 0:
1164  raise MTException("could not parse MTData message (too long).")
1165  return output
1166 
1167  def ChangeBaudrate(self, baudrate):
1168  """Change the baudrate, reset the device and reopen communication."""
1169  brid = Baudrates.get_BRID(baudrate)
1170  self.SetBaudrate(brid)
1171  self.Reset()
1172  # self.device.flush()
1173  self.device.baudrate = baudrate
1174  # self.device.flush()
1175  time.sleep(0.01)
1176  self.read_msg()
1177  self.write_msg(MID.WakeUpAck)
1178 
1179 
1180 
1183 def find_devices(timeout=0.002, verbose=False, initial_wait=0.1):
1184  mtdev_list = []
1185  for port in glob.glob("/dev/tty*S*"):
1186  if verbose:
1187  print("Trying '%s'" % port)
1188  try:
1189  br = find_baudrate(port, timeout, verbose, initial_wait)
1190  if br:
1191  mtdev_list.append((port, br))
1192  except MTException:
1193  pass
1194  return mtdev_list
1195 
1196 
1197 
1200 def find_baudrate(port, timeout=0.002, verbose=False, initial_wait=0.1):
1201  baudrates = (115200, 460800, 921600, 230400, 57600, 38400, 19200, 9600)
1202  for br in baudrates:
1203  if verbose:
1204  print("Trying %d bd:" % br, end=' ')
1205  sys.stdout.flush()
1206  try:
1207  mt = MTDevice(port, br, timeout=timeout, verbose=verbose,
1208  initial_wait=initial_wait)
1209  except serial.SerialException:
1210  if verbose:
1211  print("fail: unable to open device.")
1212  raise MTException("unable to open %s" % port)
1213  try:
1214  mt.GoToConfig()
1215  mt.GoToMeasurement()
1216  if verbose:
1217  print("ok.")
1218  return br
1219  except MTException:
1220  if verbose:
1221  print("fail.")
def SetStringOutputType(self, string_output_type)
def read_measurement(self, mode=None, settings=None)
def __init__(self, port, baudrate=115200, timeout=0.002, autoconf=True, config_mode=False, verbose=False, initial_wait=0.1)
def parse_MTData(self, data, mode=None, settings=None)
def SetTransmitDelay(self, transmit_delay)
def SetUTCTime(self, ns, year, month, day, hour, minute, second, flag)
def configure_legacy(self, mode, settings, period=None, skipfactor=None)
High-level utility functions.
def SetOutputConfiguration(self, output_configuration)
def write_ack(self, mid, data=b'', n_resend=30, n_read=25)
def find_devices(timeout=0.002, verbose=False, initial_wait=0.1)
def read_data_msg(self, buf=bytearray())
def SetAlignmentRotation(self, parameter, quaternion)
def find_baudrate(port, timeout=0.002, verbose=False, initial_wait=0.1)
Auto detect baudrate.
def SetOptionFlags(self, set_flags, clear_flags)
def SetSyncSettings(self, sync_settings)
def write_msg(self, mid, data=b'')
Low-level communication.
def Reset(self, go_to_config=False)
High-level functions.
def getMIDName(mid)
Definition: mtdef.py:175


xsens_driver
Author(s):
autogenerated on Tue May 2 2023 02:05:55