Wiimote — A How-to document for interfacing Nintendo Wii™ remotes with FreeVR
The Nintendo Wii™ remote, frequently referred to as a "Wiimote" has been a popular input device for virtual reality enthusiasts due to it's low-cost, rich input features, and wireless connectivity.
The wireless connectivity is handled through the Bluetooth technology standard. Part of FreeVR's design constraints is to minimize the number of external requirements, and at least for now, Bluetooth is not included as part of FreeVR's features. Therefore, other, indirect mechanisms must be used to integrate Wiimote controllers into FreeVR, each of which is essentially an input data server, though one ("CWiid") interfaces as a standard X11 input.
The three interfaces are:
NOTE: Presently all the methods presented are for use with the Linux operating system. As methods are ascertained for interfacing on other operating systems, this manpage will be augmented. Also of note is that there is a project ("XWiimote") to integrate Nintendo Wii™ remotes directly into the Linux kernel. This is part of the Linux 3.x distribution effort.
In all cases, the computer must have a Bluetooth adaptor to communicate with the device.
Each of the following subsections provide instructions on how each of the interfaces listed above can be used to accomplish Wiimote interaction with FreeVR.
Before delving into specific methods of the three interfaces, verify that the low-level Bluetooth communication with the device is operational.
On Linux this can be accomplished with the "hcitool" --- specifically the "scan" command:
(press the 1 and 2 buttons on your Wiimote) % hcitool scan Scanning ... 00:24:1E:7A:CC:2D Nintendo RVL-CNT-01
The CWiid package is a Wii™ remote "daemon" library written in C. The library provides a convenient API for interfacing with Wiimote devices, and the CWiid package includes the wminput daemon which converts Wiimote events into Linux event device system (aka "evdev", or in FreeVR parlance "EVIO") using the Linux "uinput" kernel module.
So wminput is the actual program that one executes to link the Wiimote to the uinput system. Usually, this will have to be run with superuser authority. And furthermore, doing so will also set the permissions of the "/dev/input/event<N>" device to be readable by root only, so proper accommodations must be made — generally changing the permissions on the input device.
# /usr/local/lib/cwiid/wminput -c /usr/local/lib/cwiid/config/buttons Put Wiimote in discoverable mode now (press 1+2)... Ready. # chmod 666 /dev/input/event<N>
NOTE: by default, the wminput program does not look in the local directory to find a file, so when giving a relative path, the "./" must be explicitly specified.
Once "wminput" is configured and running, you can test the inputs using the "eviotest" program that comes with the FreeVR distribution.
% ./eviotest /dev/input/event<N> [...] epttn12kdtt buttons: 00000000000
NOTE: the characters above the input values are the last character of each name.
The accompanying lswm tool can be executed first in order to list all the Wiimotes currently in discoverable mode. (Which really can also be done with the "hcitool scan" operation.)
% lswm Put Wiimotes in discoverable mode now (press 1+2)... 00:24:1E:7A:CC:2D
/usr/include/linux/input.h
For example:
% cat /usr/local/lib/cwiid/config/buttons # Button mappings: Wiimote.A = BTN_A Wiimote.B = BTN_B Wiimote.Up = KEY_UP Wiimote.Down = KEY_DOWN Wiimote.Left = KEY_LEFT Wiimote.Right = KEY_RIGHT Wiimote.1 = KEY_PROG1 Wiimote.2 = KEY_PROG2 Plugin.acc.X = ABS_X Plugin.acc.Y = -ABS_Y
For configuration on the FreeVR side, there is a difference as to whether a Wiimote button was mapped to a "BTN" or a "KEY". For "wminput" inputs mapped to "KEY" mappings, FreeVR configuration also uses "key":
control "print_struct" = "2switch(key[Home])"; input "2switch[1]" = "2switch(key[Prog1])";
For "wminputs" mapped as "BTN" type inputs, there is a choice of how to indicate this on the FreeVR side. Buttons can be thought of as special "key" inputs, using the string "Btn:" to indicate such. Thus, both of the following will work:
input "2switch[2]" = "2switch(button[A])"; input "2switch[3]" = "2switch(key[Btn:B])";
And for valuators:
input "wii-roll" = "valuator(abs[X])"; input "wii-elev" = "valuator(abs[Y])";
Note however that the only "valuators" currently available through the "wminput" program are the accelerometers. The joystick on the Nunchuk is not available as a valuator — there is a plugin to map the joystick to buttons, but not for getting the actual valuator value. This is a major shortcoming of the CWiid/wminput system.
# export PYTHONPATH=<...>/python/build/lib.linux-x86_64-2.6
First, find it's input id:
% xinput list --short | grep Wiimote Nintendo Wiimote id=10 [slave keyboard (3)]
The next step is determine the property number for the "Device Enabled property of the input device with the id above (e.g. "10" in this example):
% xinput list-props 10 | grep "Device Enabled" Device Enabled (117): 1
With the id ("10") and enable/disable property code ("117"), the device's effect on the X11 input system can now be turned off. The command to change a property also takes arguments for the number of bits of the datum as well as the value. As the enable/disable flag only requires one byte (which is in effect the minimum), the command is (along with verification):
% xinput set-int-prop 10 117 8 0 % xinput list-props 10 | grep "Device Enabled" Device Enabled (117): 0
VRPN is not generally included with Linux distributions, but it is easy to download and compile.
Enabling the basic "WiiMote" input is straightforward:
% cat wiimote_vrpn.cfg vrpn_WiiMote WiiMote0 1 0 0 1 % vrpn_server -f wiimote_vrpn.cfg
There is also a tracking form of VRPN interface with the WiiMote which involves the use of the IR sensor information along with some post-processing (all handled within VRPN):
% cat wiimote_vrpn.cfg vrpn_WiiMote WiiMote0 1 1 1 1 vrpn_Tracker_WiimoteHead Tracker0 WiiMote0@localhost % vrpn_server -f wiimote_vrpn.cfgNOTE: that the middle two flags ("useMotionSensing" and "useIR") must be enabled to create tracking output.
Here are the VRPN configuration arguments for the two input types:
for vrpn_WiiMote: 1) name_of_this_device (string) 2) Player number (int) 3) Use motion Sensing (bool/int) — from the base Wiimote, not motion sensor 4) Use IR tracking (bool/int) 5) Reorder the buttons (bool/int) 6) [optional] Bluetooth address — provided in all uppercase with colons for vrpn_Tracker_WiimoteHead 1) name_of_this_device (string) 2) name_of_vrpn_WiiMote_device (string) 3) [optional] min_update_rate (default=60) (float) [Hz] 4) [optional] led_distance (default=0.205) (float) [meters]On the FreeVR side, these can be mapped into inputs with configuration settings similar to:
input "2switch[A]" = "2switch(WiiMote0:button[1])"; input "2switch[B]" = "2switch(WiiMote0:button[2])"; input "2switch[3]" = "2switch(WiiMote0:button[3])"; input "val[x]" = "Valuator(WiiMote0:analog[ 1])"; # roll/twist input "val[y]" = "Valuator(WiiMote0:analog[-2])"; # pitch/elevation input "val[u]" = "Valuator(WiiMote0:analog[ 3])"; # right-side-upidness input "val[b]" = "Valuator(WiiMote0:analog[ 0])"; # battery level input "wand2" = "6sensor(Tracker0:tracker[0])";
NOTE: Analog values 1 and 3 are specifically the ...
The Vrui "VRDeviceDaemon" server can handle a variety of input devices, much like VRPN. And the Nintendo Wii™ remote is one input device it can handle.
In fact it is fairly straightforward. The only real requirement is that the Vrui system be compiled with the Bluetooth feature enabled.
Once Vrui is compiled, a "VRDevices.cfg" configuration file for the VRDeviceDaemon program must be created. To collect button and valuator inputs only (valuators with an attached Nunchuk of course), use this configuration (replacing the hostname with the correct value):
section "<hostname>" section DeviceManager deviceNames (Wiimote1) section Wiimote1 deviceType WiimoteTracker # Set this to the Bluetooth ID of the Wiimote devicename "00:24:1E:7A:CC:2D" # Set the LED pattern for this Wiimote (any 4-bit value) ledMask 1 # Disable motion tracking using the Wiimote's camera enableTracker false endsection endsection endsection
and then run the Vrui VRDeviceDaemon:
% bin/VRDeviceDaemon VRDeviceDaemon: Reading configuration file VRDeviceDaemon: Initializing device manager VRDeviceManager: Loading device Wiimote1 of type WiimoteTracker WiimoteTracker: Connecting to first compatible Bluetooth device. WiimoteTracker: Please press buttons 1 and 2 to initiate connection... done WiimoteTracker: Connected wiimote's battery level is 145% VRDeviceManager: Managing 0 trackers, 13 buttons, 2 valuators VRDeviceManager: Managing 0 virtual devices VRDeviceDaemon: Initializing device server VRDeviceServer: Waiting for client connection
In another shell, the inputs can be tested with the FreeVR "vruiddtest" program:
% ./vruiddtest
For position tracking, there are a handful of additional options that must be specified. However, position tracking with the Vrui system only works with physical LED configurations that have four LED markers rather than the customary two. So this system does not work with the standard Wii sensor bar.
The additional configuration options are:
cameraCenter (512, 384) cameraFocalLength 1280 targetPoints ((-2.0, 0.0, 0.0), (0.0, -1.0, 2.0), (2.0, 0.0, 0.0), (0.0, -1.0, -2.0)) targetTransformation identity homeTransform identity
xinput(1), wminput(1), eviotest(1fv)
The sample FreeVR configuration file for VRPN:
Web sites:
Video:
https://www.youtube.com/watch?v=Jd3-eiid-Uw
Copyright 2022, Bill Sherman, All rights reserved.