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):
194 rospy.loginfo(
"Wiimote activated.")
217 """Wii's callback destination while zeroing the device.""" 229 self.
_accList.append(thisState.accRaw)
236 self.
_gyroList.append(thisState.angleRate)
249 Find the at-rest values of the accelerometer and the gyro. 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)). 257 The stdev thresholds are documented in wiimoteConstants.py. 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. 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. 286 wiistate.WIIState.setGyroCalibration([0, 0, 0])
287 wiistate.WIIState.setAccelerometerCalibration([0, 0, 0], [0, 0, 0])
304 if accWiiReading
is not None:
305 oneAccReading = accWiiReading.tuple()
306 accArrays.append(oneAccReading)
307 accArrays = np.reshape(accArrays, (-1, 3))
312 if (gyroReading
is not None):
313 oneGyroReading = gyroReading.tuple()
314 gyroArrays.append(oneGyroReading)
317 gyroArrays = np.reshape(gyroArrays, (-1, 3))
340 allData = np.append(accArrays, gyroArrays, axis=1)
343 thresholdsArray = THRESHOLDS_ARRAY
349 thresholdsArray = THRESHOLDS_ARRAY[0:3]
352 stdev = np.std(allData, axis=0)
357 isBadCalibration = (stdev > thresholdsArray).any()
362 if (isBadCalibration):
367 rospy.loginfo(
"Failed calibration; using questionable calibration anyway.")
368 wiistate.WIIState.setGyroCalibration(self.
meanGyro)
370 if (gyroCalibrationOrig
is not None):
371 rospy.loginfo(
"Failed calibration; retaining previous calibration.")
373 wiistate.WIIState.setGyroCalibration(gyroCalibrationOrig)
375 rospy.loginfo(
"Failed calibration; running without calibration now.")
380 wiistate.WIIState.setGyroCalibration(self.
meanGyro)
383 rospy.loginfo(
"Calibration successful.")
388 """Returns the most recent Wiistate instance. Provides proper locking.""" 393 """Accessor that provides locking.""" 398 """Accessor that provides locking.""" 403 """Accessor that provides locking.""" 408 """Accessor that provides locking.""" 413 """Accessor that provides locking.""" 418 """Accessor that provides locking.""" 423 """Return the value of the given instance variable, providing locking service.""" 428 if varName ==
"wiimoteState":
430 elif varName ==
"meanAcc":
432 elif varName ==
"stdevAcc":
434 elif varName ==
"varAcc":
436 elif varName ==
"meanGyro":
438 elif varName ==
"stdevGyro":
440 elif varName ==
"varGyro":
443 raise ValueError(
"Instance variable name " + str(varName) +
"is not under lock control.")
450 """Start of stop rumble (i.e. vibration). 1: start; 0: stop""" 451 self.
_wm.rumble = switchPos
457 return self.
_wm.state[
'rumble']
462 """Set the four Wii LEDs according to statusList 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. 471 currLEDs = self.
getLEDs(asInt=
True)
473 for LED
in range(len(statusList)):
478 elif statusList[LED]
is not None:
480 self.
_wm.led = currLEDs
483 """Get the status of the four Wii LEDs. 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. 494 LEDs = self.
_wm.state[
'led']
521 """Obtain battery state from Wiimote. 523 Maximum charge is BATTERY_MAX. 526 return self.
_wm.state[
'battery']
529 """Returns currently operative accelerometer calibration. 531 Return value: tuple with calibration for zero reading, and 532 calibration or a '1' reading. 534 return wiistate.WIIState.getAccelerometerCalibration()
537 """Obtain calibration data from accelerometer. 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: 548 factoryCalNums = self.
_wm.get_acc_cal(cwiid.EXT_NONE)
550 return (factoryCalNums[0], factoryCalNums[1])
553 """Obtain calibration data from nunchuk accelerometer. 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: 560 factoryCalNums = self.
_wm.get_acc_cal(cwiid.EXT_NUNCHUK)
561 return (factoryCalNums[0], factoryCalNums[1])
564 wiistate.WIIState.setAccelerometerCalibration(np.array(zeroReadingList), np.array(oneReadingList))
567 wiistate.WIIState.setAccelerometerCalibration(zeroReadingNPArray, oneReadingNPArray)
570 """Return current Gyro zeroing offsets as list x/y/z.""" 571 return wiistate.WIIState.getGyroCalibration()
574 wiistate.WIIState.setGyroCalibration(gyroTriplet)
577 wiistate.WIIState.setNunchukAccelerometerCalibration(np.array(zeroReadingList), np.array(oneReadingList))
580 """Return True/False to indicate whether a Wiimotion Plus is detected. 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 593 """Return True/False to indicate whether a Nunchuk is detected. 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 606 """Compute mean and stdev for accelerometer data list self._accList in both Gs and metric m/sec^2""" 609 self.
maxAccReading = np.array([0, 0, 0], dtype=
None, copy=1, order=
None, subok=0, ndmin=0)
611 if accWiiReading
is not None:
612 oneAccReading = accWiiReading.tuple()
613 accArrays.append(oneAccReading)
623 self.
meanAcc = np.vstack(accArrays).mean(axis=0)
630 """Compute mean and stdev for gyro data list self._gyroList in both Gs and metric m/sec^2""" 634 if (gyroReading
is not None):
635 oneGyroReading = gyroReading.tuple()
636 gyroArrays.append(oneGyroReading)
639 if len(gyroArrays) != 0:
640 self.
meanGyro = np.vstack(gyroArrays).mean(axis=0)
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. 662 A stack discipline is imposed. Operations: 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 679 _singletonInstance =
None 694 """Given function becomes the new WIImote callback function, shadowing 695 the function that is currently on the stack 702 """Wiimote callback function is popped off the stack. New top of stack 703 becomes the new callback function. Old function is returned. 714 """WIIMote callbacks are temporarily stopped.""" 716 self.
_wm.disable(cwiid.FLAG_MESG_IFC)
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 735 self._wiiCallbackStack(_functionStack.index[-1])
738 """Tell WIIMote which function to call when reporting status.""" 740 self.
_wm.mesg_callback = f
741 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)