Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

563 lines
16KB

  1. # LICENSE: MIT (X11) License which follows:
  2. #
  3. # Copyright (c) 2008 Stephane Duchesneau
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a copy
  6. # of this software and associated documentation files (the "Software"), to deal
  7. # in the Software without restriction, including without limitation the rights
  8. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. # copies of the Software, and to permit persons to whom the Software is
  10. # furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. # THE SOFTWARE.
  22. #
  23. # Modified by Pere Negre and Pietro Pilolli
  24. #
  25. #
  26. import bluetooth
  27. import code
  28. from datetime import datetime
  29. from math import atan, asin, acos #ZDR
  30. import threading
  31. from time import time,sleep
  32. import time
  33. def i2bs(val):
  34. lst = []
  35. while val:
  36. lst.append(val&0xff)
  37. val = val >> 8
  38. lst.reverse()
  39. return lst
  40. class WiimoteState:
  41. Battery = None
  42. class ButtonState:
  43. A = False
  44. B = False
  45. Down = False
  46. Home = False
  47. Left = False
  48. Minus = False
  49. One = False
  50. Plus = False
  51. Right = False
  52. Two = False
  53. Up = False
  54. class GyroState:
  55. calibrated = False
  56. int_yaw = 0
  57. int_roll = 0
  58. int_pitch = 0
  59. zero_yaw = 8192
  60. zero_roll = 8159
  61. zero_pitch = 8208
  62. class AccelState:
  63. X = 0
  64. Y = 0
  65. Z = 0
  66. RawX = 0
  67. RawY = 0
  68. RawZ = 0
  69. zeroX = 0
  70. zeroY = 0
  71. zeroZ = 0
  72. class IRState:
  73. RawX1 = 0
  74. RawX2 = 0
  75. RawX3 = 0
  76. RawX4 = 0
  77. RawY1 = 0
  78. RawY2 = 0
  79. RawY3 = 0
  80. RawY4 = 0
  81. Found1 = 0
  82. Found2 = 0
  83. Found3 = 0
  84. Found4 = 0
  85. Size1 = 0
  86. Size2 = 0
  87. Size3 = 0
  88. Size4 = 0
  89. X1 = X2 = X3 = X4 = 0.0
  90. Y1 = Y2 = Y3 = Y4 = 0.0
  91. #Mode = None
  92. MidX = 0
  93. MidY = 0
  94. RawMidX = 0
  95. RawMidY = 0
  96. class LEDState:
  97. LED1 = False
  98. LED2 = False
  99. LED3 = False
  100. LED4 = False
  101. class Parser:
  102. """ Sets the values contained in a signal """
  103. A = 0x0008
  104. B = 0x0004
  105. Down = 0x0400
  106. Home = 0x0080
  107. Left = 0x0100
  108. Minus = 0x0010
  109. One = 0x0002
  110. Plus = 0x1000
  111. Right = 0x0200
  112. Two = 0x0001
  113. Up = 0x0800
  114. # ZDR
  115. gyro_deg_s = 1./8192./200.
  116. def parseButtons(self,signal, ButtonState): #signal is 16bit long intl
  117. ButtonState.A = bool(signal&self.A)
  118. ButtonState.B = bool(signal&self.B)
  119. ButtonState.Down = bool(signal&self.Down)
  120. ButtonState.Home = bool(signal&self.Home)
  121. ButtonState.Left = bool(signal&self.Left)
  122. ButtonState.Minus = bool(signal&self.Minus)
  123. ButtonState.One = bool(signal&self.One)
  124. ButtonState.Plus = bool(signal&self.Plus)
  125. ButtonState.Right = bool(signal&self.Right)
  126. ButtonState.Two = bool(signal&self.Two)
  127. ButtonState.Up = bool(signal&self.Up)
  128. #ZDR
  129. def parseAccelerometer(self, signal, AccelState):
  130. AccelState.RawX = signal[0] - 512
  131. AccelState.RawY = signal[1] - 512
  132. AccelState.RawZ = signal[2] - 512
  133. #ZDR
  134. def parseGyro(self, signal, slow, GyroState):
  135. if GyroState.calibrated==False:
  136. return
  137. yaw_slow = 440 if slow[0]==1 else 2000
  138. roll_slow = 440 if slow[1]==1 else 2000
  139. pitch_slow = 440 if slow[2]==1 else 2000
  140. GyroState.int_yaw += (signal[0] - GyroState.zero_yaw)*yaw_slow # *self.gyro_deg_s
  141. GyroState.int_roll += (signal[1] - GyroState.zero_roll)*roll_slow
  142. GyroState.int_pitch += (signal[2] - GyroState.zero_pitch)*pitch_slow
  143. #print '%d\t\t%d\t\t%d' % (GyroState.int_yaw, GyroState.int_roll, GyroState.int_pitch )
  144. def parseIR(self,signal,irstate):
  145. irstate.RawX1 = signal[0] + ((signal[2] & 0x30) >>4 << 8)
  146. irstate.RawY1 = signal[1] + (signal[2] >> 6 << 8)
  147. irstate.Size1 = signal[2] & 0x0f
  148. if irstate.RawY1 == 1023: irstate.Found1 = False
  149. else: irstate.Found1 = True
  150. irstate.RawX2 = signal[3] + ((signal[5] & 0x30) >>4 << 8)
  151. irstate.RawY2 = signal[4] + (signal[5] >> 6 << 8)
  152. irstate.Size2 = signal[5] & 0x0f
  153. if irstate.RawY2 == 1023: irstate.Found2 = False
  154. else: irstate.Found2 = True
  155. irstate.RawX3 = signal[6] + ((signal[8] & 0x30) >>4 << 8)
  156. irstate.RawY3 = signal[7] + (signal[8] >> 6 << 8)
  157. irstate.Size3 = signal[8] & 0x0f
  158. if irstate.RawY3 == 1023: irstate.Found3 = False
  159. else: irstate.Found3 = True
  160. irstate.RawX4 = signal[9] + ((signal[11] & 0x30) >>4 << 8)
  161. irstate.RawY4 = signal[10] + (signal[11] >> 6 << 8)
  162. irstate.Size4 = signal[11] & 0x0f
  163. if irstate.RawY4 == 1023: irstate.Found4 = False
  164. else: irstate.Found4 = True
  165. if irstate.Found1:
  166. if irstate.Found2:
  167. irstate.RawMidX = (irstate.RawX1 + irstate.RawX2) / 2
  168. irstate.RawMidY = (irstate.RawY1 + irstate.RawY2) / 2
  169. else:
  170. irstate.RawMidX = irstate.RawX1
  171. irstate.RawMidY = irstate.RawY1
  172. irstate.MidX = float(irstate.RawMidX) / 1024
  173. irstate.MidY = float(irstate.RawMidY) / 768
  174. else: irstate.MidX = irstate.MidY = 0
  175. class Setter:
  176. """The opposite from the Parser class: returns the signal needed to set the values in the wiimote"""
  177. LED1 = 0x10
  178. LED2 = 0x20
  179. LED3 = 0x40
  180. LED4 = 0x80
  181. def SetLEDs(self,ledstate):
  182. signal = 0
  183. if ledstate.LED1: signal += self.LED1
  184. if ledstate.LED2: signal += self.LED2
  185. if ledstate.LED3: signal += self.LED3
  186. if ledstate.LED4: signal += self.LED4
  187. return signal
  188. class InputReport:
  189. Buttons = 2 #2 to 8 not implemented yet !!! only IR is implemented
  190. Status = 4
  191. ReadData = 5
  192. ButtonsExtension = 6
  193. class Wiimote(threading.Thread):
  194. state = None
  195. running = False
  196. WiimoteState = WiimoteState
  197. InputReport = InputReport
  198. gyroCalibration = [] # ZDR
  199. packet_number = 0
  200. packet_time = 0
  201. def __init__(self):
  202. threading.Thread.__init__(self)
  203. self.parser = Parser()
  204. self.setter = Setter()
  205. self.IRCallback = None
  206. def Connect(self, device):
  207. self.bd_addr = device[0]
  208. self.name = device[1]
  209. self.controlsocket = bluetooth.BluetoothSocket(bluetooth.L2CAP)
  210. try:
  211. self.controlsocket.connect((self.bd_addr,17))
  212. except:
  213. return False
  214. self.datasocket = bluetooth.BluetoothSocket(bluetooth.L2CAP)
  215. self.datasocket.connect((self.bd_addr,19))
  216. self.sendsocket = self.controlsocket
  217. self.CMD_SET_REPORT = 0x52
  218. if self.name == "Nintendo RVL-CNT-01-TR":
  219. self.CMD_SET_REPORT = 0xa2
  220. self.sendsocket = self.datasocket
  221. try:
  222. self.datasocket.settimeout(1)
  223. except NotImplementedError:
  224. print "socket timeout not implemented with this bluetooth module"
  225. print "Connected to ", self.bd_addr
  226. self._get_battery_status()
  227. self.start_time = datetime.now()
  228. #self.f = open('wiimote.log', 'w')
  229. #self.measurement_ended = False
  230. self.start() #start this thread
  231. return True
  232. def char_to_binary_string(self,char):
  233. ascii = ord(char)
  234. bin = []
  235. while (ascii > 0):
  236. if (ascii & 1) == 1:
  237. bin.append("1")
  238. else:
  239. bin.append("0")
  240. ascii = ascii >> 1
  241. bin.reverse()
  242. binary = "".join(bin)
  243. zerofix = (8 - len(binary)) * '0'
  244. return zerofix + binary
  245. def SetLEDs(self, led1,led2,led3,led4):
  246. self.WiimoteState.LEDState.LED1 = led1
  247. self.WiimoteState.LEDState.LED2 = led2
  248. self.WiimoteState.LEDState.LED3 = led3
  249. self.WiimoteState.LEDState.LED4 = led4
  250. self._send_data((0x11,self.setter.SetLEDs(self.WiimoteState.LEDState)))
  251. def run(self):
  252. print "starting"
  253. #i = 0
  254. self.running = True
  255. while self.running:
  256. try:
  257. x= map(ord,self.datasocket.recv(32))
  258. #t = datetime.now() - self.start_time
  259. #self.packet_time = t.seconds * 1000.0 + t.microseconds / 1000.0
  260. #if t_millis <= 60000.0:
  261. # self.f.write("Packet %i Zeit %f\n" % (self.i, t_millis))
  262. #elif not self.measurement_ended:
  263. # self.f.close()
  264. # print "Measurement ended"
  265. # self.measurement_ended = True
  266. #print "New Data %i" % self.i
  267. #self.packet_number = self.packet_number + 1
  268. except bluetooth.BluetoothError:
  269. continue
  270. self.state = ""
  271. for each in x[:17]:
  272. self.state += self.char_to_binary_string(chr(each)) + " "
  273. if len(x) >= 4:
  274. self.parser.parseButtons((x[2]<<8) + x[3], self.WiimoteState.ButtonState)
  275. #ZDR xyz = x[4:7]
  276. # 0x31: core buttons and accelerometer
  277. # 0x35: buttens accelerometer and extension data
  278. if len(x)>4 and (x[1]==0x31 or x[1]==0x35):
  279. # assume 10 bit precision
  280. ax,ay,az = [i<<2 for i in x[4:7]]
  281. #print ax-512,ay-512,az-512
  282. # add LSB from button values
  283. ax += x[2]>>5 & 0x3
  284. ay += x[3]>>4 & 0x2
  285. az += x[3]>>5 & 0x2
  286. self.parser.parseAccelerometer([ax,ay,az], self.WiimoteState.AccelState)
  287. # ZDR gyroscope data
  288. if len(x)>7 and x[1]==0x35:
  289. data = x[7:13]
  290. yaw = (data[3] & 0xfc)<<6 | data[0]
  291. roll = (data[4] & 0xfc)<<6 | data[1]
  292. pitch = (data[5] & 0xfc)<<6 | data[2]
  293. slow_mode_yaw = (data[3] & 0x2)>>1
  294. slow_mode_pitch = (data[3] & 0x1)
  295. slow_mode_roll = (data[4] & 0x2)>>1
  296. clen = 3000.0
  297. self.WiimoteState.GyroState.calibrated = True
  298. if self.WiimoteState.GyroState.calibrated==False and len(self.gyroCalibration)!=clen:
  299. self.gyroCalibration.append([yaw,roll,pitch])
  300. if len(self.gyroCalibration)==clen:
  301. # gc = self.gyroCalibration
  302. self.WiimoteState.GyroState.calibrated = True
  303. self.WiimoteState.GyroState.zero_yaw = sum([y for y,r,p in self.gyroCalibration])/clen
  304. self.WiimoteState.GyroState.zero_roll = sum([r for y,r,p in self.gyroCalibration])/clen
  305. self.WiimoteState.GyroState.zero_pitch = sum([p for y,r,p in self.gyroCalibration])/clen
  306. print self.WiimoteState.GyroState.zero_yaw
  307. print self.WiimoteState.GyroState.zero_roll
  308. print self.WiimoteState.GyroState.zero_pitch
  309. code.interact(local=locals())
  310. #print yaw, roll, pitch, slow_mode_yaw, slow_mode_roll, slow_mode_pitch,
  311. self.parser.parseGyro([yaw,roll,pitch], [slow_mode_yaw,slow_mode_roll,slow_mode_pitch], self.WiimoteState.GyroState)
  312. #print roll
  313. #if len(x) >= 19:
  314. # self.parser.parseIR(x[7:19],self.WiimoteState.IRState)
  315. # self.doIRCallback()
  316. #sleep(0.01)
  317. self.datasocket.close()
  318. self.controlsocket.close()
  319. print "Bluetooth socket closed succesfully."
  320. self.Dispose()
  321. print "stopping"
  322. def Dispose(self):
  323. self.Disconnect()
  324. def Disconnect(self):
  325. self.running = False
  326. self.WiimoteState.Battery = None
  327. def join(self):#will be called last...
  328. self.Dispose()
  329. def _send_data(self,data):
  330. str_data = ""
  331. for each in data:
  332. str_data += chr(each)
  333. self.sendsocket.send(chr(self.CMD_SET_REPORT) + str_data)
  334. def _write_to_mem(self, address, value):
  335. val = i2bs(value)
  336. val_len=len(val)
  337. val += [0]*(16-val_len)
  338. msg = [0x16] + i2bs(address) + [val_len] +val
  339. self._send_data(msg)
  340. def SetRumble(self,on):
  341. if on: self._send_data((0x11,0x01))
  342. else: self._send_data((0x11,0x00))
  343. def activate_IR(self, sens=6):
  344. self._send_data(i2bs(0x120033)) #mode IR
  345. self._send_data(i2bs(0x1304))#enable transmission
  346. self._send_data(i2bs(0x1a04))#enable transmission
  347. self.setIRSensitivity(sens)
  348. # ZDR
  349. def SetAccelerometerMode(self, mode=0x0):
  350. # see: http://wiibrew.org/wiki/Wiimote#Data_Reporting
  351. # set data reporting mode 0x31: (a1) 31 BB BB AA AA AA
  352. self._send_data((0x12,0x0,0x31))
  353. # ZDR
  354. def SetGyroMode(self):
  355. """ initialize motion plus the extension """
  356. self._write_to_mem(0x4A600FE,0x04)
  357. self._send_data((0x12,0x4,0x35))
  358. # ZDR
  359. def getAccelState(self):
  360. return (self.WiimoteState.AccelState.RawX - WiimoteState.AccelState.zeroX,
  361. self.WiimoteState.AccelState.RawY - WiimoteState.AccelState.zeroY,
  362. self.WiimoteState.AccelState.RawZ - WiimoteState.AccelState.zeroZ)
  363. # ZDR
  364. def calibrateAccelerometer(self):
  365. WiimoteState.AccelState.zeroX = self.WiimoteState.AccelState.RawX
  366. WiimoteState.AccelState.zeroY = self.WiimoteState.AccelState.RawY
  367. WiimoteState.AccelState.zeroZ = self.WiimoteState.AccelState.RawZ
  368. # ZDR
  369. def getGyroState(self, deg_scale=1./8192./200):
  370. return (self.WiimoteState.GyroState.int_yaw*deg_scale,
  371. self.WiimoteState.GyroState.int_roll*deg_scale,
  372. self.WiimoteState.GyroState.int_pitch*deg_scale)
  373. def calibrateGyro(self, yaw=None, roll=None, pitch=None):
  374. if yaw is not None:
  375. self.WiimoteState.GyroState.int_yaw = yaw
  376. if roll is not None:
  377. self.WiimoteState.GyroState.int_roll = roll
  378. if pitch is not None:
  379. self.WiimoteState.GyroState.int_pitch = pitch
  380. def setIRSensitivity(self, n):
  381. if n < 1 or n > 6:
  382. return
  383. self._write_to_mem(0x04b00030,0x08)
  384. time.sleep(0.1)
  385. if n == 1:
  386. self._write_to_mem(0x04b00000,0x0200007101006400fe)
  387. time.sleep(0.1)
  388. self._write_to_mem(0x04b0001a,0xfd05)
  389. elif n == 2:
  390. self._write_to_mem(0x04b00000,0x0200007101009600b4)
  391. time.sleep(0.1)
  392. self._write_to_mem(0x04b0001a,0xb304)
  393. elif n == 3:
  394. self._write_to_mem(0x04b00000,0x020000710100aa0064)
  395. time.sleep(0.1)
  396. self._write_to_mem(0x04b0001a,0x6303)
  397. elif n == 4:
  398. self._write_to_mem(0x04b00000,0x020000710100c80036)
  399. time.sleep(0.1)
  400. self._write_to_mem(0x04b0001a,0x3503)
  401. elif n == 5:
  402. self._write_to_mem(0x04b00000,0x070000710100720020)
  403. time.sleep(0.1)
  404. self._write_to_mem(0x04b0001a,0x1f03)
  405. # MAX
  406. elif n == 6:
  407. self._write_to_mem(0x04b00000,0x000000000000900041)
  408. time.sleep(0.1)
  409. self._write_to_mem(0x04b0001a,0x4000)
  410. time.sleep(0.1)
  411. self._write_to_mem(0x04b00033,0x33)
  412. def _get_battery_status(self):
  413. self._send_data((0x15,0x00))
  414. self.running2 = True
  415. while self.running2:
  416. try:
  417. x= map(ord,self.datasocket.recv(32))
  418. except bluetooth.BluetoothError:
  419. continue
  420. self.state = ""
  421. for each in x[:17]:
  422. if len(x) >= 7:
  423. self.running2 = False
  424. battery_level = x[7]
  425. self.WiimoteState.Battery = float(battery_level) / float(208)
  426. def setIRCallBack(self, func):
  427. self.IRCallback = func
  428. def doIRCallback(self):
  429. if self.IRCallback == None: return
  430. irstate = self.WiimoteState.IRState
  431. if irstate.Found1:
  432. self.IRCallback(irstate.RawX1, irstate.RawY1)
  433. elif irstate.Found2:
  434. self.IRCallback(irstate.RawX2, irstate.RawY2)
  435. elif irstate.Found3:
  436. self.IRCallback(irstate.RawX3, irstate.RawY3)
  437. elif irstate.Found4:
  438. self.IRCallback(irstate.RawX4, irstate.RawY4)
  439. if __name__ == "__main__":
  440. device = ('40:F4:07:C2:08:B9', 'Nintendo RVL-CNT-01-TR')
  441. print device
  442. connected = False
  443. wiimote = Wiimote()
  444. print "Press SYNC on wiimote to make it discoverable"
  445. while (not connected):
  446. connected = wiimote.Connect(device)
  447. leds = [False]*4
  448. for i in xrange(16):
  449. leds[i&0x3] = not leds[i&0x3]
  450. wiimote.SetLEDs(*leds);
  451. #time.sleep(0.1)
  452. #ZDR
  453. # see: http://wiibrew.org/wiki/Wiimote#Data_Reporting
  454. # If bit 2 (0x04) is set, the Wii Remote will send reports
  455. # whether there has been any change to the data or
  456. # not. Otherwise, the Wii Remote will only send an output
  457. # report when the data has changed. set data reporting mode
  458. # 0x31: (a1) 31 BB BB AA AA AA
  459. wiimote._send_data((0x12,0x4,0x31))
  460. #time.sleep(0.1)
  461. print wiimote.WiimoteState.AccelState.RawX, wiimote.WiimoteState.AccelState.RawY, wiimote.WiimoteState.AccelState.RawZ, wiimote.WiimoteState.ButtonState.A
  462. # 0x35: Core Buttons and Accelerometer with 16 Extension Bytes
  463. # (a1) 35 BB BB AA AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE
  464. # init motion plus: the extension is initialised by writing 0x55 to 0x(4)a600f0
  465. wiimote._write_to_mem(0x4A600FE,0x04)
  466. wiimote._send_data((0x12,0x4,0x35))
  467. code.interact(local=locals())
  468. while 1:
  469. print "%.2f\t%.2f\t%.2f" % wiimote.getGyroState()
  470. if wiimote.WiimoteState.ButtonState.A:
  471. wiimote.calibrateGyro(yaw=0, roll=0)
  472. #time.sleep(0.1)
  473. # wiimote._send_data((0x12,0x4,0x30))
  474. # wiimote.activate_IR()
  475. # while 1:
  476. # time.sleep(0.1)
  477. # #print wiimote.state
  478. # print wiimote.WiimoteState.ButtonState.A, wiimote.WiimoteState.ButtonState.B, wiimote.WiimoteState.ButtonState.Up, wiimote.WiimoteState.ButtonState.Down, wiimote.WiimoteState.ButtonState.Left, wiimote.WiimoteState.ButtonState.Right, wiimote.WiimoteState.ButtonState.Minus, wiimote.WiimoteState.ButtonState.Plus, wiimote.WiimoteState.ButtonState.Home, wiimote.WiimoteState.ButtonState.One, wiimote.WiimoteState.ButtonState.Two, wiimote.WiimoteState.IRState.RawX1, wiimote.WiimoteState.IRState.RawY1, wiimote.WiimoteState.IRState.Size1, wiimote.WiimoteState.IRState.RawX2, wiimote.WiimoteState.IRState.RawY2, wiimote.WiimoteState.IRState.Size2
  479. # #print wiimote.IRState.Found1