56 from wiiutils
import *
57 from wiimoteExceptions
import *
58 from wiimoteConstants
import *
78 """Main class for Wiimote device interaction. 80 This class should be a singleton, or it should have 81 only class members/methods. 83 Public Data attributes: 84 wiiMoteState WIIState object that holds the latest sampled state 85 sampleRate Control Wiimote state samples to take per second 86 meanAcc Triplet with mean of accelerator at rest 87 stdevAcc Triplet with standard deviation of accelerator at rest 88 meanGyro Triplet with mean of gyro (angular rate) at rest 89 stdevGyro Triplet with standard deviation gyro (angular rate) at rest 98 BATTERY_MAX = cwiid.BATTERY_MAX
109 _wiiCallbackStack =
None 122 _nunchukJoyOrig =
None 124 _LEDMasksOn = [LED1_ON, LED2_ON, LED3_ON, LED4_ON]
125 _LEDMasksOff = [0 | LED2_ON | LED3_ON | LED4_ON,
126 0 | LED1_ON | LED3_ON | LED4_ON,
127 0 | LED1_ON | LED2_ON | LED4_ON,
128 0 | LED1_ON | LED2_ON | LED3_ON]
135 def __init__(self, theSampleRate=0, wiiStateLock=None, gatherCalibrationStats=False):
136 """Instantiate a Wiimote driver instance, which controls one physical Wiimote device. 139 theSampleRate: How often to update the instance's wiiMoteState variable: 140 theSampleRate= -1: never 141 theSampleRate= 0: as often as possible 142 theSampleRate= x: every x seconds 150 for i
in range(NUM_ZEROING_READINGS):
170 self.
meanAcc = np.array([
None,
None,
None],dtype=np.float64)
173 self.
stdevAcc = np.array([
None,
None,
None],dtype=np.float64)
176 self.
varAcc = np.array([
None,
None,
None],dtype=np.float64)
179 self.
meanGyro = np.array([
None,
None,
None],dtype=np.float64)
182 self.
stdevGyro = np.array([
None,
None,
None],dtype=np.float64)
189 promptUsr(
"Press buttons 1 and 2 together to pair (within 6 seconds).\n (If no blinking lights, press power button for ~3 seconds.)")
192 self.
_wm = cwiid.Wiimote()
197 rospy.loginfo(
"Pairing successful.")
200 self._wm.enable(cwiid.FLAG_MOTIONPLUS)
211 self._wm.rpt_mode = cwiid.RPT_ACC | cwiid.RPT_MOTIONPLUS | cwiid.RPT_BTN | cwiid.RPT_IR | cwiid.RPT_NUNCHUK | cwiid.RPT_CLASSIC
221 if (self._wm.state[
'ext_type'] == cwiid.EXT_NUNCHUK):
231 rospy.loginfo(
"Wiimote activated.")
247 self.wiiStateLock.acquire()
256 self.wiiStateLock.release()
264 """Wii's callback destination while zeroing the device.""" 276 self._accList.append(thisState.accRaw)
283 self._gyroList.append(thisState.angleRate)
299 """Find the at-rest values of the accelerometer and the gyro. 301 Collect NUM_ZEROING_READINGS readings of acc and gyro. Average them. 302 If the standard deviation of any of the six axes exceeds a threshold 303 that was determined empirically, then the calibration fails. Else 304 the gyro is biased to compensate for its at-rest offset. The offset 305 is the abs(mean(Gyro)). 307 The stdev thresholds are documented in wiimoteConstants.py. 309 Note that we always use the Wiimote's factory-installed zeroing data. 310 In the code below we nonetheless compute the stats for the 311 accelerometer, in case this behavior is to change in the future. 313 We sleep while the samples are taken. In order to prevent other 314 threads from reading bad values for mean/stdev, and variance, 315 we lock access to those vars. 330 self.wiiStateLock.acquire()
336 wiistate.WIIState.setGyroCalibration([0,0,0])
337 wiistate.WIIState.setAccelerometerCalibration([0,0,0], [0,0,0])
342 self._wiiCallbackStack.pause()
345 self._wiiCallbackStack.pop()
346 self.wiiStateLock.release()
354 if accWiiReading
is not None:
355 oneAccReading = accWiiReading.tuple()
356 accArrays.append(oneAccReading)
357 accArrays = np.reshape(accArrays, (-1,3))
362 if (gyroReading
is not None):
363 oneGyroReading = gyroReading.tuple()
364 gyroArrays.append(oneGyroReading)
367 gyroArrays = np.reshape(gyroArrays, (-1,3))
390 allData = np.append(accArrays, gyroArrays, axis=1)
393 thresholdsArray = THRESHOLDS_ARRAY
399 thresholdsArray = THRESHOLDS_ARRAY[0:3]
402 stdev = np.std(allData, axis=0)
407 isBadCalibration = (stdev > thresholdsArray).any()
412 if (isBadCalibration):
417 rospy.loginfo(
"Failed calibration; using questionable calibration anyway.")
418 wiistate.WIIState.setGyroCalibration(self.
meanGyro)
420 if (gyroCalibrationOrig
is not None):
421 rospy.loginfo(
"Failed calibration; retaining previous calibration.")
423 wiistate.WIIState.setGyroCalibration(gyroCalibrationOrig)
425 rospy.loginfo(
"Failed calibration; running without calibration now.")
435 wiistate.WIIState.setGyroCalibration(self.
meanGyro)
438 rospy.loginfo(
"Calibration successful.")
447 """Returns the most recent Wiistate instance. Provides proper locking.""" 456 """Accessor that provides locking.""" 465 """Accessor that provides locking.""" 474 """Accessor that provides locking.""" 483 """Accessor that provides locking.""" 492 """Accessor that provides locking.""" 501 """Accessor that provides locking.""" 511 """Return the value of the given instance variable, providing locking service.""" 514 self.wiiStateLock.acquire()
516 if varName ==
"wiimoteState":
518 elif varName ==
"meanAcc":
520 elif varName ==
"stdevAcc":
522 elif varName ==
"varAcc":
524 elif varName ==
"meanGyro":
526 elif varName ==
"stdevGyro":
528 elif varName ==
"varGyro":
531 raise ValueError(
"Instance variable name " + str(varName) +
"is not under lock control." )
534 self.wiiStateLock.release()
542 """Start of stop rumble (i.e. vibration). 1: start; 0: stop""" 543 self._wm.rumble = switchPos
554 return self._wm.state[
'rumble']
563 """Set the four Wii LEDs according to statusList 565 statusList must be a 4-tuple. Each entry 566 is either True/1, False/0, or None. True (or 1) 567 will turn the respective LED on; False (or 0) 568 turns it off, and None leaves the state unchanged. 572 currLEDs = self.
getLEDs(asInt=
True)
574 for LED
in range(len(statusList)):
579 elif statusList[LED]
is not None:
581 self._wm.led = currLEDs
589 """Get the status of the four Wii LEDs. 591 Return value depends on the asInt parameter: 592 if asInt=False, the method returns a 4-tuple. 593 Each entry is either True or False. True indicates 594 that the respective LED is on; False means off. 595 If asInt=True, return value is a bit vector 596 indicating which LEDs are on. 600 LEDs = self._wm.state[
'led']
631 """Obtain battery state from Wiimote. 633 Maximum charge is BATTERY_MAX. 636 return self._wm.state[
'battery']
643 """Returns currently operative accelerometer calibration. 645 Return value: tuple with calibration for zero reading, and 646 calibration or a '1' reading. 648 return wiistate.WIIState.getAccelerometerCalibration()
655 """Obtain calibration data from accelerometer. 657 Retrieve factory-installed calibration data for 658 the Wiimote's accelerometer. Returns a two-tuple 659 with the calibration numbers for zero and one: 666 factoryCalNums = self._wm.get_acc_cal(cwiid.EXT_NONE);
668 return (factoryCalNums[0], factoryCalNums[1])
675 """Obtain calibration data from nunchuk accelerometer. 677 Retrieve factory-installed calibration data for 678 the Nunchuk's accelerometer. Returns a two-tuple 679 with the calibration numbers for zero and one: 682 factoryCalNums = self._wm.get_acc_cal(cwiid.EXT_NUNCHUK);
683 return (factoryCalNums[0], factoryCalNums[1])
690 wiistate.WIIState.setAccelerometerCalibration(np.array(zeroReadingList), np.array(oneReadingList))
693 wiistate.WIIState.setAccelerometerCalibration(zeroReadingNPArray, oneReadingNPArray)
700 """Return current Gyro zeroing offsets as list x/y/z.""" 701 return wiistate.WIIState.getGyroCalibration()
708 wiistate.WIIState.setGyroCalibration(gyroTriplet)
715 wiistate.WIIState.setNunchukAccelerometerCalibration(np.array(zeroReadingList), np.array(oneReadingList))
722 """Return True/False to indicate whether a Wiimotion Plus is detected. 724 Note: The return value is accurate only after at least one 725 Wiimote state has been read. This means that either 726 _steadyStateCallback or _calibrationCallback must have 730 return self.wiiMoteState.motionPlusPresent
739 """Return True/False to indicate whether a Nunchuk is detected. 741 Note: The return value is accurate only after at least one 742 Wiimote state has been read. This means that either 743 _steadyStateCallback or _calibrationCallback must have 747 return self.wiiMoteState.nunchukPresent
756 """Compute mean and stdev for accelerometer data list self._accList in both Gs and metric m/sec^2""" 759 self.
maxAccReading = np.array([0,0,0], dtype=
None, copy=1, order=
None, subok=0, ndmin=0)
761 if accWiiReading
is not None:
762 oneAccReading = accWiiReading.tuple()
763 accArrays.append(oneAccReading)
785 """Compute mean and stdev for gyro data list self._gyroList in both Gs and metric m/sec^2""" 789 if (gyroReading
is not None):
790 oneGyroReading = gyroReading.tuple()
791 gyroArrays.append(oneGyroReading)
794 if len(gyroArrays) != 0:
827 """Class organizes installation and removal/restoration 828 of callback functions for the Wii driver to use. 829 Only one instance of this class is allowed. Additional 830 instantiations generate a CallbackStackMultInstError. 832 A stack discipline is imposed. Operations: 834 - push(<callBackFunc>) # New function becomes the active 835 # callback immediately 836 - pop() -> <oldCallBackFunc> # If another function is still on 837 # the stack, it immediately becomes 838 # the active callback. If callback 839 # is paused, resume() is forced. 840 - pause() # Callbacks are temporarily turned off 841 - paused() -> True/False 842 - resume(sloppy=True) # If sloppy=False, resuming when 843 # callbacks are not paused throws an 844 # exception. If sloppy=True, the call is 850 _singletonInstance =
None 874 """Given function becomes the new WIImote callback function, shadowing 875 the function that is currently on the stack 878 self._functionStack.append(func)
886 """Wiimote callback function is popped off the stack. New top of stack 887 becomes the new callback function. Old function is returned. 893 func = self._functionStack.pop()
902 """WIIMote callbacks are temporarily stopped.""" 904 self._wm.disable(cwiid.FLAG_MESG_IFC)
912 """Resume the (presumably) previously paused WIIMote callback functions. 913 If sloppy is True, this method won't complain if pause was not 914 called earlier. If sloppy is False, an exception is raised in 927 self._wiiCallbackStack(_functionStack.index[-1])
935 """Tell WIIMote which function to call when reporting status.""" 937 self._wm.mesg_callback = f
938 self._wm.enable(cwiid.FLAG_MESG_IFC)
def __init__(self, wiiDriver, sloppy=True)
def getLEDs(self, asInt=False)
def setMaxAcc(self, maxArray)
def setStdevGyro(self, stdevArray)
def _getInstanceVarCriticalSection(self, varName)
def getNunchukFactoryCalibrationSettings(self)
def setGyroData(self, gyroArray)
def getWiimoteState(self)
def getStdevAccelerator(self)
def setRumble(self, switchPos)
def getAccelerometerCalibration(self)
def getVarianceGyro(self)
def setMeanGyro(self, meanArray)
def setGyroCalibration(self, gyroTriplet)
def getAccFactoryCalibrationSettings(self)
def getGyroCalibration(self)
def _steadyStateCallback(self, state, theTime)
def setStdevAcc(self, stdevArray)
def getMeanAccelerator(self)
def _calibrationCallback(self, state, theTime)
def setMeanAcc(self, meanArray)
def setAccelerometerCalibration(self, zeroReadingList, oneReadingList)
def setMaxGyro(self, maxArray)
def computeAccStatistics(self)
def setAccData(self, accArray)
def computeGyroStatistics(self)
def setNunchukAccelerometerCalibration(self, zeroReadingList, oneReadingList)
def __init__(self, theSampleRate=0, wiiStateLock=None, gatherCalibrationStats=False)
def getVarianceAccelerator(self)
def setLEDs(self, statusList)
def motionPlusPresent(self)
latestCalibrationSuccessful
def resume(self, sloppy=True)