/ak47/ak47wiimote.py

https://github.com/vranki/wiishooter
Python | 333 lines | 199 code | 98 blank | 36 comment | 42 complexity | 65566e410bf2a1b0aef58e670e148a60 MD5 | raw file
  1. import cwiid
  2. from ak47 import Ak47
  3. from math import *
  4. import copy
  5. import pickle
  6. class Ak47Wiimote(Ak47):
  7. def __init__(self):
  8. self.ir_pos = []
  9. self.volatile_ir_pos = []
  10. self.volatile_acc_data = []
  11. self.acc_data = []
  12. self.reload_on = False
  13. self.dist = 0 #distance to sensobar in cm
  14. self.cpoint = [0,0]
  15. self.old_cpoint = self.cpoint[:]
  16. self.calib_points = []
  17. self.maxmin = []
  18. self.fire_button = False
  19. self.volatile_fire_button = False
  20. self.dist_values = []
  21. self.reso = (1024,768) #wiimote
  22. fov_scale = 1.33
  23. self.x_pix = fov_scale*33/1024.0 #[deg/pixel]
  24. self.y_pix = fov_scale*23/768.0 #[deg/pixel]
  25. self.wiimote = cwiid.Wiimote()
  26. led = 0
  27. led ^= cwiid.LED2_ON
  28. self.wiimote.led = led
  29. self.wiimote.mesg_callback = self.callback
  30. rpt_mode = 0
  31. rpt_mode ^= cwiid.RPT_IR
  32. rpt_mode ^= cwiid.RPT_BTN
  33. rpt_mode ^= cwiid.RPT_ACC
  34. self.wiimote.rpt_mode = rpt_mode
  35. self.wiimote.enable(cwiid.FLAG_MESG_IFC)
  36. self.vel_values = []
  37. def close(self):
  38. self.wiimote.close()
  39. def save_calibration(self, file_name):
  40. f = open(file_name, "w+")
  41. pickle.dump(self.maxmin, f)
  42. f.close()
  43. def load_calibration(self, file_name):
  44. f = open(file_name)
  45. self.maxmin = pickle.load(f)
  46. f.close()
  47. def is_calibrated(self):
  48. return len(self.maxmin) > 0
  49. def decalibrate(self):
  50. self.minmax = []
  51. self.calib_points = []
  52. def get_pos(self):
  53. screen_reso = (1024,768)
  54. self.ir_pos = self.volatile_ir_pos[:]
  55. self.fire_button = self.volatile_fire_button
  56. self.calc_distance()
  57. self.center_point()
  58. if not self.is_calibrated():
  59. ret_x = self.cpoint[0] / 1024.0*screen_reso[0]
  60. ret_y = self.cpoint[1] / 768.0*screen_reso[1]
  61. return [ret_x, ret_y], self.fire_button
  62. cent = (self.reso[0]/2, self.reso[1]/2)
  63. x = self.dist * tan(self.x_pix*(-self.cpoint[0]+cent[0])*pi/180)
  64. y = self.dist * tan(self.y_pix*(-self.cpoint[1]+cent[1])*pi/180)
  65. x_scale = 1.0/(self.maxmin[0] - self.maxmin[1])
  66. y_scale = 1.0/(self.maxmin[2] - self.maxmin[3])
  67. x_scaled = x_scale*(self.maxmin[0] - x)
  68. y_scaled = y_scale*(self.maxmin[2] - y)
  69. #print x,y,x_scale,y_scale,x_scaled,y_scaled
  70. ret_x = max([0.0, x_scaled])
  71. ret_x = min([1.0, ret_x])
  72. ret_y = max([0.0, y_scaled])
  73. ret_y = min([1.0, ret_y])
  74. return [int(ret_x*screen_reso[0]), int(ret_y*screen_reso[1])], self.fire_button
  75. def fire(self, on):
  76. try:
  77. if not on:
  78. self.wiimote.led = 0
  79. else:
  80. self.wiimote.led = cwiid.LED2_ON
  81. except:
  82. print "wiimote led state change failed! (solenoid command!)"
  83. print self.wiimote
  84. def reload_ak(self):
  85. acc = self.volatile_acc_data[:]
  86. if acc[0] < 140 and acc[0] > 110 and \
  87. acc[1] > 143 and acc[1] < 155 and \
  88. acc[2] < 143 and acc[2] > 125:
  89. self.reload_on = True
  90. if acc[0] < 105 or acc[0] > 145 or \
  91. acc[1] < 138 or acc[2] > 147:
  92. self.reload_on = False
  93. return self.reload_on
  94. def get_acc_data(self):
  95. return self.volatile_acc_data
  96. def calibrate(self, calib_index):
  97. self.ir_pos = self.volatile_ir_pos[:]
  98. self.calc_distance()
  99. self.center_point()
  100. temp_pos = copy.deepcopy(self.cpoint)
  101. if calib_index < 3:
  102. self.calib_points.append(temp_pos)
  103. return
  104. else:
  105. self.calib_points.append(temp_pos)
  106. cent = (self.reso[0]/2, self.reso[1]/2)
  107. x_const = self.x_pix*pi/180
  108. y_const = self.x_pix*pi/180
  109. calib_min_x1 = self.dist * tan(x_const*(cent[0] - self.calib_points[0][0]))
  110. calib_min_x2 = self.dist * tan(x_const*(cent[0] - self.calib_points[1][0]))
  111. calib_min_y1 = self.dist * tan(y_const*(cent[1] - self.calib_points[0][1]))
  112. calib_min_y2 = self.dist * tan(y_const*(cent[1] - self.calib_points[3][1]))
  113. calib_max_x1 = self.dist * tan(x_const*(cent[0] - self.calib_points[2][0]))
  114. calib_max_x2 = self.dist * tan(x_const*(cent[0] - self.calib_points[3][0]))
  115. calib_max_y1 = self.dist * tan(y_const*(cent[1] - self.calib_points[1][1]))
  116. calib_max_y2 = self.dist * tan(y_const*(cent[1] - self.calib_points[2][1]))
  117. if abs(calib_min_x1 - calib_min_x2) > 25:
  118. print "calib error #1", calib_min_x1, calib_min_x2
  119. if abs(calib_max_x1 - calib_max_x2) > 25:
  120. print "calib error #2", calib_max_x1, calib_max_x2
  121. if abs(calib_min_y1 - calib_min_y2) > 25:
  122. print "calib error #3", calib_min_y1, calib_min_y2
  123. if abs(calib_max_y1 - calib_max_y2) > 25:
  124. print "calib error #4", calib_max_y1, calib_max_y2
  125. self.maxmin = [ (calib_min_x1 + calib_min_x2) / 2.0, \
  126. (calib_max_x1 + calib_max_x2) / 2.0, \
  127. (calib_min_y1 + calib_min_y2) / 2.0, \
  128. (calib_max_y1 + calib_max_y2) / 2.0 ]
  129. print "calib points", self.calib_points
  130. print "calib points2", calib_min_x1, calib_min_x2, calib_max_x1, calib_max_x2, \
  131. calib_min_y1, calib_min_y2, calib_max_y1, calib_max_y2
  132. print "minmax", self.maxmin
  133. def valid_value(self):
  134. if len(self.ir_pos) != 4:
  135. return False
  136. if self.ir_pos[0] == None or self.ir_pos[1] == None or \
  137. self.ir_pos[2] != None or self.ir_pos[3] != None:
  138. return False
  139. if self.ir_pos[0].has_key("pos") and self.ir_pos[1].has_key("pos"):
  140. pass
  141. else:
  142. return False
  143. return True
  144. def compensate(self):
  145. comp = 1.5
  146. vel_vect = [self.cpoint[0] - self.old_cpoint[0], \
  147. self.cpoint[1] - self.old_cpoint[1]]
  148. #print vel_vect, self.cpoint, self.old_cpoint
  149. self.old_cpoint = self.cpoint[:]
  150. # mean value filtering (low pass filter)
  151. self.vel_values.append(vel_vect)
  152. if len(self.vel_values) > 4:
  153. self.vel_values.pop(0)
  154. x_vel = 0
  155. y_vel = 0
  156. for vel in self.vel_values:
  157. x_vel += vel[0]
  158. y_vel += vel[1]
  159. x_vel = x_vel/len(self.vel_values)
  160. y_vel = y_vel/len(self.vel_values)
  161. self.cpoint = [self.cpoint[0] + x_vel*comp, \
  162. self.cpoint[1] + y_vel*comp]
  163. def center_point(self):
  164. if not self.valid_value():
  165. return
  166. led1 = self.ir_pos[0]["pos"]
  167. led2 = self.ir_pos[1]["pos"]
  168. self.cpoint[0] = 1024 - (led1[0] + led2[0]) / 2.0
  169. self.cpoint[1] = (led1[1] + led2[1]) / 2.0
  170. #self.compensate()
  171. #distance to screen [cm]
  172. def calc_distance(self):
  173. ir_sensor_width = 19 #[cm]
  174. pix = (self.x_pix + self.y_pix) / 2.0
  175. if not self.valid_value():
  176. return
  177. led1 = self.ir_pos[0]["pos"]
  178. led2 = self.ir_pos[1]["pos"]
  179. # angle between ir-blobs
  180. alfa = sqrt( (led1[0] - led2[0]) ** 2 + (led1[1] - led2[1]) ** 2 ) * pix
  181. local_dist = ir_sensor_width / tan(alfa*pi/180)
  182. #self.dist = tan(alfa*pi/180)
  183. # mean value filtering (low pass filter)
  184. self.dist_values.append(local_dist)
  185. if len(self.dist_values) > 10:
  186. self.dist_values.pop(0)
  187. self.dist = 0
  188. for dist in self.dist_values:
  189. self.dist += dist
  190. self.dist = self.dist/len(self.dist_values)
  191. def callback(self, mesg_list, time):
  192. for mesg in mesg_list:
  193. if mesg[0] == cwiid.MESG_BTN:
  194. if mesg[1]==4:
  195. self.volatile_fire_button = True
  196. if mesg[1]==0:
  197. self.volatile_fire_button = False
  198. elif mesg[0] == cwiid.MESG_IR:
  199. self.volatile_ir_pos = mesg[1]
  200. elif mesg[0] == cwiid.MESG_ACC:
  201. self.volatile_acc_data = mesg[1]
  202. elif mesg[0] == cwiid.MESG_ERROR:
  203. print "Wiimote: Error message received"
  204. self.wiimote.close()
  205. exit(-1)
  206. else:
  207. print "Wiimote: Unknown Report"
  208. ##print ""
  209. ##mote = Ak47()
  210. ##mote.ir_pos = [[521,400], [600,400]]
  211. ##mote.calc_distance()
  212. ##print mote.dist
  213. ##
  214. ##print ""
  215. ##print mote.is_calibrated()
  216. ##print mote.get_pos()
  217. ##
  218. ##print ""
  219. ##mote.ir_pos = [[800,750], [1000,750]]
  220. ##mote.calibrate(0)
  221. ##mote.ir_pos = [[800,50], [1000,50]]
  222. ##mote.calibrate(1)
  223. ##mote.ir_pos = [[50,50], [250,50]]
  224. ##mote.calibrate(2)
  225. ##mote.ir_pos = [[50,750], [250,750]]
  226. ##mote.calibrate(3)
  227. ##print mote.maxmin
  228. ##print ""
  229. ##print mote.is_calibrated()
  230. ##
  231. ##print ""
  232. ##mote.ir_pos = [[100,700], [300,700]]
  233. ##print mote.get_pos()
  234. ##mote.ir_pos = [[700,20], [900,20]]
  235. ##print mote.get_pos()