Skip to content

Hardware » Wiimote

Ivan Perez edited this page Oct 5, 2015 · 23 revisions

Wii remotes, also known as WiiMotes, are Nintendo's Wii console remote controllers.

Wiimotes are wireless devices that communicate over bluetooth. They feature multiple push buttons, accelerometers, and an infrared camera. Wiimotes can be used in combination with the wii bar (a bar with 4 IR leds that sits on top of your TV) to provide a unique point of reference. This lets your game know which part of the screen the wiimote it pointing towards, and can be used to turn the wiimote into a gun and play first-person shooting games. Wiimotes have an extension port that can be used to connect additional devices, like nunchakus (a small extension with a joystick-like controller and a fire button; see image below) and more precise accelerometers.

Cool stuff!

People have been doing all kinds of hacks with wiimotes, including low-cost whiteboards, touch screens, head-tracking and 3D screens, slide presenters, connecting them to Android/iPhones, and extremely amazing games. Head over to youtube (in a new tab) for a few ideas for your next wiimote project.

On Linux, the library CWiid provides comprehensive support for many Wii devices1. Hcwiid is a Haskell library that provides bindings for CWiid. While the capabilities of Hcwiid are behind those of CWiid or its newer fork, the API provided is enought to access button, infrared and accelerometer information.

In this section we will learn how to:

  • Create a Haskell program that connects to a Wiimote.
  • Poll the wiimote regularly for the information we are interested in.
  • Present that information on the screen.
  • Process the information to obtain more sophisticated and useful data.

At the end of this chapter you should be able to use a Wiimote to control the games and examples provided in others lessons (eg. [SDL1](SDL » SDL1)), and to create a Haskell application that uses a Wiimote to interact with it. In chapter Examples we will see how to create a small game and enable wiimote support.

Portability

Currently cwiid is only available for Linux. If your game uses wiimotes, consider allowing an alternative input method (if possible), and disabling all wii-related code on Windows and MacOSX. See Haskanoid for an example of how to use the C preprocessor and cabal flags to implement conditional wiimote support for different OSs.

Baby steps

Connecting to the wiimote the first time could not be simpler.

import System.CWiid

main :: IO ()
main = do
  putStrLn "Initializing WiiMote. Please press 1+2 to connect."
  wm <- cwiidOpen
  case wm of
    Just _aWiimote -> putStrLn "Connected"
    Nothing        -> putStrLn "Could not connect"

🔑 Compilation

Haskell RTS uses a POSIX signal that is needed by cwiid to interact with the wiimote. To make wiimotes work on linux, you need to disable the RTS clock completely2. Compile your program with the flag -rtsopts and pass the runtime option -V0 to your program during execution, like so:

$ cabal exec -- ghc Main.hs -rtsopts
$ ./Main +RTS -V0
Initializing WiiMote. Please press 1+2 to connect.

If you run the program above, you should see the message "Press 1+2 to connect". There is a standard delay of a few seconds, during which you should press the buttons 1 and 2 on the wiimote simultaneously and it will enter discovery mode and connect to your computer. If successful, you should receive a handle to your wiimote in the form of a CWiidWiimote value.

Connect, poll buttons

Wiimotes run on batteries. The more data that is polled from the wiimote, the faster the batteries will be drained. To make them last longer, wiimotes require that you enable and disable different input subdevices before you can use them. You do that with the function cwiidSetRptMode with a numeric argument: the sum of the independent modes that are enabled. Head over to the cwiid documentation for a detailed list of the modes available and their numeric codes.

Our next program is going to enable Buttons, IR and Accelerometers on a wiimote, and poll and report the state of the button A every 100 milliseconds.

import Control.Concurrent
import Control.Monad
import System.CWiid

main :: IO ()
main = do
  putStrLn "Initializing WiiMote. Please press 1+2 to connect."
  wm <- cwiidOpen
  case wm of
    Nothing      -> putStrLn "Could not connect"
    Just wiimote -> do 
      putStrLn "Connected"

      -- NEW

      -- Enable different sensors (15 = 1 + 2 + 4 + 8):
      -- 1 for status, 2 for buttons, 4 for accelerometers, and 8 for IR.
      cwiidSetRptMode wiimote 15

      -- "game" loop
      forever $ do

        -- Input: Poll new state
        allButtons <- cwiidGetBtnState wiimote
        let btnAPushed = cwiidIsBtnPushed allButtons cwiidBtnA

        -- Rendering: Report
        let msg = if btnAPushed then "Down" else "Up"
        putStrLn msg

        -- Introduce a small delay
        threadDelay 100000

Try this example. You should see a continuous report stream that changes to "Down" whenever the button is depressed.

Summary

  • Wiimotes contain multiple inputs, including discrete ones (on/off) ones and more analog-like ones (accelerometers, IR camera).

  • To interact with a wiimote, one needs to connect to it, set the input reception mode, and then poll the state.

  • Unlike in SDL, wiimotes do not report input events. They need to be polled regularly. That means that, unless polled frequently enough, one might miss intermediate states (very fast clicks). In the previous example, if you click the button A very quickly, you may see that some button presses are missed.

Homework

  • Head over to the haddock documentation for hcwiid and review other buttons available. Modify the program above to get the state of other buttons.

  • If you did the SDL input lesson, modify the program REFNEEDED to use the wiimote instead of a keyboard. (Note: theoretically, you could create an intermediate layer that turns wiimote state changes into SDL user events and keep a uniform game interface. If you end up doing something so sophisticated, please send us a link. However, the purpose of this exercise is just to modify the program to use a Wiimote as the input device, in the simplest way possible.)

Accelerometers

Infrared

Shooting at the screen

Installation

To write Haskell programs with Wiimote support, you need a linux computer, the cwiid development library and hcwiid. On Ubuntu, all you need to do is

$ sudo apt-get install libcwiid-dev
$ cabal install hcwidd # Better to do it in a sandbox

Contribute!

  • As you can see, the hcwiid bindings are very incomplete. If you have a wiimote, please improve wii support for Haskell and send a pull request to the github project.

  • Wiimote support is currently only available on linux. Consider writing a small version of the bindings for a cross-platform wii library. See this wiki for a list of existing libraries.

Footnotes

  1. From the Wiibrew project: "While the original library ceased to be developed around 2010, in 2011 it has been forked by the Linux Laptop Orchestra (L2Ork) project (http://l2ork.music.vt.edu) and has since been upgraded to provide comprehensive support for all Nintendo brand Wii controllers, including Wiimote, Nunchuk, MotionPlus, Classic, Wii Fit board, and the newer version of the Wiimote with MotionPlus Inside."

  2. From GHG's documentation: "RTS clock completely, and has the effect of disabling timers that depend on it: the context switch timer and the heap profiling timer. Context switches will still happen, but deterministically and at a rate much faster than normal. Disabling the interval timer is useful for debugging, because it eliminates a source of non-determinism at runtime."

Credits

  • Wiimote image was taken from this Wikipedia page.

  • The nunchaku image was taken from wikipedia, and that one was taken from Flickr. The original image's author Marcin Chady. Distributed under CC BY 2.0 licence.

Clone this wiki locally