I came across a DIY project over on the website for Maker magazine to connected a Wii Nunchuck to your computer as a mouse using an Arduino board and Python. Problem was, they only made it for Windows (they also suck at Python programming, but whatever). So after quite a bit of work over the past three days, I finally got it working.
The problem is Windows is not very secure and anything running on it can really do whatever it pleases, like say move the mouse around or click on things, without much effort. Linux has a bit more to it.
I went in originally planning on using libX11.so through ctypes.cdll, but setting up an event on that was not only pure hell, I don't even know if it is possible. Plan B presented itself as Xlib. The documents are not that complete, examples seem to be scarce and I don't have much in the way of patience.
You can check everything out here, I'm going to skim over the details and then show the Python code, all commented.
First thing first, get the library for interfacing the Nunchuck here. The readme there should tell you how to use it.
Next you want to jam some wires into your Nunchuck (the jumper wires from the starter kit fit fine without breaking anything) like so and connect it to your board to the corresponding holes.
From there you want to upload the example code for the Wii Nunchuck library so we can just process the data as a string rather than a bytestream.
Now we just need to run some Python code and you get all the mouse control I could jam into the thing (two buttons, joystick and accelerometer gave me just enough room for everything a standard modern day mouse has).
The problem is Windows is not very secure and anything running on it can really do whatever it pleases, like say move the mouse around or click on things, without much effort. Linux has a bit more to it.
I went in originally planning on using libX11.so through ctypes.cdll, but setting up an event on that was not only pure hell, I don't even know if it is possible. Plan B presented itself as Xlib. The documents are not that complete, examples seem to be scarce and I don't have much in the way of patience.
You can check everything out here, I'm going to skim over the details and then show the Python code, all commented.
First thing first, get the library for interfacing the Nunchuck here. The readme there should tell you how to use it.
Next you want to jam some wires into your Nunchuck (the jumper wires from the starter kit fit fine without breaking anything) like so and connect it to your board to the corresponding holes.
From there you want to upload the example code for the Wii Nunchuck library so we can just process the data as a string rather than a bytestream.
Now we just need to run some Python code and you get all the mouse control I could jam into the thing (two buttons, joystick and accelerometer gave me just enough room for everything a standard modern day mouse has).
#!/usr/bin/env python import serial, sys, Xlib, Xlib.display, Xlib.ext.xtest # This will be later on, setting it now global d, root # The port to which your Arduino board is connected # Change for your system and board port = '/dev/serial/by-id/usb-Arduino__www.arduino.cc__0043_64131383331351306291-if00' # The baudrate of the Arduino program baudrate = 19200 # Variables indicating the center position (no movement) of the controller # Increase the amount of play if to sensitive, decrease if not sensitive enough # Increase speed to cut it down, decrease to raise it (1 is the highest) midAccelX = 515 # Accelerometer X midAccelY = 590 # Accelerometer Y midAccelZ = 710 # Accelerometer Z (not used) midAnalogY = 134 # Analog Y midAnalogX = 127 # Analog X tollerance = 5 # Amount of play accelToll = 80 # Amout of accelerometer play speed = 4 # difference / speed = movement # Generic mouse movement def move_mouse(x,y): x = int((x - midAnalogX) / speed) y = int((midAnalogY - y) / speed) # Make sure it's not just white noise if abs(x) < tollerance: x = 0 # Move in the right direction the right amount else: if x < 0: x += tollerance else: x -= tollerance # Same deal, filtering white noise if abs(y) < tollerance: y = 0 # Move in the right direction the right amount else: if y < 0: y += tollerance else: y -= tollerance # Save the Xorg processing if we're not moving if x != 0 or y != 0: d.warp_pointer(x, y, src_window = root) d.flush() # Simulated button down def mouse_down(button): Xlib.ext.xtest.fake_input(d, Xlib.X.ButtonPress, button) d.sync() #simulated button up def mouse_up(button): Xlib.ext.xtest.fake_input(d, Xlib.X.ButtonRelease, button) d.sync() def main(): # Connect to the serial port try: ser = serial.Serial(port, baudrate) except Exception as err: sys.stderr.write(str(err) + "\n") return 0 # Mouse buttons leftDown = False rightDown = False middleDown = False # While the serial port is open while ser.isOpen(): # Read and process the line line = ser.readline() line = line.strip('\r\n') line = line.split(' ') # Not sane yet, nothing to see here if len(line) != 7: continue # Alias the info so we can make sense of the rest try: analogX = int(line[0]) analogY = int(line[1]) accelX = int(line[2]) accelY = int(line[3]) accelZ = int(line[4]) zButton = int(line[5]) cButton = int(line[6]) # It hiccuped, ignore and move on except ValueError: continue # Left Mouse Button (Z) # Button down, don't need to press again if it's already down if zButton and not leftDown: leftDown = True mouse_down(Xlib.X.Button1) # Release the button elif leftDown and not zButton: leftDown = False mouse_up(Xlib.X.Button1) # Gestures to map more buttons since we only have two # It's the C button if cButton: # Tilt right, right click if (not rightDown) and accelX - midAccelX > accelToll: rightDown = True mouse_down(Xlib.X.Button3) elif rightDown and accelX - midAccelX <= accelToll: rightDown = False mouse_up(Xlib.X.Button3) # Tilt left, middle click if (not middleDown) and midAccelX - accelX > accelToll: middleDown = True mouse_down(Xlib.X.Button2) elif rightDown and accelX - midAccelX <= accelToll: middleDown = False mouse_up(Xlib.X.Button2) # Tilt forward, scroll up if accelY - midAccelY > accelToll: mouse_down(Xlib.X.Button4) mouse_up(Xlib.X.Button4) # Tilt back, scroll down elif midAccelY - accelY > accelToll: mouse_down(Xlib.X.Button5) mouse_up(Xlib.X.Button5) # Cleanup any buttons down when gesture stops else: if rightDown: rightDown = False mouse_up(Xlib.X.Button3) if middleDown: middleDown = False mouse_up(Xlib.X.Button2) # Move the mouse move_mouse(analogX, analogY) # After the program is over, close the serial port connection ser.close() if __name__ == '__main__': # Create display and get the root d = Xlib.display.Display(None) root = d.screen().root try: main() except KeyboardInterrupt: print "" except Exception as err: sys.stderr.write(str(err) + "\n") # Regardless of what happens, close the display finally: d.close()
Remember to change your port for your board and system and adjust any values to adjust to your sensitivity and any excess give or lack there of that it may have.
No comments:
Post a Comment