Using the Wii Remote in Your TV3D Projects

With the advent of the fifth console generation comes the Nintendo Wii, loved for its low retail price, endearing exclusive franchises, and most importantly, its unique input device: a controller with Infrared pointing capabilities, an accessory slot for attachments, and accelerometers that measure rotation along 3 axes. This controller has opened up a whole new world of control beyond what the fourth console generation offered us, and now independent developers everywhere are scrambling to get a bite of this technology for their own projects.

While the rest of the world waits to see if Nintendo actually makes good on their uncharacteristic promises of openness to 3rd party developers with “small budgets and big ideas,” the impatient independent community has already started tearing the Wii console and remote apart trying to figure it all out, and their efforts have yielded plenty of libraries that allow us to use the Wii Remote as an input device in our PC software.

This tutorial will explain how to use one such library, WiimoteLib, to interpret the signals sent from the Wii remote via Bluetooth.

I learned everything I know about this subject from personal experience and this tutorial by Brian Peek. If you don’t think I’m cool enough for your tutorial needs, I welcome you to go check out his tutorial instead. ;D

You Will Need:

  • A Wii Remote: $40, but if you’re reading this article, there’s a good chance you already have one. :D
  • A Bluetooth Receiver: Mine came free with a program I found at Best Buy called “Mii Manager,” which was only $20. Keep your receipt: not all Bluetooth Receivers are compatible with the Wii Remote.
  • The WiimoteLib Library: Grab it for free here.

You Might Also Want:

  • A Nunchuk Attachment: ~$20
  • Two small candles: Unless you happen to have a couple of unitasking Infrared signal emitters lying around the house, I recommend a couple of votive candles. Fire does a pretty darned good job of emitting infrared heat, don’t you know?

PART ONE: Connecting the Wiimote to your PC

This is quite possibly the only difficult part of the whole tutorial, simply because it involves taking a lot of independent hardware made by different manufacturers and trying to make them all talk to each other. The unfortunate truth is that depending on your computer and what kind of Bluetooth adapter you’re using, this process is probably going to be slightly different for you. Regardless, however, most of the basic steps are the same no matter what tools you’re using, so try to follow along as best as you can, and if it just isn’t working, try referring to your Bluetooth adapter’s instruction manual.

Connect your Bluetooth Adapter to your PC

If you’ve already got a Bluetooth adapter installed on your computer (or if you’re one of the lucky ones who has Bluetooth communications built right in), then this step should be as easy as plugging in the USB dongle and letting it start up. If this is your first time, however, follow the instructions included with your adapter and make sure you install it correctly before proceeding.

Connect the Wiimote to your Bluetooth Adapter

This step varies depending on your bluetooth adapter, but the process should look something like this.

Open your Bluetooth Software and begin searching for nearby devices

If you’re asked, choose to search for input devices, mice, keyboards, and joysticks.

While your Bluetooth Software is searching, press and hold the 1 and 2 buttons on the Wii Remote

Pressing the 1 and 2 buttons will make the Wiimote enter the Bluetooth Discoverable mode, which is indicated by the flashing LED lights at the bottom of the Wiimote. Make sure you keep the 1 and 2 buttons held down while establishing the connection. If you let go, the Wiimote will go back to sleep faster and you might not be able to finish establishing the connection.

Once the Wiimote is found by your Bluetooth Software, select it and finish setting up the connection

The Wiimote should be listed as Nintendo RVL-CNT-01. Depending on how your software works, select the Wiimote and establish a connection with it. If you are asked for a PIN number at any time, leave the field blank and/or skip that step. If you are asked which service you want the Wiimote to use, select something to the tune of “Input / Keyboard & Mouse / Human Interface Device (HID)”.

Once the connection has been established, the Wiimote might keep flashing its LED lights, which can be confusing. To test whether or not the connection has been successfully made, try running this application. If the connection has been made, the program will display the Wiimote’s current button and joystick states, accelerometer readings, IR info, and attachment info for the Nunchuk or Classic Controller.

Troubleshooting

  • Some bluetooth adapters simply don’t seem to pick up the Wiimote’s signal. I can confirm that the Bluetooth dongle that came free with Mii Manager has worked like a charm for me, and it was only $20.
  • If you are anywhere near an active Wii console, the Wii console might be picking up the Wiimote’s Bluetooth signal faster than your computer can. When dealing with greedy siblings who refuse to turn off the Wii momentarily, I like to throw the circuit breaker.
  • If your Wiimote doesn’t seem to enter Bluetooth Discoverable mode, it might still be connected to the Wii or to an old Bluetooth session. Removing and re-inserting the batteries always does the trick, for me.
  • Likewise, your Bluetooth adapter may not be capable of tracking more than one Wiimote. Make sure you aren’t already connected to another Wiimote. Removing the Bluetooth USB dongle does the trick, for me.

PART TWO: Set up WiimoteLib.DLL for use in your application

