Tuesday, April 2, 2013

Arduino Wii Nunchuck on Linux

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).

#!/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.

Wednesday, February 27, 2013

Chrome CORS

This is a bit of a follow-up post to my Refused to set unsafe header post. A question I was asked was about how to do something with CORS in Chrome, and my immediate findings were that it is impossible. As of recently I looked back into it and have come across a couple possible solution.

The first possible solution is to make sure to send the proper headers, as Chrome will take into account what the server says is allowed. For this, you can set the access control headers however you want. For the example, I will show the php version I found.

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Credentials: true ");
header("Access-Control-Allow-Methods: OPTIONS, GET, POST");
header("Access-Control-Allow-Headers: Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control");

This will allow you to set the various headers you would need for a CORS request. Another possibility is by using a content type that the control isn't strictly enforced. With that, it seems by setting the Content-Type to plain/text, it should go through without a problem.

I personally haven't tried either of these because I have yet to have a use for it with what I do, however I wanted to share this bit of information should anyone be curious and happen across here.

Wednesday, February 20, 2013

Fibonacci Generator

I was reading up on various types of morphism recently. While I was disappointed in the examples, as they were showing off bad practice, even if they were just an example, I got an idea. While I do have a post showing off a similar bad example with calculating a Fibonacci number, I have since refined it into a faster and more efficient method and an explanation to it you can find here.

My main focus of interest was looking at catamorphism and anamorphism. In the process of reading up, I came across other types of morphisms that while were mathematically interesting, I only saw bad programming being shown emerging from the ideas.

To explain in the simplest way possible, catamorphism is a generator and the opposite of anamorphism, which is a fold. Generators are functions that produce data on-call, using the generated data to provide more data upon the next call. This can create an infinite data type or have an end. Counting can be catamorphic in nature. For the explanation, let's look at a Python generator.

def counting(x):
    while 1:
        yield x
        x += 1

This is the equivalent to this Haskell code.

counting x = [x..]

The Python code has a bit of a more robust description to it, but the idea is the same for both, they will count from x on up until forever. Anamorphism includes things like the sum function, a list of stuff goes in, and it's all folded together with a function (in the case of sum, adding) until one result remains.

Now to the cool part and what this all means. This all means that with the magic of generators, there is an easy way to create a fibonacci generator. This is a simple one-liner in Haskell and as far as I can tell, can outdo the crappy version of the recursive Fibonacci shown everywhere else.

fibgen a b = a : (fibgen b (a + b))

That's all there is to it. The idea is you supply the first two numbers and it does the rest, forever and ever. So if you want the numbers from it, just take them. Now I suppose I can be nice and give something similar in Python, although to be honest it will look pretty much like the counting function I made.

def fibgen(a, b):
    while 1:
        yield a
        a, b = b, a + b

With only some very small tweaking, I turned the counting function into a Fibonacci generator. Now, like magic, we have an easy way to cycle through a sequence of Fibonacci numbers. I want to try to work on various problems more in this manor for when list processing or other related activities that require sequential computations, I feel it simplifies the process and gives a more elegant solution (or if nothing else, it looks cool).

Tuesday, October 16, 2012

MyBB Post BBCode Button Problem

I wanted to post this a couple days ago when the problem was brought to my attention at a forum I code for, but was too busy to get it up until now. The problem has a fix for it, here. I just want to go over quickly what is the cause of the problem and let people know it may effect Chrome and Opera. The fix was simply changing some variable names, so it wasn't anything too complicated.

So Firefox implemented something called Microdata API. This is a new thing for HTML5 that adds more information to your markup. The catch is, whether or not you are using HTML5, it still effects your site. It adds new DOM attributes that MyBB 1.6.8 is using. This particular one is itemData. That is now an object and due to the way the script was made for the post editor, it just screws it up. From what I've read, Chrome and Opera will be implementing them soon. I hope eventually it will be made to only effect HTML5 pages.

I have yet to read up how to use the Microdata API, but if you are interested, you can find notes on it here.

Friday, September 28, 2012

Haskell Network not found (Ubuntu)

So for a bit recently, I've been looking into Haskell. I really want to get into some functional programming. On thing I like doing is network programming because it actually gives me something extra to interact with than my own I/O or bugging a friend to help out or check something out. So I gave a quick glance at sockets and wanted to just see what the types look like on ghci, and of course it cannot find anything related to the network package.

> import Network.Socket

:
    Could not find module `Network.Socket':
      it is not a module in the current program, or in any known package.
Leaving GHCi.
$ ghc-pkg field network exposed-modules
ghc-pkg: cannot find package network

After a few minutes of banging my head against my desk, I say screw the gui package manager and just poke around with apt-cache search. Manage to find the library and for some reason, it was not installed by default. So here's what lead me to the package and the quick and easy fix for it.

$ apt-cache search haskell | grep network
libghc6-network-dev - Haskell network library for GHC
libghc6-network-doc - Haskell network library for GHC; documentation
libghc6-network-prof - Haskell network library for GHC; profiling libraries
$ sudo apt-get install libghc6-network-dev

Then problem solved, hoped over to ghci and it's there.

$ ghc-pkg field network exposed-modules
exposed-modules: Network Network.BSD Network.Socket.Internal
                 Network.Socket Network.URI
$ ghci
> :t Network.Socket.socket
Network.Socket.socket
  :: Network.Socket.Internal.Family
     -> Network.Socket.SocketType
     -> Network.Socket.ProtocolNumber
     -> IO Network.Socket.Socket
> 

So yeah, if you run into this, there you go. I think everyone looking into this can probably figure it out on their own, but if not, hopefully this helps. Edited the command stuff to just remove some information and lots of text in between.