MPU6KSearch.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #!/usr/bin/env python
  2. '''
  3. search a set of log files for signs of inconsistent IMU data
  4. '''
  5. from __future__ import print_function
  6. from builtins import input
  7. from builtins import range
  8. import sys, time, os
  9. import zipfile
  10. from pymavlink import mavutil
  11. from math import degrees
  12. # extra imports for pyinstaller
  13. import json
  14. from pymavlink.dialects.v10 import ardupilotmega
  15. search_dirs = ['c:\Program Files\APM Planner',
  16. 'c:\Program Files\Mission Planner',
  17. 'c:\Program Files (x86)\APM Planner',
  18. 'c:\Program Files (x86)\Mission Planner']
  19. results = 'SearchResults.zip'
  20. email = 'Craig Elder <craig@3drobotics.com>'
  21. def IMUCheckFail(filename):
  22. try:
  23. mlog = mavutil.mavlink_connection(filename)
  24. except Exception:
  25. return False
  26. accel1 = None
  27. accel2 = None
  28. gyro1 = None
  29. gyro2 = None
  30. t1 = 0
  31. t2 = 0
  32. ecount_accel = [0]*3
  33. ecount_gyro = [0]*3
  34. athreshold = 3.0
  35. gthreshold = 30.0
  36. count_threshold = 100
  37. imu1_count = 0
  38. imu2_count = 0
  39. while True:
  40. try:
  41. m = mlog.recv_match(type=['RAW_IMU','SCALED_IMU2','IMU','IMU2','PARM','PARAM_VALUE'])
  42. except Exception as e:
  43. print('Error: %s' % e)
  44. break
  45. if m is None:
  46. break
  47. mtype = m.get_type()
  48. gotimu2 = False
  49. if mtype == 'RAW_IMU':
  50. accel1 = [m.xacc*9.81*0.001, m.yacc*9.81*0.001, m.zacc*9.81*0.001]
  51. gyro1 = [degrees(m.xgyro*0.001), degrees(m.ygyro*0.001), degrees(m.zgyro*0.001)]
  52. t1 = m.time_usec/1000
  53. imu1_count += 1
  54. elif mtype == 'SCALED_IMU2':
  55. accel2 = [m.xacc*9.81*0.001, m.yacc*9.81*0.001, m.zacc*9.81*0.001]
  56. gyro2 = [degrees(m.xgyro*0.001), degrees(m.ygyro*0.001), degrees(m.zgyro*0.001)]
  57. gotimu2 = True
  58. t2 = m.time_boot_ms
  59. imu2_count += 1
  60. elif mtype == 'IMU':
  61. accel1 = [m.AccX, m.AccY, m.AccZ]
  62. gyro1 = [m.GyrX, m.GyrY, m.GyrZ]
  63. t1 = m.TimeMS
  64. imu1_count += 1
  65. elif mtype == 'IMU2':
  66. accel2 = [m.AccX, m.AccY, m.AccZ]
  67. gyro2 = [m.GyrX, m.GyrY, m.GyrZ]
  68. gotimu2 = True
  69. t2 = m.TimeMS
  70. imu2_count += 1
  71. elif mtype == 'PARM':
  72. if m.Name.startswith('INS_ACCOFFS_') or m.Name.startswith('INS_ACC2OFFS_'):
  73. if m.Value == 0.0:
  74. print('UNCALIBRATED: %s' % m)
  75. return False
  76. elif mtype == 'PARAM_VALUE':
  77. if m.param_id.startswith('INS_ACCOFFS_') or m.param_id.startswith('INS_ACC2OFFS_'):
  78. if m.param_value == 0.0:
  79. print('UNCALIBRATED: %s' % m)
  80. return False
  81. # skip out early if we don't have two IMUs
  82. if imu1_count > imu2_count + 100:
  83. return False
  84. if accel1 is not None and accel2 is not None and gotimu2 and t2 >= t1:
  85. for i in range(3):
  86. adiff = accel1[i] - accel2[i]
  87. if adiff > athreshold:
  88. if ecount_accel[i] < 0:
  89. ecount_accel[i] = 0
  90. else:
  91. ecount_accel[i] += 1
  92. elif adiff < -athreshold:
  93. if ecount_accel[i] > 0:
  94. ecount_accel[i] = 0
  95. else:
  96. ecount_accel[i] -= 1
  97. else:
  98. ecount_accel[i] = 0
  99. gdiff = gyro1[i] - gyro2[i]
  100. if gdiff > gthreshold:
  101. if ecount_gyro[i] < 0:
  102. ecount_gyro[i] = 0
  103. else:
  104. ecount_gyro[i] += 1
  105. elif gdiff < -gthreshold:
  106. if ecount_gyro[i] > 0:
  107. ecount_gyro[i] = 0
  108. else:
  109. ecount_gyro[i] -= 1
  110. else:
  111. ecount_gyro[i] = 0
  112. if abs(ecount_accel[i]) > count_threshold:
  113. print("acceldiff[%u] %.1f" % (i, adiff))
  114. print(m)
  115. return True
  116. if abs(ecount_gyro[i]) > count_threshold:
  117. print("gyrodiff[i] %.1f" % (i, adiff))
  118. print(m)
  119. return True
  120. return False
  121. found = []
  122. directories = sys.argv[1:]
  123. if not directories:
  124. directories = search_dirs
  125. filelist = []
  126. extensions = ['.tlog','.bin']
  127. def match_extension(f):
  128. '''see if the path matches a extension'''
  129. (root,ext) = os.path.splitext(f)
  130. return ext.lower() in extensions
  131. for d in directories:
  132. if not os.path.exists(d):
  133. continue
  134. if os.path.isdir(d):
  135. print("Searching in %s" % d)
  136. for (root, dirs, files) in os.walk(d):
  137. for f in files:
  138. if not match_extension(f):
  139. continue
  140. path = os.path.join(root, f)
  141. filelist.append(path)
  142. elif match_extension(d):
  143. filelist.append(d)
  144. for i in range(len(filelist)):
  145. f = filelist[i]
  146. print("Checking %s ... [found=%u i=%u/%u]" % (f, len(found), i, len(filelist)))
  147. try:
  148. if IMUCheckFail(f):
  149. found.append(f)
  150. except Exception as e:
  151. print("Failed - %s" % e)
  152. continue
  153. sys.stdout.flush()
  154. if len(found) == 0:
  155. print("No matching files found - all OK!")
  156. input('Press enter to close')
  157. sys.exit(0)
  158. print("Creating zip file %s" % results)
  159. try:
  160. zip = zipfile.ZipFile(results, 'w')
  161. except Exception:
  162. print("Unable to create zip file %s" % results)
  163. print("Please send matching files manually")
  164. for f in found:
  165. print('MATCHED: %s' % f)
  166. input('Press enter to close')
  167. sys.exit(1)
  168. for f in found:
  169. arcname=os.path.basename(f)
  170. if not arcname.startswith('201'):
  171. mtime = os.path.getmtime(f)
  172. arcname = "%s-%s" % (time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(mtime)), arcname)
  173. zip.write(f, arcname=arcname)
  174. zip.close()
  175. print('==============================================')
  176. print("Created %s with %u of %u matching logs" % (results, len(found), len(filelist)))
  177. print("Please send this file to %s" % email)
  178. print('==============================================')
  179. input('Press enter to close')
  180. sys.exit(0)