2 from __future__
import print_function
8 from serial
import SerialException
11 from xsens_driver.mtdef import MTException, MTErrorMessage, MTTimeoutException, OutputMode, OutputSettings
18 print(
"""MT device driver. 20 ./mtdevice.py [commands] [opts] 24 Print this help and quit. 26 Reset device to factory defaults. 27 -a, --change-baudrate=NEW_BAUD 28 Change baudrate from BAUD (see below) to NEW_BAUD. 29 -c, --configure=OUTPUT 30 Configure the device (see OUTPUT description below). 32 Print MTData. It is the default if no other command is supplied. 34 Print current MT device configuration. 36 Change the current XKF scenario. 37 -l, --legacy-configure 38 Configure the device in legacy mode (needs MODE and SETTINGS arguments 42 -y, --synchronization=settings (see below) 43 Configure the synchronization settings of each sync line (see below). 44 -u, --utc-time=time (see below) 45 Set the UTC time buffer of the device. 46 -g, --gnss-platform=platform 47 Change the GNSS navigation filter settings (check the documentation). 48 -o, --option-flags=flags (see below) 50 -j, --icc-command=command (see below) 51 Send command to the In-run Compass Calibration. 55 Serial interface of the device (default: /dev/ttyUSB0). If 'auto', then 56 all serial ports are tested at all baudrates and the first 57 suitable device is used. 59 Baudrate of serial interface (default: 115200). If 0, then all 60 rates are tried until a suitable one is found. 62 Timeout of serial communication in second (default: 0.002). 63 -w, --initial-wait=WAIT 64 Initial wait to allow device to be ready in second (default: 0.1). 68 The format is a sequence of "<group><type><frequency>?<format>?" 70 The frequency and format are optional. 71 The groups and types can be: 72 t temperature (max frequency: 1 Hz): 74 i timestamp (max frequency: 2000 Hz): 77 ii Integer Time of the Week (ITOW) 81 o orientation data (max frequency: 400 Hz): 85 b pressure (max frequency: 50 Hz): 87 a acceleration (max frequency: 2000 Hz (see documentation)): 91 ah acceleration HR (max frequency 1000 Hz) 92 p position (max frequency: 400 Hz): 96 n GNSS (max frequency: 4 Hz): 98 ns GNSS satellites info 99 w angular velocity (max frequency: 2000 Hz (see documentation)): 102 wh rate of turn HR (max frequency 1000 Hz) 103 g GPS (max frequency: 4 Hz): 108 r Sensor Component Readout (max frequency: 2000 Hz): 109 rr ACC, GYR, MAG, temperature 111 m Magnetic (max frequency: 100 Hz): 113 v Velocity (max frequency: 400 Hz): 115 s Status (max frequency: 2000 Hz): 118 Frequency is specified in decimal and is assumed to be the maximum 119 frequency if it is omitted. 120 Format is a combination of the precision for real valued numbers and 123 f single precision floating point number (32-bit) (default) 124 d double precision floating point number (64-bit) 126 e East-North-Up (default) 130 The default configuration for the MTi-1/10/100 IMUs can be 134 "wd2000fe,ad2000fe,mf100fe,ip2000,if2000,sw2000" 135 For getting quaternion orientation in float with sample time: 137 For longitude, latitude, altitude and orientation (on MTi-G-700): 138 "pl400fe,pa400fe,oq400fe" 140 Synchronization settings: 141 The format follows the xsens protocol documentation. All fields are 142 required and separated by commas. 143 Note: The entire synchronization buffer is wiped every time a new one 144 is set, so it is necessary to specify the settings of multiple 146 It also possible to clear the synchronization with the argument "clear" 148 Function (see manual for details): 150 4 Interval Transition Measurement 152 9 ClockBiasEstimation 154 Line (manual for details): 156 1 GPSClockIn (only available for 700/710) 157 2 Input Line (SyncIn) 159 5 ExtTimepulseIn (only available for 700/710) 160 6 Software (only available for SendLatest with ReqData message) 162 1 Positive pulse/ Rising edge 163 2 Negative pulse/ Falling edge 168 Skip First (unsigned_int): 169 Number of initial events to skip before taking actions 170 Skip Factor (unsigned_int): 171 Number of events to skip before taking action again 172 Ignored with ReqData. 173 Pulse Width (unsigned_int): 175 For SyncOut, the width of the generated pulse in 100 microseconds 176 unit. Ignored for Toggle pulses. 178 Delay after receiving a sync pulse to taking action, 179 100 microseconds units, range [0...600000] 181 Reference clock period in milliseconds for ClockBiasEstimation 183 Offset from event to pulse generation. 184 100 microseconds unit, range [-30000...+30000] 187 For changing the sync setting of the SyncIn line to trigger indication 188 with rising edge, one time triggering and no skipping and delay. Enter 192 Note a number is still in the place for pulse width despite it being 195 To set multiple lines at once: 196 ./mtdevice.py -y 3,2,1,0,0,0,0,0 -y 9,0,1,0,0,0,10,0 198 To clear the synchronization settings of MTi 199 ./mtdevice.py -y clear 202 There are two ways to set the UTCtime for the MTi. 203 Option #1: set MTi to the current UTC time based on local system time with 205 Option #2: set MTi to a specified UTC time 206 The time fields are set as follows: 207 year: range [1999,2099] 209 day: day of the month, range [1,31] 210 hour: hour of the day, range [0,23] 211 min: minute of the hour, range [0,59] 212 sec: second of the minute, range [0,59] 213 ns: nanosecond of the second, range [0,1000000000] 215 1: Valid Time of Week 218 Note: the flag is ignored for --utc-time as it is set by the device 219 itself when connected to a GPS 222 Set UTC time for the device: 224 ./mtdevice.py -u 1999,1,1,0,0,0,0,0 226 GNSS platform settings: 227 Only for MTi-G-700/710 with firmware>=1.7. 228 The following two platform settings are listed in the documentation: 231 Check the XSens documentation before changing anything. 234 Several flags can be set or cleared. 235 0x00000001 DisableAutoStore: when set, configuration changes are not saved 236 in non-volatile memory (only MTi-1 series) 237 0x00000002 DisableAutoMeasurement: when set, device will stay in Config 238 Mode upon start up (only MTi-1 series) 239 0x00000004 EnableBeidou: when set, enable Beidou and disable GLONASS (only 241 0x00000010 EnableAHS: enable Active Heading Stabilization (overrides 243 0x00000080 EnableInRunCompassCalibration: doc is unclear 244 The flags provided must be a pair of ored values: the first for flags to be 245 set the second for the flags to be cleared. 247 Only set DisableAutoStore and DisableAutoMeasurement flags: 248 ./mtdevice.py -o 0x03,0x00 249 Disable AHS (clear EnableAHS flag): 250 ./mtdevice.py -o 0x00,0x10 251 Set DisableAutoStore and clear DisableAutoMeasurement: 252 ./mtdevice.py -o 0x02,0x01 254 In-run Compass Calibration commands: 255 The idea of ICC is to record magnetic field data during so-called 256 representative motion in order to better calibrate the magnetometer and 258 Typical usage would be to issue the start command, then move the device 259 for some time then issue the stop command. If parameters are acceptable, 260 these can be stored using the store command. 262 00: Start representative motion 263 01: Stop representative motion; return ddt, dimension, and status. 264 02: Store ICC parameters 265 03: Get representative motion state; return 1 if active 266 Check the documentation for more details. 269 -m, --output-mode=MODE 270 Legacy mode of the device to select the information to output. 271 This is required for 'legacy-configure' command. 272 MODE can be either the mode value in hexadecimal, decimal or 273 binary form, or a string composed of the following characters 275 t temperature, [0x0001] 276 c calibrated data, [0x0002] 277 o orientation data, [0x0004] 278 a auxiliary data, [0x0008] 279 p position data (requires MTi-G), [0x0010] 280 v velocity data (requires MTi-G), [0x0020] 281 s status data, [0x0800] 282 g raw GPS mode (requires MTi-G), [0x1000] 283 r raw (incompatible with others except raw GPS), [0x4000] 284 For example, use "--output-mode=so" to have status and 286 -s, --output-settings=SETTINGS 287 Legacy settings of the device. This is required for 'legacy-configure' 289 SETTINGS can be either the settings value in hexadecimal, 290 decimal or binary form, or a string composed of the following 291 characters (in any order): 292 t sample count (excludes 'n') 293 n no sample count (excludes 't') 295 q orientation in quaternion (excludes 'e' and 'm') 296 e orientation in Euler angles (excludes 'm' and 'q') 297 m orientation in matrix (excludes 'q' and 'e') 298 A acceleration in calibrated data 299 G rate of turn in calibrated data 300 M magnetic field in calibrated data 301 i only analog input 1 (excludes 'j') 302 j only analog input 2 (excludes 'i') 303 N North-East-Down instead of default: X North Z up 304 For example, use "--output-settings=tqMAG" for all calibrated 305 data, sample counter and orientation in quaternion. 307 Sampling period in (1/115200) seconds (default: 1152). 308 Minimum is 225 (1.95 ms, 512 Hz), maximum is 1152 310 Note that for legacy devices it is the period at which sampling occurs, 311 not the period at which messages are sent (see below). 314 -f, --deprecated-skip-factor=SKIPFACTOR 315 Only for mark III devices. 316 Number of samples to skip before sending MTData message 318 The frequency at which MTData message is send is: 319 115200/(PERIOD * (SKIPFACTOR + 1)) 320 If the value is 0xffff, no data is send unless a ReqData request 330 shopts =
'hra:c:eild:b:m:s:p:f:x:vy:u:g:o:j:t:w:' 331 lopts = [
'help',
'reset',
'change-baudrate=',
'configure=',
'echo',
332 'inspect',
'legacy-configure',
'device=',
'baudrate=',
333 'output-mode=',
'output-settings=',
'period=',
334 'deprecated-skip-factor=',
'xkf-scenario=',
'verbose',
335 'synchronization=',
'utc-time=',
'gnss-platform=',
336 'option-flags=',
'icc-command=',
'timeout=',
'initial-wait=']
338 opts, args = getopt.gnu_getopt(sys.argv[1:], shopts, lopts)
339 except getopt.GetoptError
as e:
344 device =
'/dev/ttyUSB0' 360 if o
in (
'-h',
'--help'):
363 elif o
in (
'-r',
'--reset'):
364 actions.append(
'reset')
365 elif o
in (
'-a',
'--change-baudrate'):
367 new_baudrate = int(a)
369 print(
"change-baudrate argument must be integer.")
371 actions.append(
'change-baudrate')
372 elif o
in (
'-c',
'--configure'):
374 if output_config
is None:
376 actions.append(
'configure')
377 elif o
in (
'-e',
'--echo'):
378 actions.append(
'echo')
379 elif o
in (
'-i',
'--inspect'):
380 actions.append(
'inspect')
381 elif o
in (
'-l',
'--legacy-configure'):
382 actions.append(
'legacy-configure')
383 elif o
in (
'-x',
'--xkf-scenario'):
387 print(
"xkf-scenario argument must be integer.")
389 actions.append(
'xkf-scenario')
390 elif o
in (
'-y',
'--synchronization'):
392 if new_sync_settings
is None:
394 sync_settings.append(new_sync_settings)
395 actions.append(
'synchronization')
396 elif o
in (
'-u',
'--setUTCtime'):
398 if UTCtime_settings
is None:
400 actions.append(
'setUTCtime')
401 elif o
in (
'-d',
'--device'):
403 elif o
in (
'-b',
'--baudrate'):
407 print(
"baudrate argument must be integer.")
409 elif o
in (
'-m',
'--output-mode'):
413 elif o
in (
'-s',
'--output-settings'):
417 elif o
in (
'-p',
'--period'):
421 print(
"period argument must be integer.")
423 elif o
in (
'-f',
'--deprecated-skip-factor'):
427 print(
"skip-factor argument must be integer.")
429 elif o
in (
'-v',
'--verbose'):
431 elif o
in (
'-g',
'--gnss-platform'):
435 actions.append(
'gnss-platform')
436 elif o
in (
'-o',
'--option-flags'):
438 if flag_tuple
is None:
440 actions.append(
'option-flags')
441 elif o
in (
'-j',
'--icc-command'):
443 if icc_command
is None:
445 actions.append(
'icc-command')
446 elif o
in (
'-t',
'--timeout'):
450 print(
"timeout argument must be a floating number.")
452 elif o
in (
'-w',
'--initial-wait'):
454 initial_wait = float(a)
456 print(
"initial-wait argument must be a floating number.")
460 if len(actions) == 0:
461 actions.append(
'echo')
465 initial_wait=initial_wait)
467 print(
"Detected devices:",
"".join(
'\n\t%s @ %d' % (d, p)
469 print(
"Using %s @ %d" % devs[0])
470 device, baudrate = devs[0]
472 print(
"No suitable device found.")
476 baudrate =
find_baudrate(device, timeout=timeout, verbose=verbose,
477 initial_wait=initial_wait)
479 print(
"No suitable baudrate found.")
483 mt =
MTDevice(device, baudrate, timeout=timeout, verbose=verbose,
484 initial_wait=initial_wait)
485 except SerialException:
488 if 'inspect' in actions:
490 if 'change-baudrate' in actions:
491 print(
"Changing baudrate from %d to %d:" % (baudrate,
492 new_baudrate), end=
' ')
494 mt.ChangeBaudrate(new_baudrate)
496 if 'reset' in actions:
497 print(
"Restoring factory defaults", end=
' ')
499 mt.RestoreFactoryDefaults()
501 if 'configure' in actions:
502 print(
"Changing output configuration", end=
' ')
504 mt.SetOutputConfiguration(output_config)
506 if 'synchronization' in actions:
507 print(
"Changing synchronization settings", end=
' ')
509 mt.SetSyncSettings(sync_settings)
511 if 'setUTCtime' in actions:
512 print(
"Setting UTC time in the device", end=
' ')
514 mt.SetUTCTime(UTCtime_settings[6],
523 if 'gnss-platform' in actions:
524 print(
"Setting GNSS platform", end=
' ')
526 mt.SetGnssPlatform(platform)
528 if 'option-flags' in actions:
529 print(
"Setting option flags", end=
' ')
531 mt.SetOptionFlags(*flag_tuple)
533 if 'icc-command' in actions:
534 icc_command_names = {
535 0:
'start representative motion',
536 1:
'stop representative motion',
537 2:
'store ICC results',
538 3:
'representative motion state'}
539 print(
"Sending ICC command 0x%02X (%s):" % (
540 icc_command, icc_command_names[icc_command]), end=
' ')
542 res = mt.IccCommand(icc_command)
543 if icc_command == 0x00:
545 elif icc_command == 0x01:
547 elif icc_command == 0x02:
549 elif icc_command == 0x03:
550 res_string = {0:
'representative motion inactive',
551 1:
'representation motion active'}
552 print(
"0x02X (%s)" % (res, res_string.get(res,
'unknown')))
553 if 'legacy-configure' in actions:
555 print(
"output-mode is require to configure the device in " 559 print(
"output-settings is required to configure the device " 562 print(
"Configuring in legacy mode", end=
' ')
564 mt.configure_legacy(mode, settings, period, skipfactor)
566 if 'xkf-scenario' in actions:
567 print(
"Changing XKF scenario", end=
' ')
569 mt.SetCurrentScenario(new_xkf)
571 if 'echo' in actions:
577 print(mt.read_measurement(mode, settings))
578 except KeyboardInterrupt:
580 except MTErrorMessage
as e:
581 print(
"MTErrorMessage:", e)
582 except MTException
as e:
583 print(
"MTException:", e)
588 def config_fmt(config):
589 """Hexadecimal configuration.""" 590 return '[%s]' %
', '.join(
'(0x%04X, %d)' % (mode, freq)
591 for (mode, freq)
in config)
594 """Factory for hexadecimal representation formatter.""" 595 fmt =
'0x%%0%dX' % (2*size)
598 """Hexadecimal representation.""" 603 def sync_fmt(settings):
604 """Synchronization settings: N*12 bytes""" 605 return '[%s]' %
', '.join(
'(0x%02X, 0x%02X, 0x%02X, 0x%02X,' 606 ' 0x%04X, 0x%04X, 0x%04X, 0x%04X)' % s
609 def try_message(m, f, formater=None, *args, **kwargs):
610 print(
' %s ' % m, end=
' ')
612 if formater
is not None:
613 print(formater(f(*args, **kwargs)))
615 pprint.pprint(f(*args, **kwargs), indent=4)
616 except MTTimeoutException
as e:
617 print(
'timeout: might be unsupported by your device.')
618 except MTErrorMessage
as e:
620 print(
'message unsupported by your device.')
623 print(
"Device: %s at %d Bd:" % (device, baudrate))
624 try_message(
"device ID:", mt.GetDeviceID, hex_fmt(4))
625 try_message(
"product code:", mt.GetProductCode)
626 try_message(
"hardware version:", mt.GetHardwareVersion)
627 try_message(
"firmware revision:", mt.GetFirmwareRev)
628 try_message(
"baudrate:", mt.GetBaudrate)
629 try_message(
"error mode:", mt.GetErrorMode, hex_fmt(2))
630 try_message(
"option flags:", mt.GetOptionFlags, hex_fmt(4))
631 try_message(
"location ID:", mt.GetLocationID, hex_fmt(2))
632 try_message(
"transmit delay:", mt.GetTransmitDelay)
633 try_message(
"synchronization settings:", mt.GetSyncSettings, sync_fmt)
634 try_message(
"general configuration:", mt.GetConfiguration)
635 try_message(
"output configuration (mark IV devices):",
636 mt.GetOutputConfiguration, config_fmt)
637 try_message(
"string output type:", mt.GetStringOutputType)
638 try_message(
"period:", mt.GetPeriod)
639 try_message(
"alignment rotation sensor:", mt.GetAlignmentRotation,
641 try_message(
"alignment rotation local:", mt.GetAlignmentRotation,
643 try_message(
"output mode:", mt.GetOutputMode, hex_fmt(2))
644 try_message(
"extended output mode:", mt.GetExtOutputMode, hex_fmt(2))
645 try_message(
"output settings:", mt.GetOutputSettings, hex_fmt(4))
646 try_message(
"GPS coordinates (lat, lon, alt):", mt.GetLatLonAlt)
647 try_message(
"GNSS platform:", mt.GetGnssPlatform)
648 try_message(
"available scenarios:", mt.GetAvailableScenarios)
649 try_message(
"current scenario ID:", mt.GetCurrentScenario)
650 try_message(
"UTC time:", mt.GetUTCTime)
654 """Parse the mark IV output configuration argument.""" 658 'iu': (0x1010, 2000),
659 'ip': (0x1020, 2000),
660 'ii': (0x1030, 2000),
661 'if': (0x1060, 2000),
662 'ic': (0x1070, 2000),
663 'ir': (0x1080, 2000),
668 'ad': (0x4010, 2000),
669 'aa': (0x4020, 2000),
670 'af': (0x4030, 2000),
671 'ah': (0x4040, 1000),
677 'wr': (0x8020, 2000),
678 'wd': (0x8030, 2000),
679 'wh': (0x8040, 1000),
684 'rr': (0xA010, 2000),
685 'rt': (0xA020, 2000),
688 'sb': (0xE010, 2000),
692 format_dict = {
'f': 0x00,
'd': 0x03,
'e': 0x00,
'n': 0x04,
'w': 0x08}
693 config_re = re.compile(
'([a-z]{2})(\d+)?([fdenw])?([fdnew])?')
694 output_configuration = []
696 for item
in config_arg.split(
','):
697 group, frequency, fmt1, fmt2 = config_re.findall(item.lower())[0]
698 code, max_freq = code_dict[group]
699 if fmt1
in format_dict:
700 code |= format_dict[fmt1]
701 if fmt2
in format_dict:
702 code |= format_dict[fmt2]
704 frequency = min(max_freq, int(frequency))
707 output_configuration.append((code, frequency))
708 return output_configuration
709 except (IndexError, KeyError):
710 print(
'could not parse output specification "%s"' % item)
715 """Parse command line output-mode argument.""" 736 mode |= OutputMode.Temp
738 mode |= OutputMode.Calib
740 mode |= OutputMode.Orient
742 mode |= OutputMode.Auxiliary
744 mode |= OutputMode.Position
746 mode |= OutputMode.Velocity
748 mode |= OutputMode.Status
750 mode |= OutputMode.RAWGPS
752 mode |= OutputMode.RAW 754 print(
"Unknown output-mode specifier: '%s'" % c)
760 """Parse command line output-settings argument.""" 768 settings = int(arg, 2)
773 settings = int(arg, 16)
780 calib_mode = OutputSettings.CalibMode_Mask
784 timestamp = OutputSettings.Timestamp_SampleCnt
786 timestamp = OutputSettings.Timestamp_None
788 timestamp |= OutputSettings.Timestamp_UTCTime 790 orient_mode = OutputSettings.OrientMode_Quaternion
792 orient_mode = OutputSettings.OrientMode_Euler
794 orient_mode = OutputSettings.OrientMode_Matrix
796 calib_mode &= OutputSettings.CalibMode_Acc
798 calib_mode &= OutputSettings.CalibMode_Gyr
800 calib_mode &= OutputSettings.CalibMode_Mag
802 calib_mode &= OutputSettings.AuxiliaryMode_NoAIN2
804 calib_mode &= OutputSettings.AuxiliaryMode_NoAIN1
806 NED = OutputSettings.Coordinates_NED
808 print(
"Unknown output-settings specifier: '%s'" % c)
810 settings = timestamp | orient_mode | calib_mode | NED
815 """Parse command line synchronization-settings argument.""" 817 sync_settings = [0, 0, 0, 0, 0, 0, 0, 0]
821 sync_settings = arg.split(
',')
824 sync_settings = tuple([int(i)
for i
in sync_settings])
826 print(
"Synchronization sync_settings must be integers.")
829 if sync_settings[0]
in (3, 4, 8, 9, 11)
and \
830 sync_settings[1]
in (0, 1, 2, 4, 5, 6)
and \
831 sync_settings[2]
in (1, 2, 3)
and \
832 sync_settings[3]
in (0, 1):
835 print(
"Invalid synchronization settings.")
840 """Parse command line UTC time specification.""" 844 timestamp = datetime.datetime.utcnow()
846 time_settings.append(timestamp.year)
847 time_settings.append(timestamp.month)
848 time_settings.append(timestamp.day)
849 time_settings.append(timestamp.hour)
850 time_settings.append(timestamp.minute)
851 time_settings.append(timestamp.second)
852 time_settings.append(timestamp.microsecond*1000)
853 time_settings.append(0)
857 time_settings = arg.split(
',')
859 time_settings = [int(i)
for i
in time_settings]
861 print(
"UTCtime settings must be integers.")
865 if 1999 <= time_settings[0] <= 2099
and \
866 1 <= time_settings[1] <= 12
and \
867 1 <= time_settings[2] <= 31
and \
868 0 <= time_settings[3] <= 23
and \
869 0 <= time_settings[4] <= 59
and \
870 0 <= time_settings[5] <= 59
and \
871 0 <= time_settings[6] <= 1000000000:
874 print(
"Invalid UTCtime settings.")
879 """Parse and check command line GNSS platform argument.""" 883 print(
"GNSS platform must be an integer.")
885 if platform
in (0, 8):
888 print(
"Invalid GNSS platform argument (excepted 0 or 8).")
893 """Parse and check command line option flags argument.""" 895 set_flag, clear_flag = map(
lambda s: int(s.strip(), base=0),
897 return (set_flag, clear_flag)
899 print(
'incorrect option flags specification (expected a pair of ' 905 """Parse and check ICC command argument.""" 907 icc_command = int(arg, base=0)
908 if icc_command
not in range(4):
912 print(
'invalid ICC command "%s"; expected 0, 1, 2, or 3.' % arg)
916 if __name__ ==
'__main__':
def get_gnss_platform(arg)
def get_output_config(config_arg)
def find_devices(timeout=0.002, verbose=False, initial_wait=0.1)
def find_baudrate(port, timeout=0.002, verbose=False, initial_wait=0.1)
Auto detect baudrate.
def get_option_flags(arg)
def inspect(mt, device, baudrate)
def usage()
Documentation for stand alone usage.
def get_synchronization_settings(arg)