Once you’ve downloaded WiimoteLib, just grab WiimoteLib.DLL and reference it in your project. To get started, all you need is some initialization and destruction code:

Imports WiimoteLib
Private myWiimote as New Wiimote
 
Private Sub Initialize()
   myWiimote.Connect()
   myWiimote.SetReportType(Wiimote.InputReport.IRExtensionAccel, False)  '<---Use this code if you have an accessory attached
   myWiimote.SetReportType(Wiimote.InputReport.IRAccel, False)           '<---Use this code if you don't
                                                                         'In the next section, we'll see how to automatically
                                                                         'choose/change the report type when an attachment is
                                                                         'plugged in or unplugged.
End Sub
 
Private Sub Kill()
   myWiimote.SetRumble(False)
   myWiimote.SetLEDs(False, False, False, False)
   myWiimote.Disconnect()
End Sub

And now, the magical world of the Wiimote is at your fingertips! You can access the Wiimote’s different states using myWiimote.WiimoteState, like so:

   Dim wiimoteRotation as TV_3DVECTOR
   wiimoteRotation.x = myWiimote.WiimoteState.AccelState.X
   wiimoteRotation.y = myWiimote.WiimoteState.AccelState.Y
   wiimoteRotation.z = myWiimote.WiimoteState.AccelState.Z
 
   Dim buttonPressed_A as Boolean
   Dim buttonPressed_1 as Boolean
   Dim buttonPressed_2 as Boolean
   buttonPressed_A = myWiimote.WiimoteState.ButtonState.A
   buttonPressed_1 = myWiimote.WiimoteState.ButtonState.One
   buttonPressed_2 = myWiimote.WiimoteState.ButtonState.Two
 
   Dim batteryStrengthPercentage as String
   batteryStrengthPercentage = "Wiimote Battery Level: Roughly " & Int(myWiimote.WiimoteState.Battery / 2) & "%"
 
   Dim nunchukJoystickPosition as TV_2DVECTOR
   nunchukJoystickPosition.x = myWiimote.WiimoteState.NunchukState.X
   nunchukJoystickPosition.y = myWiimote.WiimoteState.NunchukState.Y

PART THREE: Handling attachment plugins and unplugs with event handlers

In order to handle the addition/removal of accessories, you can create event handlers that run whenever an accessory is plugged in or unplugged.

Imports WiimoteLib
Private myWiimote as New Wiimote
 
Private Sub Initialize()
   AddHandler myWiimote.OnWiimoteExtensionChanged, AddressOf myWiimote_ExtensionChanged
   myWiimote.Connect()
   myWiimote.SetReportType(Wiimote.InputReport.IRAccel, False)
End Sub
 
Private Sub myWiimote_ExtensionChanged(ByVal sender As Object, ByVal args As WiimoteExtensionChangedEventArgs)
   If args.Inserted Then
        myWiimote.SetReportType(Wiimote.InputReport.IRExtensionAccel, True)
   Else
        myWiimote.SetReportType(Wiimote.InputReport.IRAccel, True)
   End If
End Sub
 
Private Sub Kill()
   myWiimote.SetRumble(False)
   myWiimote.SetLEDs(False, False, False, False)
   myWiimote.Disconnect()
End Sub

PART FOUR: Tasking the rumble feature to a BackgroundWorker

One problem I quickly noticed is that there is a small ping delay when changing myWiimote.WiimoteState.Rumble which causes choppy gameplay every time the rumble turns on or off. In order to get around this, I created a simple rumble manager that utilizes a BackgroundWorker object.

Imports WiimoteLib
 
Private myWiimote as New Wiimote
Private WithEvents wiimoteBackgroundWorker As New System.ComponentModel.BackgroundWorker
Private rumbleTime As Single = -1
Private rumbling As Boolean
 
Private Sub Initialize()
   AddHandler myWiimote.OnWiimoteExtensionChanged, AddressOf myWiimote_ExtensionChanged
   myWiimote.Connect()
   myWiimote.SetReportType(Wiimote.InputReport.IRAccel, False)
   wiimoteBackgroundWorker.RunWorkerAsync()
End Sub
 
Private Sub wiimoteBackgroundWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles wiimoteBackgroundWorker.DoWork
   Do
      If rumbleTime >= 0 Then
         If Not rumbling Then
            orTV.WIIMOTE.SetRumble(True)
            rumbling = True
         End If
         rumbleTime -= fpsAdj   'fpsAdj is a global adjustment value I use to control my game's speed regardless of framerate.
                                'As my framerate goes up, fpsAdj goes down, and vice versa. You could use a flat number
                                'here if you want, instead of a dynamic value: "rumbleTime -= 1", for instance.
      ElseIf rumbling Then
         orTV.WIIMOTE.SetRumble(False)
         rumbling = False
      End If
      Application.DoEvents()
   Loop
End Sub
 
Private Sub myWiimote_ExtensionChanged(ByVal sender As Object, ByVal args As WiimoteExtensionChangedEventArgs)
   If args.Inserted Then
        myWiimote.SetReportType(Wiimote.InputReport.IRExtensionAccel, True)
   Else
        myWiimote.SetReportType(Wiimote.InputReport.IRAccel, True)
   End If
