47 from wiiutils
import *
48 from wiimoteExceptions
import *
49 from wiimoteConstants
import *
55 Main class for Wiimote device interaction.
57 This class should be a singleton, or it should have
58 only class members/methods.
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
71 BATTERY_MAX = cwiid.BATTERY_MAX
74 _wiiCallbackStack =
None
86 _nunchukJoyOrig =
None
88 _LEDMasksOn = [LED1_ON, LED2_ON, LED3_ON, LED4_ON]
89 _LEDMasksOff = [0 | LED2_ON | LED3_ON | LED4_ON,
90 0 | LED1_ON | LED3_ON | LED4_ON,
91 0 | LED1_ON | LED2_ON | LED4_ON,
92 0 | LED1_ON | LED2_ON | LED3_ON]
94 def __init__(self, theSampleRate=0, wiiStateLock=None, gatherCalibrationStats=False):
96 Instantiate a Wiimote driver instance, which controls one physical Wiimote device.
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
110 for i
in range(NUM_ZEROING_READINGS):
130 self.
meanAcc = np.array([
None,
None,
None], dtype=np.float64)
133 self.
stdevAcc = np.array([
None,
None,
None], dtype=np.float64)
136 self.
varAcc = np.array([
None,
None,
None], dtype=np.float64)
139 self.
meanGyro = np.array([
None,
None,
None], dtype=np.float64)
142 self.
stdevGyro = np.array([
None,
None,
None], dtype=np.float64)
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.)")
153 self.
_wm = cwiid.Wiimote()
158 rospy.loginfo(
"Pairing successful.")
161 self.
_wm.enable(cwiid.FLAG_MOTIONPLUS)
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)
184 if (self.
_wm.state[
'ext_type'] == cwiid.EXT_NUNCHUK):
192 rospy.loginfo(
"Wiimote activated.")
215 """Wii's callback destination while zeroing the device."""
227 self.
_accList.append(thisState.accRaw)
234 self.
_gyroList.append(thisState.angleRate)
247 Find the at-rest values of the accelerometer and the gyro.
249 Collect NUM_ZEROING_READINGS readings of acc and gyro. Average them.
250 If the standard deviation of any of the six axes exceeds a threshold
251 that was determined empirically, then the calibration fails. Else
252 the gyro is biased to compensate for its at-rest offset. The offset
253 is the abs(mean(Gyro)).
255 The stdev thresholds are documented in wiimoteConstants.py.
257 Note that we always use the Wiimote's factory-installed zeroing data.
258 In the code below we nonetheless compute the stats for the
259 accelerometer, in case this behavior is to change in the future.
261 We sleep while the samples are taken. In order to prevent other
262 threads from reading bad values for mean/stdev, and variance,
263 we lock access to those vars.
284 wiistate.WIIState.setGyroCalibration([0, 0, 0])
285 wiistate.WIIState.setAccelerometerCalibration([0, 0, 0], [0, 0, 0])
302 if accWiiReading
is not None:
303 oneAccReading = accWiiReading.tuple()
304 accArrays.append(oneAccReading)
305 accArrays = np.reshape(accArrays, (-1, 3))
310 if (gyroReading
is not None):
311 oneGyroReading = gyroReading.tuple()
312 gyroArrays.append(oneGyroReading)
315 gyroArrays = np.reshape(gyroArrays, (-1, 3))
338 allData = np.append(accArrays, gyroArrays, axis=1)
341 thresholdsArray = THRESHOLDS_ARRAY
347 thresholdsArray = THRESHOLDS_ARRAY[0:3]
350 stdev = np.std(allData, axis=0)
355 isBadCalibration = (stdev > thresholdsArray).any()
360 if (isBadCalibration):
365 rospy.loginfo(
"Failed calibration; using questionable calibration anyway.")
366 wiistate.WIIState.setGyroCalibration(self.
meanGyro)
368 if (gyroCalibrationOrig
is not None):
369 rospy.loginfo(
"Failed calibration; retaining previous calibration.")
371 wiistate.WIIState.setGyroCalibration(gyroCalibrationOrig)
373 rospy.loginfo(
"Failed calibration; running without calibration now.")
378 wiistate.WIIState.setGyroCalibration(self.
meanGyro)
381 rospy.loginfo(
"Calibration successful.")
386 """Returns the most recent Wiistate instance. Provides proper locking."""
391 """Accessor that provides locking."""
396 """Accessor that provides locking."""
401 """Accessor that provides locking."""
406 """Accessor that provides locking."""
411 """Accessor that provides locking."""
416 """Accessor that provides locking."""
421 """Return the value of the given instance variable, providing locking service."""
426 if varName ==
"wiimoteState":
428 elif varName ==
"meanAcc":
430 elif varName ==
"stdevAcc":
432 elif varName ==
"varAcc":
434 elif varName ==
"meanGyro":
436 elif varName ==
"stdevGyro":
438 elif varName ==
"varGyro":
441 raise ValueError(
"Instance variable name " + str(varName) +
"is not under lock control.")
448 """Start of stop rumble (i.e. vibration). 1: start; 0: stop"""
449 self.
_wm.rumble = switchPos
455 return self.
_wm.state[
'rumble']
460 """Set the four Wii LEDs according to statusList
462 statusList must be a 4-tuple. Each entry
463 is either True/1, False/0, or None. True (or 1)
464 will turn the respective LED on; False (or 0)
465 turns it off, and None leaves the state unchanged.
469 currLEDs = self.
getLEDs(asInt=
True)
471 for LED
in range(len(statusList)):
476 elif statusList[LED]
is not None:
478 self.
_wm.led = currLEDs
481 """Get the status of the four Wii LEDs.
483 Return value depends on the asInt parameter:
484 if asInt=False, the method returns a 4-tuple.
485 Each entry is either True or False. True indicates
486 that the respective LED is on; False means off.
487 If asInt=True, return value is a bit vector
488 indicating which LEDs are on.
492 LEDs = self.
_wm.state[
'led']
519 """Obtain battery state from Wiimote.
521 Maximum charge is BATTERY_MAX.
524 return self.
_wm.state[
'battery']
527 """Returns currently operative accelerometer calibration.
529 Return value: tuple with calibration for zero reading, and
530 calibration or a '1' reading.
532 return wiistate.WIIState.getAccelerometerCalibration()
535 """Obtain calibration data from accelerometer.
537 Retrieve factory-installed calibration data for
538 the Wiimote's accelerometer. Returns a two-tuple
539 with the calibration numbers for zero and one:
546 factoryCalNums = self.
_wm.get_acc_cal(cwiid.EXT_NONE)
548 return (factoryCalNums[0], factoryCalNums[1])
551 """Obtain calibration data from nunchuk accelerometer.
553 Retrieve factory-installed calibration data for
554 the Nunchuk's accelerometer. Returns a two-tuple
555 with the calibration numbers for zero and one:
558 factoryCalNums = self.
_wm.get_acc_cal(cwiid.EXT_NUNCHUK)
559 return (factoryCalNums[0], factoryCalNums[1])
562 wiistate.WIIState.setAccelerometerCalibration(np.array(zeroReadingList), np.array(oneReadingList))
565 wiistate.WIIState.setAccelerometerCalibration(zeroReadingNPArray, oneReadingNPArray)
568 """Return current Gyro zeroing offsets as list x/y/z."""
569 return wiistate.WIIState.getGyroCalibration()
572 wiistate.WIIState.setGyroCalibration(gyroTriplet)
575 wiistate.WIIState.setNunchukAccelerometerCalibration(np.array(zeroReadingList), np.array(oneReadingList))
578 """Return True/False to indicate whether a Wiimotion Plus is detected.
580 Note: The return value is accurate only after at least one
581 Wiimote state has been read. This means that either
582 _steadyStateCallback or _calibrationCallback must have
591 """Return True/False to indicate whether a Nunchuk is detected.
593 Note: The return value is accurate only after at least one
594 Wiimote state has been read. This means that either
595 _steadyStateCallback or _calibrationCallback must have
604 """Compute mean and stdev for accelerometer data list self._accList in both Gs and metric m/sec^2"""
607 self.
maxAccReading = np.array([0, 0, 0], dtype=
None, copy=1, order=
None, subok=0, ndmin=0)
609 if accWiiReading
is not None:
610 oneAccReading = accWiiReading.tuple()
611 accArrays.append(oneAccReading)
621 self.
meanAcc = np.vstack(accArrays).mean(axis=0)
628 """Compute mean and stdev for gyro data list self._gyroList in both Gs and metric m/sec^2"""
632 if (gyroReading
is not None):
633 oneGyroReading = gyroReading.tuple()
634 gyroArrays.append(oneGyroReading)
637 if len(gyroArrays) != 0:
638 self.
meanGyro = np.vstack(gyroArrays).mean(axis=0)
655 Class organizes installation and removal/restoration
656 of callback functions for the Wii driver to use.
657 Only one instance of this class is allowed. Additional
658 instantiations generate a CallbackStackMultInstError.
660 A stack discipline is imposed. Operations:
662 - push(<callBackFunc>) # New function becomes the active
663 # callback immediately
664 - pop() -> <oldCallBackFunc> # If another function is still on
665 # the stack, it immediately becomes
666 # the active callback. If callback
667 # is paused, resume() is forced.
668 - pause() # Callbacks are temporarily turned off
669 - paused() -> True/False
670 - resume(sloppy=True) # If sloppy=False, resuming when
671 # callbacks are not paused throws an
672 # exception. If sloppy=True, the call is
677 _singletonInstance =
None
692 """Given function becomes the new WIImote callback function, shadowing
693 the function that is currently on the stack
700 """Wiimote callback function is popped off the stack. New top of stack
701 becomes the new callback function. Old function is returned.
712 """WIIMote callbacks are temporarily stopped."""
714 self.
_wm.disable(cwiid.FLAG_MESG_IFC)
718 """Resume the (presumably) previously paused WIIMote callback functions.
719 If sloppy is True, this method won't complain if pause was not
720 called earlier. If sloppy is False, an exception is raised in
733 self._wiiCallbackStack(_functionStack.index[-1])
736 """Tell WIIMote which function to call when reporting status."""
738 self.
_wm.mesg_callback = f
739 self.
_wm.enable(cwiid.FLAG_MESG_IFC)