WIIMote.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # ###############################################################################
3 #
4 # File: WIIMote.py
5 # RCS: $Header: $
6 # Description: Top Level Wii Remote Control
7 # Author: Andreas Paepcke
8 # Created: Thu Aug 13 09:00:27 2009
9 # Modified: Fri Jan 14 10:48:48 2011 (Andreas Paepcke) paepcke@bhb.willowgarage.com
10 # Language: Python
11 # Package: N/A
12 # Status: Experimental (Do Not Distribute)
13 #
14 #
15 # ###############################################################################
16 #
17 # Revisions:
18 #
19 # Fri Jan 14 10:48:11 2011 (Andreas Paepcke) paepcke@bhb.willowgarage.com
20 # Added warning to ignore error messages when neither Nunchuk nor WiimotePlus
21 # are present.
22 # Thu Jan 13 17:29:06 2011 (Andreas Paepcke) paepcke@bhb.willowgarage.com
23 # Added shutdown exception guard in getRumble()
24 # Thu Sep 10 10:27:38 2009 (Andreas Paepcke) paepcke@anw.willowgarage.com
25 # Added option to lock access to wiiMoteState instance variable.
26 # Thu Mar 18 10:56:09 2010 (David Lu) davidlu@wustl.edu
27 # Enabled nunchuk reports
28 # Fri Oct 29 08:58:21 2010 (Miguel Angel Julian Aguilar, QBO Project) miguel.angel@thecorpora.com
29 # Enabled classic controller reports
30 # Mon Nov 08 11:44:39 2010 (David Lu) davidlu@wustl.edu
31 # Added nunchuk calibration
32 # ###############################################################################
33 
34 import operator
35 import time
36 import sys
37 import threading
38 from math import *
39 import tempfile
40 import os
41 
42 import rospy
43 
44 import numpy as np
45 import cwiid
46 
47 from wiiutils import *
48 from wiimoteExceptions import *
49 from wiimoteConstants import *
50 import wiistate
51 
52 
53 class WIIMote(object):
54  """
55  Main class for Wiimote device interaction.
56 
57  This class should be a singleton, or it should have
58  only class members/methods.
59 
60  Public Data attributes:
61  wiiMoteState WIIState object that holds the latest sampled state
62  sampleRate Control Wiimote state samples to take per second
63  meanAcc Triplet with mean of accelerator at rest
64  stdevAcc Triplet with standard deviation of accelerator at rest
65  meanGyro Triplet with mean of gyro (angular rate) at rest
66  stdevGyro Triplet with standard deviation gyro (angular rate) at rest
67 
68  Public Methods:
69 
70  """
71  BATTERY_MAX = cwiid.BATTERY_MAX # 208 a.k.a. 0xD0
72 
73  _wm = None # WIIMote object
74  _wiiCallbackStack = None # Stack for directing Wii driver callbacks
75 
76  _startTime = None # Used for state sampling
77  _accList = None # Collecting accelerator readings for zeroing and others
78  _gyroList = None
79  _readingsCnt = None # For counting how many readings were taken
80  _accTotal = None # Summed up acc readings in one AccReading instance
81  _gyroTotal = None # Summed up gyro readings in one AccReading instance
82 
83  _accNormal = None # Readings of accelerometer at rest
84  _gyroNormal = None # Readings of gyro at rest
85 
86  _nunchukJoyOrig = None # Initial Reading of the nunchuk's joystick
87 
88  _LEDMasksOn = [LED1_ON, LED2_ON, LED3_ON, LED4_ON] # OR to turn on
89  _LEDMasksOff = [0 | LED2_ON | LED3_ON | LED4_ON, # AND to turn off
90  0 | LED1_ON | LED3_ON | LED4_ON,
91  0 | LED1_ON | LED2_ON | LED4_ON,
92  0 | LED1_ON | LED2_ON | LED3_ON]
93 
94  def __init__(self, theSampleRate=0, wiiStateLock=None, gatherCalibrationStats=False):
95  """
96  Instantiate a Wiimote driver instance, which controls one physical Wiimote device.
97 
98  Parameters:
99  theSampleRate: How often to update the instance's wiiMoteState variable:
100  theSampleRate= -1: never
101  theSampleRate= 0: as often as possible
102  theSampleRate= x: every x seconds
103  """
104 
105  self.lastZeroingTime = 0.
106 
107  self.gatherCalibrationStats = gatherCalibrationStats
108  if (self.gatherCalibrationStats):
110  for i in range(NUM_ZEROING_READINGS):
112 
113  # Create a threading.Lock instance.
114  # The instance variable wiiMoteState is only updated after acquiring that
115  # lock. This is true for both reading and writing. The same is
116  # true for accesses to: meanAcc, stdevAcc, varAcc, stdevGyro, and varGyro
117  # All such accesses happen w/in this class, b/c we have accessors for
118  # these variables. The lock is used also in method zeroDevice() as
119  # well, to prevent other threads from retrieving bad values between
120  # the time zeroDevice() begins and ends:
121 
122  self.wiiStateLock = threading.Lock()
123  self.wiiMoteState = None # Object holding a snapshot of the Wiimote state
124  self.sampleRate = -1 # How often to update wiiMoteState
125  # -1: Never
126  # 0: Everytime the underlying system offers state
127  # else: (Possibly fractional) seconds between updates
128 
129  # Mean x/y/z of most recent accelerometer zeroing in Gs and metric:
130  self.meanAcc = np.array([None, None, None], dtype=np.float64)
131  self.meanAccMetric = np.array([None, None, None], dtype=np.float64)
132  # Stdev x/y/z of most recent accelerometer zeroing in Gs and metric:
133  self.stdevAcc = np.array([None, None, None], dtype=np.float64)
134  self.stdevAccMetric = np.array([None, None, None], dtype=np.float64)
135  # Variance x/y/z of most recent accelerometer zeroing
136  self.varAcc = np.array([None, None, None], dtype=np.float64)
137 
138  # Mean x/y/z of most recent gyro zeroing in Gs and metric:
139  self.meanGyro = np.array([None, None, None], dtype=np.float64)
140  self.meanGyroMetric = np.array([None, None, None], dtype=np.float64)
141  # Stdev x/y/z of most recent gyro zeroing in Gs and metric:
142  self.stdevGyro = np.array([None, None, None], dtype=np.float64)
143  self.stdevGyroMetric = np.array([None, None, None], dtype=np.float64)
144  # Variance x/y/z of most recent gyro zeroing
145  self.varGyroMetric = np.array([None, None, None], dtype=np.float64)
146 
148 
149  promptUsr("Press buttons 1 and 2 together to pair (within 6 seconds).\n "
150  "(If no blinking lights, press power button for ~3 seconds.)")
151 
152  try:
153  self._wm = cwiid.Wiimote()
154  except RuntimeError:
155  raise WiimoteNotFoundError("No Wiimote found to pair with.")
156  exit()
157 
158  rospy.loginfo("Pairing successful.")
159 
160  try:
161  self._wm.enable(cwiid.FLAG_MOTIONPLUS)
162  except RuntimeError:
163  raise WiimoteEnableError("Found Wiimote, but could not enable it.")
164  exit
165 
166  self.sampleRate = theSampleRate
167  self._startTime = getTimeStamp()
168 
170 
171  # Enable reports from the WII:
172  self._wm.rpt_mode = (cwiid.RPT_ACC | cwiid.RPT_MOTIONPLUS |
173  cwiid.RPT_BTN | cwiid.RPT_IR |
174  cwiid.RPT_NUNCHUK | cwiid.RPT_CLASSIC)
175 
176  # Set accelerometer calibration to factory defaults:
177  (factoryZero, factoryOne) = self.getAccFactoryCalibrationSettings()
178  self.setAccelerometerCalibration(factoryZero, factoryOne)
179 
180  # Initialize Gyro zeroing to do nothing:
181  self.setGyroCalibration([0, 0, 0])
182 
183  # Set nunchuk calibration to factory defaults.
184  if (self._wm.state['ext_type'] == cwiid.EXT_NUNCHUK):
185  try:
186  (factoryZero, factoryOne) = self.getNunchukFactoryCalibrationSettings()
187  self.setNunchukAccelerometerCalibration(factoryZero, factoryOne)
188  except:
189  pass
190 
191  time.sleep(0.2)
193 
194  rospy.loginfo("Wiimote activated.")
195 
196  def _steadyStateCallback(self, state, theTime):
197  now = getTimeStamp()
198  if now - self._startTime >= self.sampleRate:
199  # If this Wiimote driver is to synchronize write
200  # access to the wii state variable (which is read from
201  # outside), then acquire the lock that was provided
202  # by the instantiator of this instance:
203  if self.wiiStateLock is not None:
204  self.wiiStateLock.acquire()
205  try:
206  self.wiiMoteState = wiistate.WIIState(state, theTime, self.getRumble(), self._wm.state['buttons'])
207  except ValueError:
208  # A 'Wiimote is closed' error can occur as a race condition
209  # as threads close down after a Cnt-C. Catch those and
210  # ignore:
211  pass
212  if self.wiiStateLock is not None:
213  self.wiiStateLock.release()
214  self._startTime = now
215 
216  def _calibrationCallback(self, state, theTime):
217  """Wii's callback destination while zeroing the device."""
218 
219  self._warmupCnt += 1
220  if self._warmupCnt < NUM_WARMUP_READINGS:
221  return
222 
223  if self._readingsCnt >= NUM_ZEROING_READINGS:
224  return
225 
226  thisState = wiistate.WIIState(state, theTime, self.getRumble(), self._wm.state['buttons'])
227 
228  # Pull out the accelerometer x,y,z, accumulate in a list:
229  self._accList.append(thisState.accRaw)
230 
231  # Pull out the gyro x,y,z, and build a GyroReading from them.
232  # For a few cycles, the Wiimote does not deliver gyro info.
233  # When it doesn't, we get a 'None' is unsubscriptable. Ignore
234  # those initial instabilities:
235  try:
236  self._gyroList.append(thisState.angleRate)
237  except TypeError:
238  pass
239  self._readingsCnt += 1
240 
241  if thisState.nunchukPresent and self._nunchukJoyOrig is None:
242  self._nunchukJoyOrig = thisState.nunchukStickRaw
243  wiistate.WIIState.setNunchukJoystickCalibration(self._nunchukJoyOrig)
244 
245  return
246 
247  def zeroDevice(self):
248  """
249  Find the at-rest values of the accelerometer and the gyro.
250 
251  Collect NUM_ZEROING_READINGS readings of acc and gyro. Average them.
252  If the standard deviation of any of the six axes exceeds a threshold
253  that was determined empirically, then the calibration fails. Else
254  the gyro is biased to compensate for its at-rest offset. The offset
255  is the abs(mean(Gyro)).
256 
257  The stdev thresholds are documented in wiimoteConstants.py.
258 
259  Note that we always use the Wiimote's factory-installed zeroing data.
260  In the code below we nonetheless compute the stats for the
261  accelerometer, in case this behavior is to change in the future.
262 
263  We sleep while the samples are taken. In order to prevent other
264  threads from reading bad values for mean/stdev, and variance,
265  we lock access to those vars.
266  """
267 
268  self._accList = [] # Calibration callback will put samples here (WIIReading()s)
269  self._gyroList = [] # Calibration callback will put samples here (WIIReading()s)
270  self._readingsCnt = 0
271  self._warmupCnt = 0
272  # The factory calibration setting for the accelerometer (two values in a tuple):
273  accCalibrationOrig = self.getAccelerometerCalibration()
274  gyroCalibrationOrig = self.getGyroCalibration()
275  accArrays = [] # Place to put raw reading triplets
276  gyroArrays = [] # Place to put raw reading triplets
277 
278  try:
279  # Get the samples for accelerometer and gyro:
280  self.wiiStateLock.acquire()
281 
283 
284  # Wipe out previous calibration correction data
285  # while we gather raw samples:
286  wiistate.WIIState.setGyroCalibration([0, 0, 0])
287  wiistate.WIIState.setAccelerometerCalibration([0, 0, 0], [0, 0, 0])
288 
289  while (self._readingsCnt < NUM_ZEROING_READINGS) or (self._warmupCnt < NUM_WARMUP_READINGS):
290  time.sleep(.1)
291 
292  self._wiiCallbackStack.pause()
293  finally:
294  # Restore the callback that was in force before zeroing:
295  self._wiiCallbackStack.pop()
296  self.wiiStateLock.release()
297 
298  # Compute and store basic statistics about the readings:
299  self.computeAccStatistics()
300  self.computeGyroStatistics()
301 
302  # Extract the accelerometer reading triplets from the list of WIIReading()s:
303  for accWiiReading in self._accList:
304  if accWiiReading is not None:
305  oneAccReading = accWiiReading.tuple()
306  accArrays.append(oneAccReading)
307  accArrays = np.reshape(accArrays, (-1, 3))
308 
309  # Extract the gyro reading triplets from the list of WIIReading()s:
310  if (self.motionPlusPresent()):
311  for gyroReading in self._gyroList:
312  if (gyroReading is not None):
313  oneGyroReading = gyroReading.tuple()
314  gyroArrays.append(oneGyroReading)
315 
316  if (self.motionPlusPresent()):
317  gyroArrays = np.reshape(gyroArrays, (-1, 3))
318 
319  # We now have:
320  # [[accX1, accZ1, accZ1]
321  # [accX2, accZ2, accZ2]
322  # ...
323  # ]
324  #
325  # and:
326  #
327  # [[gyroX1, gyroZ1, gyroZ1]
328  # [gyroX2, gyroZ2, gyroZ2]
329  # ...
330  # ]
331  #
332  # Combine all into:
333  #
334  # [[accX1, accZ1, accZ1, gyroX1, gyroZ1, gyroZ1]
335  # [accX2, accZ2, accZ2, gyroX2, gyroZ2, gyroZ2]
336  # ...
337  # ]
338  #
339 
340  allData = np.append(accArrays, gyroArrays, axis=1)
341  # Will compare both, accelerometer x/y/z, and gyro x/y/z
342  # to their stdev threshold to validate calibration:
343  thresholdsArray = THRESHOLDS_ARRAY
344  else:
345  allData = accArrays
346  # Will compare only accelerometer x/y/z to their stdev
347  # threshold to validate calibration. No Wiimote+ was
348  # detected:
349  thresholdsArray = THRESHOLDS_ARRAY[0:3]
350 
351  # And take the std deviations column-wise:
352  stdev = np.std(allData, axis=0)
353 
354  # See whether any of the six stdevs exceeds the
355  # calibration threshold:
356 
357  isBadCalibration = (stdev > thresholdsArray).any()
358 
359  # We always use the factory-installed calibration info,
360  self.setAccelerometerCalibration(accCalibrationOrig[0], accCalibrationOrig[1])
361 
362  if (isBadCalibration):
363  self.latestCalibrationSuccessful = False
364  # We can calibrate the Wiimote anyway, if the preference
365  # constant in wiimoteConstants.py is set accordingly:
366  if (CALIBRATE_WITH_FAILED_CALIBRATION_DATA and self.motionPlusPresent()):
367  rospy.loginfo("Failed calibration; using questionable calibration anyway.")
368  wiistate.WIIState.setGyroCalibration(self.meanGyro)
369  else:
370  if (gyroCalibrationOrig is not None):
371  rospy.loginfo("Failed calibration; retaining previous calibration.")
372  if (self.motionPlusPresent()):
373  wiistate.WIIState.setGyroCalibration(gyroCalibrationOrig)
374  else:
375  rospy.loginfo("Failed calibration; running without calibration now.")
376  return False
377 
378  # Do WIIState's gyro zero reading, so that future
379  # readings can be corrected when a WIIState is created:
380  wiistate.WIIState.setGyroCalibration(self.meanGyro)
381 
383  rospy.loginfo("Calibration successful.")
384  self.latestCalibrationSuccessful = True
385  return True
386 
387  def getWiimoteState(self):
388  """Returns the most recent Wiistate instance. Provides proper locking."""
389 
390  return self._getInstanceVarCriticalSection("wiimoteState")
391 
393  """Accessor that provides locking."""
394 
395  return self._getInstanceVarCriticalSection("meanAcc")
396 
398  """Accessor that provides locking."""
399 
400  return self._getInstanceVarCriticalSection("stdevAcc")
401 
403  """Accessor that provides locking."""
404 
405  return self._getInstanceVarCriticalSection("varAcc")
406 
407  def getMeanGyro(self):
408  """Accessor that provides locking."""
409 
410  return self._getInstanceVarCriticalSection("meanGyro")
411 
412  def getStdevGyro(self):
413  """Accessor that provides locking."""
414 
415  return self._getInstanceVarCriticalSection("stdevGyro")
416 
417  def getVarianceGyro(self):
418  """Accessor that provides locking."""
419 
420  return self._getInstanceVarCriticalSection("varGyro")
421 
422  def _getInstanceVarCriticalSection(self, varName):
423  """Return the value of the given instance variable, providing locking service."""
424 
425  try:
426  self.wiiStateLock.acquire()
427 
428  if varName == "wiimoteState":
429  res = self.wiiMoteState
430  elif varName == "meanAcc":
431  res = self.meanAcc
432  elif varName == "stdevAcc":
433  res = self.stdevAcc
434  elif varName == "varAcc":
435  res = self.varAcc
436  elif varName == "meanGyro":
437  res = self.meanGyro
438  elif varName == "stdevGyro":
439  res = self.stdevGyro
440  elif varName == "varGyro":
441  res = self.varGyroMetric
442  else:
443  raise ValueError("Instance variable name " + str(varName) + "is not under lock control.")
444 
445  finally:
446  self.wiiStateLock.release()
447  return res
448 
449  def setRumble(self, switchPos):
450  """Start of stop rumble (i.e. vibration). 1: start; 0: stop"""
451  self._wm.rumble = switchPos
452 
453  def getRumble(self):
454  # Protect against reading exception from reading
455  # from an already closed device during shutdown:
456  try:
457  return self._wm.state['rumble']
458  except ValueError:
459  pass
460 
461  def setLEDs(self, statusList):
462  """Set the four Wii LEDs according to statusList
463 
464  statusList must be a 4-tuple. Each entry
465  is either True/1, False/0, or None. True (or 1)
466  will turn the respective LED on; False (or 0)
467  turns it off, and None leaves the state unchanged.
468 
469  """
470 
471  currLEDs = self.getLEDs(asInt=True)
472  # Cycle through each LED:
473  for LED in range(len(statusList)):
474  # Should this LED be on?
475  if statusList[LED]:
476  currLEDs = currLEDs | self._LEDMasksOn[LED]
477  # Is this LED to be OFF? (if not, leave it alone)
478  elif statusList[LED] is not None:
479  currLEDs = currLEDs & self._LEDMasksOff[LED]
480  self._wm.led = currLEDs
481 
482  def getLEDs(self, asInt=False):
483  """Get the status of the four Wii LEDs.
484 
485  Return value depends on the asInt parameter:
486  if asInt=False, the method returns a 4-tuple.
487  Each entry is either True or False. True indicates
488  that the respective LED is on; False means off.
489  If asInt=True, return value is a bit vector
490  indicating which LEDs are on.
491 
492  """
493 
494  LEDs = self._wm.state['led']
495  if asInt:
496  return LEDs
497  res = []
498  if LEDs & LED1_ON:
499  res.append(True)
500  else:
501  res.append(False)
502 
503  if LEDs & LED2_ON:
504  res.append(True)
505  else:
506  res.append(False)
507 
508  if LEDs & LED3_ON:
509  res.append(True)
510  else:
511  res.append(False)
512 
513  if LEDs & LED4_ON:
514  res.append(True)
515  else:
516  res.append(False)
517 
518  return res
519 
520  def getBattery(self):
521  """Obtain battery state from Wiimote.
522 
523  Maximum charge is BATTERY_MAX.
524  """
525 
526  return self._wm.state['battery']
527 
529  """Returns currently operative accelerometer calibration.
530 
531  Return value: tuple with calibration for zero reading, and
532  calibration or a '1' reading.
533  """
534  return wiistate.WIIState.getAccelerometerCalibration()
535 
537  """Obtain calibration data from accelerometer.
538 
539  Retrieve factory-installed calibration data for
540  the Wiimote's accelerometer. Returns a two-tuple
541  with the calibration numbers for zero and one:
542 
543  """
544 
545  # Parameter is the Wiimote extension from which
546  # the calibration is to be retrieved.
547 
548  factoryCalNums = self._wm.get_acc_cal(cwiid.EXT_NONE)
549 
550  return (factoryCalNums[0], factoryCalNums[1])
551 
553  """Obtain calibration data from nunchuk accelerometer.
554 
555  Retrieve factory-installed calibration data for
556  the Nunchuk's accelerometer. Returns a two-tuple
557  with the calibration numbers for zero and one:
558 
559  """
560  factoryCalNums = self._wm.get_acc_cal(cwiid.EXT_NUNCHUK)
561  return (factoryCalNums[0], factoryCalNums[1])
562 
563  def setAccelerometerCalibration(self, zeroReadingList, oneReadingList):
564  wiistate.WIIState.setAccelerometerCalibration(np.array(zeroReadingList), np.array(oneReadingList))
565 
566  def setAccelerometerCalibration(self, zeroReadingNPArray, oneReadingNPArray):
567  wiistate.WIIState.setAccelerometerCalibration(zeroReadingNPArray, oneReadingNPArray)
568 
570  """Return current Gyro zeroing offsets as list x/y/z."""
571  return wiistate.WIIState.getGyroCalibration()
572 
573  def setGyroCalibration(self, gyroTriplet):
574  wiistate.WIIState.setGyroCalibration(gyroTriplet)
575 
576  def setNunchukAccelerometerCalibration(self, zeroReadingList, oneReadingList):
577  wiistate.WIIState.setNunchukAccelerometerCalibration(np.array(zeroReadingList), np.array(oneReadingList))
578 
579  def motionPlusPresent(self):
580  """Return True/False to indicate whether a Wiimotion Plus is detected.
581 
582  Note: The return value is accurate only after at least one
583  Wiimote state has been read. This means that either
584  _steadyStateCallback or _calibrationCallback must have
585  run at least once.
586  """
587  if (self.wiiMoteState is not None):
588  return self.wiiMoteState.motionPlusPresent
589  else:
590  return False
591 
592  def nunchukPresent(self):
593  """Return True/False to indicate whether a Nunchuk is detected.
594 
595  Note: The return value is accurate only after at least one
596  Wiimote state has been read. This means that either
597  _steadyStateCallback or _calibrationCallback must have
598  run at least once.
599  """
600  if (self.wiiMoteState is not None):
601  return self.wiiMoteState.nunchukPresent
602  else:
603  return False
604 
606  """Compute mean and stdev for accelerometer data list self._accList in both Gs and metric m/sec^2"""
607 
608  accArrays = []
609  self.maxAccReading = np.array([0, 0, 0], dtype=None, copy=1, order=None, subok=0, ndmin=0)
610  for accWiiReading in self._accList:
611  if accWiiReading is not None:
612  oneAccReading = accWiiReading.tuple()
613  accArrays.append(oneAccReading)
614  self.maxAccReading = np.maximum(self.maxAccReading, np.abs(oneAccReading))
615 
616  # Turn list of numpy triplets into three columns containing
617  # all x, all y, and all z values, respectively:
618  # [array(10,20,30), array(100,200,300)] ==> [[10 20 30],
619  # [100 200 300]]
620  # and take the means of each column. We will end up
621  # with: [55.0 110.0 165.0]
622 
623  self.meanAcc = np.vstack(accArrays).mean(axis=0)
624  self.meanAccMetric = self.meanAcc * EARTH_GRAVITY
625  self.stdevAcc = np.vstack(accArrays).std(axis=0)
626  self.stdevAccMetric = self.stdevAcc * EARTH_GRAVITY
627  self.varAcc = np.square(self.stdevAccMetric)
628 
630  """Compute mean and stdev for gyro data list self._gyroList in both Gs and metric m/sec^2"""
631  gyroArrays = []
632  self.maxGyroReading = np.array([0, 0, 0], dtype=np.float64)
633  for gyroReading in self._gyroList:
634  if (gyroReading is not None):
635  oneGyroReading = gyroReading.tuple()
636  gyroArrays.append(oneGyroReading)
637  self.maxGyroReading = np.maximum(self.maxGyroReading, np.abs(oneGyroReading))
638 
639  if len(gyroArrays) != 0:
640  self.meanGyro = np.vstack(gyroArrays).mean(axis=0)
641  # Convert to radians/sec:
642  self.meanGyroMetric = self.meanGyro * GYRO_SCALE_FACTOR
643  self.stdevGyro = np.vstack(gyroArrays).std(axis=0)
644  # Convert stdev to radians/sec:
645  self.stdevGyroMetric = self.stdevGyro * GYRO_SCALE_FACTOR
646  self.varGyroMetric = np.square(self.stdevGyroMetric)
647 
648  def printState(self):
649  log(self.wiiMoteState)
650 
651  def shutdown(self):
652  self._wm.close()
653 
654 
655 class _WiiCallbackStack(object):
656  """
657  Class organizes installation and removal/restoration
658  of callback functions for the Wii driver to use.
659  Only one instance of this class is allowed. Additional
660  instantiations generate a CallbackStackMultInstError.
661 
662  A stack discipline is imposed. Operations:
663 
664  - push(<callBackFunc>) # New function becomes the active
665  # callback immediately
666  - pop() -> <oldCallBackFunc> # If another function is still on
667  # the stack, it immediately becomes
668  # the active callback. If callback
669  # is paused, resume() is forced.
670  - pause() # Callbacks are temporarily turned off
671  - paused() -> True/False
672  - resume(sloppy=True) # If sloppy=False, resuming when
673  # callbacks are not paused throws an
674  # exception. If sloppy=True, the call is
675  # a no-op
676 
677  """
678  _functionStack = []
679  _singletonInstance = None # No instance exists yet.
680  _paused = False
681 
682  _wm = None # The Wii remote driver instance
683 
684  def __init__(self, wiiDriver, sloppy=True):
685 
686  if self._singletonInstance:
687  if not sloppy:
688  raise CallbackStackMultInstError("Can only instantiate one Wii callback stack.")
689 
690  self._singletonInstance = self
691  self._wm = wiiDriver
692 
693  def push(self, func):
694  """Given function becomes the new WIImote callback function, shadowing
695  the function that is currently on the stack
696  """
697 
698  self._functionStack.append(func)
699  self.setcallback(func)
700 
701  def pop(self):
702  """Wiimote callback function is popped off the stack. New top of stack
703  becomes the new callback function. Old function is returned.
704  """
705 
706  if not self._functionStack:
707  raise CallbackStackEmptyError("Attempt to pop empty callback stack")
708  _paused = False
709  func = self._functionStack.pop()
710  self.setcallback(self._functionStack[-1])
711  return func
712 
713  def pause(self):
714  """WIIMote callbacks are temporarily stopped."""
715 
716  self._wm.disable(cwiid.FLAG_MESG_IFC)
717  self._paused = True
718 
719  def resume(self, sloppy=True):
720  """Resume the (presumably) previously paused WIIMote callback functions.
721  If sloppy is True, this method won't complain if pause was not
722  called earlier. If sloppy is False, an exception is raised in
723  that case.
724  """
725 
726  if not self._paused:
727  if sloppy:
728  return
729  else:
730  raise ResumeNonPausedError("Can't resume without first pausing.")
731 
732  if not self._functionStack:
733  raise CallbackStackEmptyError("Attempt to pop empty callback stack")
734 
735  self._wiiCallbackStack(_functionStack.index[-1])
736 
737  def setcallback(self, f):
738  """Tell WIIMote which function to call when reporting status."""
739 
740  self._wm.mesg_callback = f
741  self._wm.enable(cwiid.FLAG_MESG_IFC)
742 
743 
745 
746  def __init__(self):
747  # runNum, meanAcc, maxAcc, stdevAcc, meanGyro, maxGyro, stdevGyro,
748  # accVal, devAccVal, stdevFractionAccVal, isOutlierAcc,
749  # gyroVal, devGyroVal, stdevFractionGyroVal, isOutlierGyro):
750 
751  pass
752 
753  def setAccData(self, accArray):
754  self.accVal = accArray
755 
756  def setStdevAcc(self, stdevArray):
757  self.stdevAcc = stdevArray
758 
759  def setMeanAcc(self, meanArray):
760  self.meanAcc = meanArray
761 
762  def setMaxAcc(self, maxArray):
763  self.maxAcc = maxArray
764 
765  def setGyroData(self, gyroArray):
766  self.gyroVal = gyroArray
767 
768  def setStdevGyro(self, stdevArray):
769  self.stdevGyro = stdevArray
770 
771  def setMeanGyro(self, meanArray):
772  self.meanGyro = meanArray
773 
774  def setMaxGyro(self, maxArray):
775  self.maxGyro = maxArray
776 
777  def setGyroData(self, gyroVal):
778  self.gyroVal = gyroVal
def __init__(self, wiiDriver, sloppy=True)
Definition: WIIMote.py:684
def printState(self)
Definition: WIIMote.py:648
def getLEDs(self, asInt=False)
Definition: WIIMote.py:482
def getMeanGyro(self)
Definition: WIIMote.py:407
def setStdevGyro(self, stdevArray)
Definition: WIIMote.py:768
def _getInstanceVarCriticalSection(self, varName)
Definition: WIIMote.py:422
def getTimeStamp()
Definition: wiiutils.py:44
def getNunchukFactoryCalibrationSettings(self)
Definition: WIIMote.py:552
def setGyroData(self, gyroArray)
Definition: WIIMote.py:765
def getStdevGyro(self)
Definition: WIIMote.py:412
def getWiimoteState(self)
Definition: WIIMote.py:387
def getStdevAccelerator(self)
Definition: WIIMote.py:397
def setRumble(self, switchPos)
Definition: WIIMote.py:449
def getAccelerometerCalibration(self)
Definition: WIIMote.py:528
def getVarianceGyro(self)
Definition: WIIMote.py:417
def log(str, file=None)
Definition: wiiutils.py:33
def nunchukPresent(self)
Definition: WIIMote.py:592
def setMeanGyro(self, meanArray)
Definition: WIIMote.py:771
def zeroDevice(self)
Definition: WIIMote.py:247
def setGyroCalibration(self, gyroTriplet)
Definition: WIIMote.py:573
def getBattery(self)
Definition: WIIMote.py:520
def promptUsr(str)
Definition: wiiutils.py:38
def getAccFactoryCalibrationSettings(self)
Definition: WIIMote.py:536
def getGyroCalibration(self)
Definition: WIIMote.py:569
def _steadyStateCallback(self, state, theTime)
Definition: WIIMote.py:196
def setStdevAcc(self, stdevArray)
Definition: WIIMote.py:756
def getMeanAccelerator(self)
Definition: WIIMote.py:392
def _calibrationCallback(self, state, theTime)
Definition: WIIMote.py:216
def setMeanAcc(self, meanArray)
Definition: WIIMote.py:759
def setAccelerometerCalibration(self, zeroReadingList, oneReadingList)
Definition: WIIMote.py:563
def computeAccStatistics(self)
Definition: WIIMote.py:605
def computeGyroStatistics(self)
Definition: WIIMote.py:629
def setNunchukAccelerometerCalibration(self, zeroReadingList, oneReadingList)
Definition: WIIMote.py:576
def __init__(self, theSampleRate=0, wiiStateLock=None, gatherCalibrationStats=False)
Definition: WIIMote.py:94
def getVarianceAccelerator(self)
Definition: WIIMote.py:402
def setLEDs(self, statusList)
Definition: WIIMote.py:461
def motionPlusPresent(self)
Definition: WIIMote.py:579
def resume(self, sloppy=True)
Definition: WIIMote.py:719


wiimote
Author(s): Andreas Paepcke, Melonee Wise, Mark Horn
autogenerated on Mon Feb 28 2022 22:37:04