End Sub
 
Private Sub Kill()
   myWiimote.SetRumble(False)
   myWiimote.SetLEDs(False, False, False, False)
   myWiimote.Disconnect()
End Sub

With this code in place, you can set the number of frames you want the Wiimote to rumble like this:

Private Sub RumbleForAWhile()
   rumbleTime = 100
End Sub
 
Private Sub RumbleForAWhileLonger()
   rumbleTime += 50
End Sub
 
Private Sub StopRumblingImmediately()
   rumbleTime = 0
End Sub

PART FIVE: Using the Infrared sensors for pointing and distance checking

Introduction

The Wiimote has a powerful Infrared feature that detects four infrared light sources, then interprets those two (up to four) IR “dots” to X and Y values which are sent to the Wii. The fact that the Wiimote picks up four separated IR dots allows us to tell when the Wiimote is moving closer and farther away from the screen, in the exact same way that having two eyes allows humans to see with depth perception.

That silver bar that comes with your Wii and is placed in front of your TV screen is nothing more than a couple of infrared light emitters attached to a plastic spacer. They emit small, focused, and bright infrared “dots” for the Wiimote to easily see and trace, but the Wiimote can also pick up on other infrared light, like nearby lamps and other electronic equipment. If you’ve ever been playing a Wii game when your Wiimote suddenly glitched and became seemingly uncontrollable, there’s a good chance that you pointed the Wiimote too far away from the center of the screen, and when the Wiimote lost focus on one end of the sensor bar, it picked up another nearby IR source, such as a lamp next to your TV. Turning off nearby lights or moving them behind you usually does the trick, if you run into this problem frequently. Additionally, sitting a little bit farther away from the sensor bar makes it harder for the Wiimote to lose track of the sensor bar.

The problem with the Wii’s sensor bar is that it isn’t wireless, like the Wiimote. Tethered to the Wii like a chained dog, it’s rather useless to us. So what are we supposed to do? Sure, we don’t need to utilize the Wiimote’s IR capabilities to come up with some pretty awesome games, but let’s face it: every good shooter deserves IR pointing- and so do a lot of other cool games.

I’ve always envisioned a pair of USB plugin IR emitters that you can clip, stick, or mount onto the top or sides of your monitor, but I haven’t been able to find any such thing for sale anywhere. And let’s be honest, who wants to pay money for a unitasking tool when there’s a cheap, simple, and- frankly- somewhat medieval solution sitting right under your nose? That’s right: candles. Candles yield heat, heat yields infrared light, and as long as we keep a small and focused flame going, we can definitely get a couple of IR “dots” strong enough for our Wiimote to pick up on.

Setting up your... *ahem*... Infrared Emitting Devices

I know, I know, it looks ridiculous, but trust me... this works:

Example code

Now, once you have your candles set up, you can use the following two lines of code to see exactly what the Wiimote sees: two infrared “dots”.

tvScreen2dImmediate.Draw_Circle(myWiimote.WiimoteState.IRState.X1 * screenWidth, screenHeight - myWiimote.WiimoteState.IRState.Y1 * screenHeight, 8, 12, orTV.GLOBALS.RGBA(1, 0, 0, 1))
tvScreen2dImmediate.Draw_Circle(myWiimote.WiimoteState.IRState.X2 * screenWidth, screenHeight - myWiimote.WiimoteState.IRState.Y2 * screenHeight, 8, 12, orTV.GLOBALS.RGBA(1, 0, 0, 1))

Using the IR coordinates we get from the Wiimote, we can make a simple pointer out of the Wiimote, like so:

tvScreen2dImmediate.Draw_Circle(screenWidth - (myWiimote.WiimoteState.IRState.X1 + myWiimote.WiimoteState.IRState.X2) / 2 * screenWidth, (myWiimote.WiimoteState.IRState.Y1 + myWiimote.WiimoteState.IRState.Y2) / 2 * screenHeight, Math.Abs(myWiimote.WiimoteState.IRState.X2 - myWiimote.WiimoteState.IRState.X1) * 64, 12, orTV.GLOBALS.RGBA(1, 1, 1, 1))

Now, that simple line of code will render a dot where you’re pointing the Wiimote, and as you move the Wiimote closer to the screen, the dot will grow bigger. This simple code has many weaknesses, however. For instance:

  • If you tilt the Wiimote side to side while pointing, the pointer goes askew
  • If either of the IR sensors leave the Wiimote’s vision, the pointer goes berserk.

With a little creativity, you can easily overcome these problems. I also plan to write a more failproof cursor handler sometime soon, and when I do so, I’ll be sure to upload it. :D

Happy Wiimoting!

-Fex

 
tutorialsarticlesandexamples/using_the_wii_remote_in_your_tv3d_projects.txt · Last modified: 2013/11/22 13:32