A C#/.NET interactive display driven by a real Wii Remote over Bluetooth: motion, pointing, and gestures mapped to an on-screen canvas in real time.
A gaming motion controller is a cheap, precise, and genuinely fun way to drive an interactive
display, but the value is in the plumbing: reading the controller over Bluetooth HID, turning
noisy accelerometer and infrared data into stable pointing, motion, and gestures, and mapping
that onto something on screen without lag. wiimote-motion-display does that end to end. A Wii
Remote connects over Bluetooth HID; its accelerometer, IR camera, and buttons drive a pointer,
tilt and motion, and recognized gestures on an interactive canvas built with MonoGame.
Scope note: the input layer is pluggable, with the Wii Remote as the reference device. The canvas is built on MonoGame, the open-source continuation of the XNA Framework, so the programming model is the same one legacy Kinect/XNA projects use, and porting the render side to XNA on Visual Studio is direct. This is my own hardware, built and tested for real.
flowchart LR
W[Wii Remote] -- Bluetooth HID --> R[HID report reader\naccel, IR, buttons]
R --> F[Fusion\norientation, pointer, gesture]
F --> M[Mapping]
M --> C[MonoGame canvas\npointer / motion / gesture actions]
C -- rumble / LEDs --> W
- Bluetooth HID. Pairs the Wii Remote and reads its HID report stream: buttons, the 3-axis accelerometer, and the IR camera's tracked points. No vendor SDK, just the HID protocol.
- Pointer. Computes an on-screen pointer from the IR camera and sensor bar (or any IR sources), with smoothing so it sits still when your hand does.
- Motion and orientation. Derives tilt and motion from the accelerometer (and the MotionPlus gyro if the remote has one).
- Gestures. Recognizes flicks, swings, shakes, and holds from accelerometer patterns.
- Interactive display. A MonoGame canvas responds to the pointer, motion, and gestures in real time: move and throw objects, draw, and trigger actions, with rumble and LED feedback.
The hard parts of a movement-controlled display are the same whatever the sensor: read a noisy real-time input, turn it into stable motion and gestures, and drive a responsive display. This project does exactly that with a Wii Remote and MonoGame. A Kinect exposes a skeletal-joint stream in place of the accelerometer/IR data, and XNA is the framework MonoGame continues, so the same pipeline and the same render loop carry straight over.
That is why IMotionSource is the seam rather than a convenience: the canvas never names a Wii
Remote type. Swapping the sensor means writing one more implementation, not touching the
display.
Pointer stability. Two IR points give position and roll; one point (a partially occluded sensor bar, or the remote turned away) still gives a usable pointer if you carry the last known separation forward, which is what keeps pointing alive instead of snapping to a corner. Smoothing is a One Euro filter rather than a plain low-pass, because a low-pass makes you choose once between a still cursor and a responsive one, and this needs both.
Rumble is a side effect. The rumble motor is the low bit of every output report, so any
write that forgets to preserve it silently turns the motor off (or on). Every output path in
WiimoteDevice carries the current rumble state.
The read loop never blocks the render loop. HID reads happen on their own thread and publish a state snapshot; the game loop samples it. Nothing on the report path allocates.
What the system is built to achieve. These are the specified targets, not measurements from a run; a bring-up session with the real remote fills in the actual figures.
| Metric | Target |
|---|---|
| Controller | Wii Remote (RVL-CNT-01), Bluetooth HID, no vendor SDK |
| Report rate | 100 Hz continuous reporting (mode 0x33 / 0x37) |
| Pointer | Derived from IR at report rate, degrading gracefully to one visible point |
| Pointer stability | Still when the hand is still, via a One Euro filter rather than a fixed low-pass |
| Orientation | Pitch and roll from accelerometer, complementary-filtered with MotionPlus gyro when present |
| Gestures | Flick, swing, shake, hold; each fires once per motion with a refractory period |
| Threading | HID reads off the render thread; no allocation per report |
| Render | MonoGame DesktopGL, vsynced 60 fps |
| Input abstraction | Canvas depends only on IMotionSource, never on a Wii Remote type |
- Wii Remote pairing and HID report parsing (buttons, accelerometer, IR)
- IR pointer with smoothing
- Accelerometer orientation and motion
- Gesture recognition (flick, swing, shake, hold)
- MonoGame interactive canvas with rumble/LED feedback
- Pluggable input interface (Wii Remote as reference implementation)
- Bring-up run measured against the targets above
C# / .NET, MonoGame for the canvas, Bluetooth HID for the controller. Windows.
dotnet build
dotnet run --project src/MotionDisplay
Pair the remote first: hold 1+2 (or press the red sync button) and pair it as a Bluetooth HID device with no PIN. It appears as a standard HID device; this project talks to it directly.
MIT.