eMPL-client.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. #!/usr/bin/python
  2. # eMPL_client.py
  3. # A PC application for use with Embedded MotionApps.
  4. # Copyright 2012 InvenSense, Inc. All Rights Reserved.
  5. import serial, sys, time, string, pygame
  6. from ponycube import *
  7. class eMPL_packet_reader:
  8. def __init__(self, port, quat_delegate=None, debug_delegate=None, data_delegate=None ):
  9. self.s = serial.Serial(port,115200)
  10. self.s.setTimeout(0.1)
  11. self.s.setWriteTimeout(0.2)
  12. # TODO: Will this break anything?
  13. ##Client attempts to write to eMPL.
  14. #try:
  15. #self.s.write("\n")
  16. #except serial.serialutil.SerialTimeoutException:
  17. #pass # write will timeout if umpl app is already started.
  18. if quat_delegate:
  19. self.quat_delegate = quat_delegate
  20. else:
  21. self.quat_delegate = empty_packet_delegate()
  22. if debug_delegate:
  23. self.debug_delegate = debug_delegate
  24. else:
  25. self.debug_delegate = empty_packet_delegate()
  26. if data_delegate:
  27. self.data_delegate = data_delegate
  28. else:
  29. self.data_delegate = empty_packet_delegate()
  30. self.packets = []
  31. self.length = 0
  32. self.previous = None
  33. def read(self):
  34. NUM_BYTES = 23
  35. p = None
  36. while self.s.inWaiting() >= NUM_BYTES:
  37. rs = self.s.read(NUM_BYTES)
  38. if ord(rs[0]) == ord('$'):
  39. pkt_code = ord(rs[1])
  40. if pkt_code == 1:
  41. d = debug_packet(rs)
  42. self.debug_delegate.dispatch(d)
  43. elif pkt_code == 2:
  44. p = quat_packet(rs)
  45. self.quat_delegate.dispatch(p)
  46. elif pkt_code == 3:
  47. d = data_packet(rs)
  48. self.data_delegate.dispatch(d)
  49. else:
  50. print "no handler for pkt_code",pkt_code
  51. else:
  52. c = ' '
  53. print "serial misaligned!"
  54. while not ord(c) == ord('$'):
  55. c = self.s.read(1)
  56. self.s.read(NUM_BYTES-1)
  57. def write(self,a):
  58. self.s.write(a)
  59. def close(self):
  60. self.s.close()
  61. def write_log(self,fname):
  62. f = open(fname,'w')
  63. for p in self.packets:
  64. f.write(p.logfile_line())
  65. f.close()
  66. # =========== PACKET DELEGATES ==========
  67. class packet_delegate(object):
  68. def loop(self,event):
  69. print "generic packet_delegate loop w/event",event
  70. def dispatch(self,p):
  71. print "generic packet_delegate dispatched",p
  72. class empty_packet_delegate(packet_delegate):
  73. def loop(self,event):
  74. pass
  75. def dispatch(self,p):
  76. pass
  77. class cube_packet_viewer (packet_delegate):
  78. def __init__(self):
  79. self.screen = Screen(480,400,scale=1.5)
  80. self.cube = Cube(30,60,10)
  81. self.q = Quaternion(1,0,0,0)
  82. self.previous = None # previous quaternion
  83. self.latest = None # latest packet (get in dispatch, use in loop)
  84. def loop(self,event):
  85. packet = self.latest
  86. if packet:
  87. q = packet.to_q().normalized()
  88. self.cube.erase(self.screen)
  89. self.cube.draw(self.screen,q)
  90. pygame.display.flip()
  91. self.latest = None
  92. def dispatch(self,p):
  93. if isinstance(p,quat_packet):
  94. self.latest = p
  95. class debug_packet_viewer (packet_delegate):
  96. def loop(self,event):
  97. pass
  98. def dispatch(self,p):
  99. assert isinstance(p,debug_packet);
  100. p.display()
  101. class data_packet_viewer (packet_delegate):
  102. def loop(self,event):
  103. pass
  104. def dispatch(self,p):
  105. assert isinstance(p,data_packet);
  106. p.display()
  107. # =============== PACKETS =================
  108. # For 16-bit signed integers.
  109. def two_bytes(d1,d2):
  110. d = ord(d1)*256 + ord(d2)
  111. if d > 32767:
  112. d -= 65536
  113. return d
  114. # For 32-bit signed integers.
  115. def four_bytes(d1, d2, d3, d4):
  116. d = ord(d1)*(1<<24) + ord(d2)*(1<<16) + ord(d3)*(1<<8) + ord(d4)
  117. if d > 2147483648:
  118. d-= 4294967296
  119. return d
  120. class debug_packet (object):
  121. # body of packet is a debug string
  122. def __init__(self,l):
  123. sss = []
  124. for c in l[3:21]:
  125. if ord(c) != 0:
  126. sss.append(c)
  127. self.s = "".join(sss)
  128. def display(self):
  129. sys.stdout.write(self.s)
  130. class data_packet (object):
  131. def __init__(self, l):
  132. self.data = [0,0,0,0,0,0,0,0,0]
  133. self.type = ord(l[2])
  134. if self.type == 0: # accel
  135. self.data[0] = four_bytes(l[3],l[4],l[5],l[6]) * 1.0 / (1<<16)
  136. self.data[1] = four_bytes(l[7],l[8],l[9],l[10]) * 1.0 / (1<<16)
  137. self.data[2] = four_bytes(l[11],l[12],l[13],l[14]) * 1.0 / (1<<16)
  138. elif self.type == 1: # gyro
  139. self.data[0] = four_bytes(l[3],l[4],l[5],l[6]) * 1.0 / (1<<16)
  140. self.data[1] = four_bytes(l[7],l[8],l[9],l[10]) * 1.0 / (1<<16)
  141. self.data[2] = four_bytes(l[11],l[12],l[13],l[14]) * 1.0 / (1<<16)
  142. elif self.type == 2: # compass
  143. self.data[0] = four_bytes(l[3],l[4],l[5],l[6]) * 1.0 / (1<<16)
  144. self.data[1] = four_bytes(l[7],l[8],l[9],l[10]) * 1.0 / (1<<16)
  145. self.data[2] = four_bytes(l[11],l[12],l[13],l[14]) * 1.0 / (1<<16)
  146. elif self.type == 3: # quat
  147. self.data[0] = four_bytes(l[3],l[4],l[5],l[6]) * 1.0 / (1<<30)
  148. self.data[1] = four_bytes(l[7],l[8],l[9],l[10]) * 1.0 / (1<<30)
  149. self.data[2] = four_bytes(l[11],l[12],l[13],l[14]) * 1.0 / (1<<30)
  150. self.data[3] = four_bytes(l[15],l[16],l[17],l[18]) * 1.0 / (1<<30)
  151. elif self.type == 4: # euler
  152. self.data[0] = four_bytes(l[3],l[4],l[5],l[6]) * 1.0 / (1<<16)
  153. self.data[1] = four_bytes(l[7],l[8],l[9],l[10]) * 1.0 / (1<<16)
  154. self.data[2] = four_bytes(l[11],l[12],l[13],l[14]) * 1.0 / (1<<16)
  155. elif self.type == 5: # rot
  156. self.data[0] = two_bytes(l[3],l[4]) * 1.0 / (1<<14)
  157. self.data[1] = two_bytes(l[5],l[6]) * 1.0 / (1<<14)
  158. self.data[2] = two_bytes(l[7],l[8]) * 1.0 / (1<<14)
  159. self.data[3] = two_bytes(l[9],l[10]) * 1.0 / (1<<14)
  160. self.data[4] = two_bytes(l[11],l[12]) * 1.0 / (1<<14)
  161. self.data[5] = two_bytes(l[13],l[14]) * 1.0 / (1<<14)
  162. self.data[6] = two_bytes(l[15],l[16]) * 1.0 / (1<<14)
  163. self.data[7] = two_bytes(l[17],l[18]) * 1.0 / (1<<14)
  164. self.data[8] = two_bytes(l[19],l[20]) * 1.0 / (1<<14)
  165. elif self.type == 6: # heading
  166. self.data[0] = four_bytes(l[3],l[4],l[5],l[6]) * 1.0 / (1<<16)
  167. else: # unsupported
  168. pass
  169. def display(self):
  170. if self.type == 0:
  171. print 'accel: %7.3f %7.3f %7.3f' % \
  172. (self.data[0], self.data[1], self.data[2])
  173. elif self.type == 1:
  174. print 'gyro: %9.5f %9.5f %9.5f' % \
  175. (self.data[0], self.data[1], self.data[2])
  176. elif self.type == 2:
  177. print 'compass: %7.4f %7.4f %7.4f' % \
  178. (self.data[0], self.data[1], self.data[2])
  179. elif self.type == 3:
  180. print 'quat: %7.4f %7.4f %7.4f %7.4f' % \
  181. (self.data[0], self.data[1], self.data[2], self.data[3])
  182. elif self.type == 4:
  183. print 'euler: %7.4f %7.4f %7.4f' % \
  184. (self.data[0], self.data[1], self.data[2])
  185. elif self.type == 5:
  186. print 'rotation matrix: \n%7.3f %7.3f %7.3f\n%7.3f %7.3f %7.3f\n%7.3f %7.3f %7.3f' % \
  187. (self.data[0], self.data[1], self.data[2], self.data[3], \
  188. self.data[4], self.data[5], self.data[6], self.data[7], \
  189. self.data[8])
  190. elif self.type == 6:
  191. print 'heading: %7.4f' % self.data[0]
  192. else:
  193. print 'what?'
  194. class quat_packet (object):
  195. def __init__(self, l):
  196. self.l = l
  197. self.q0 = four_bytes(l[3],l[4],l[5],l[6]) * 1.0 / (1<<30)
  198. self.q1 = four_bytes(l[7],l[8],l[9],l[10]) * 1.0 / (1<<30)
  199. self.q2 = four_bytes(l[11],l[12],l[13],l[14]) * 1.0 / (1<<30)
  200. self.q3 = four_bytes(l[15],l[16],l[17],l[18]) * 1.0 / (1<<30)
  201. def display_raw(self):
  202. l = self.l
  203. print "".join(
  204. [ str(ord(l[0])), " "] + \
  205. [ str(ord(l[1])), " "] + \
  206. [ str(ord(a)).ljust(4) for a in
  207. [ l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9], l[10] ] ] + \
  208. [ str(ord(a)).ljust(4) for a in
  209. [ l[8], l[9], l[10] , l[11], l[12], l[13]] ]
  210. )
  211. def display(self):
  212. if 1:
  213. print "qs " + " ".join([str(s).ljust(15) for s in
  214. [ self.q0, self.q1, self.q2, self.q3 ]])
  215. if 0:
  216. euler0, euler1, euler2 = self.to_q().get_euler()
  217. print "eulers " + " ".join([str(s).ljust(15) for s in
  218. [ euler0, euler1, euler2 ]])
  219. if 0:
  220. euler0, euler1, euler2 = self.to_q().get_euler()
  221. print "eulers " + " ".join([str(s).ljust(15) for s in
  222. [ (euler0 * 180.0 / 3.14159) - 90 ]])
  223. def to_q(self):
  224. return Quaternion(self.q0, self.q1, self.q2, self.q3)
  225. # =============== MAIN ======================
  226. if __name__ == "__main__":
  227. if len(sys.argv) == 2:
  228. comport = int(sys.argv[1]) - 1
  229. else:
  230. print "usage: " + sys.argv[0] + " port"
  231. sys.exit(-1)
  232. pygame.init()
  233. viewer = cube_packet_viewer()
  234. debug = debug_packet_viewer()
  235. data = data_packet_viewer()
  236. reader = eMPL_packet_reader(comport,
  237. quat_delegate = viewer,
  238. debug_delegate = debug,
  239. data_delegate = data)
  240. while 1:
  241. event = pygame.event.poll()
  242. # TODO: Allow exit via keystroke.
  243. if event.type == pygame.QUIT:
  244. viewer.close()
  245. break
  246. if event.type == pygame.KEYDOWN:
  247. reader.write(pygame.key.name(event.key))
  248. reader.read()
  249. viewer.loop(event)
  250. debug.loop(event)
  251. data.loop(event)
  252. # TODO: If system load is too high, increase this sleep time.
  253. pygame.time.delay(0)