By Nathan Jacobson
|
Published on: Sat Jun 27 2026
|
Yes you read the title correct. I built a custom C++ driver to control my engineering design teams robotic cars with a Wii remote. And it even supports motion controls. You can view the driver here
The engineering design team I am a part of, SFU Racerbot, is a part of the RoboRacer autonomous racing community, a group of univeristy students worldwide who build and program 1/10 scale autonomous race cars. Usually teams will just use a cheap USB wireless game controller to either manually control their robot or use one of the buttons on the controller as a “deadman” switch that stops the car’s autonomous code when it’s released.
We decided we wanted to be different from everyone else and use a Wii remote to control our car. It would be a fun programming challenge for us and would make for some pretty good social media content.
Our robotic cars have NVIDIA Jetsons powering them, which are small Linux computers similar to Raspberry PIs except they have GPUs. NVIDIA Jetsons also have Bluetooth which is what Wiimotes use to connect to the Wii. So theoretically you can just connect to a Wiimote like you would a Bluetooth speaker or a pair of AirPods.
Now that’s probably not super suprising since a lot of consoles use Bluetooth to connect to their controllers. What is suprising is the fact that there is a driver, built into the Linux kernel for Wii remotes.
Why does this exist? No idea. But it saves me alot of trouble of having to write my own Linux driver. So thank you Linus Torvalds for including this in the Linux kernel.
Since the NVIDIA Jetson runs a custom, streamlined image of Ubuntu, this driver was not included with the kernel on the Jetson. This meant we had to download the source code for that driver, compile it and install it manually on the Jetson.
Now that the Wiimote is connected, how do you even read it’s inputs or control it’s LEDs?
Someone made a C library that does that all for you, xwiimote. It’s a C library and since we write code for our car using ROS2 and C++,
we can easily link our program to xwiimote and interface with a connected Wiimote.
It’s a fairly simple API that uses Linux file descriptors so that you can use functions such as poll() to check for events. Here’s an example of how to check for button inputs on the Wiimote:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <errno.h>
#include <xwiimote.h>
// Helper function to find the first available Wiimote path
char *find_wiimote() {
struct xwii_monitor *mon;
char *ent, *res = NULL;
// Create a monitor to scan for xwiimote devices
mon = xwii_monitor_new(false, false);
if (!mon) {
fprintf(stderr, "Error: Cannot create xwiimote monitor\n");
return NULL;
}
ent = xwii_monitor_poll(mon);
if (ent) {
res = strdup(ent);
free(ent);
}
xwii_monitor_unref(mon);
return res;
}
int main(int argc, char **argv) {
struct xwii_iface *core_dev = NULL;
char *path = NULL;
int err;
struct pollfd pfd;
// Find a connected Wiimote
path = find_wiimote();
if (!path) {
fprintf(stderr, "No Wiimote found. Please connect a Wiimote via Bluetooth first.\n");
return EXIT_FAILURE;
}
// Open the Wiimote interface
err = xwii_iface_new(&core_dev, path);
if (err) {
fprintf(stderr, "Error: Cannot open Wiimote device (Error code: %d)\n", err);
return EXIT_FAILURE;
}
pfd.fd = xwii_iface_get_fd(core_dev);
pfd.events = POLLIN;
free(path);
// main event loop
while (1) {
err = poll(fds, 1, -1); // block until a new event appears from the Wiimote
if (err < 0) {
if (errno == EINTR)
continue;
perror("Poll error");
break;
}
// Process all events queued from the driver
while ((err = xwii_iface_dispatch(core_dev, &event, sizeof(event))) == 0) {
if (event.type == XWII_EVENT_KEY) {
// 1 means key down, 0 means key up
if (event.v.key.code == XWII_KEY_A && event.v.key.state == 1) {
printf("A Button Pressed\n");
} else if (event.v.key.code == XWII_KEY_A && event.v.key.state == 0) {
printf("A Button Released\n");
}
}
}
}
I then wrapped xwiimote into a C++ class that automatically managed/freed resources from xwiimote and exposes methods for reading button inputs, controlling LEDs and
read the Wii’s accelerometer (motion controls).
With this C++ class that can interface with the Wiimote, I created a C++ ROS2 node that uses the aforementioned class to publish/subscribe to various topics that allow the Wiimote to be controlled by other ROS2 nodes. If you don’t know much about ROS2 (Robot Operation System 2), every program you write is a node and you communicate with nodes through topics which can be published to and subscribed from.
In this ROS2 node I read the accelerometer/button inputs and mapped them to the standardized ROS2 gamepad inputs so existing nodes that work with gamepads, will work with the Wiimote. I also publish/subscribe to custom Wiimote topics so other nodes can have more low-level control over the Wiimote, such as reading the raw accelerometer values, controlling the LEDs, reading the battery level, and controlling the rumble motor in the Wiimote.
Unfortunately I do not have any videos at the moment of us controlling the car with a Wiimote due to the fact our team is moving spaces, but I will update this post later with a video once we finish the move.
You can view the source code for this driver here