Introduction: Raspberry Pi and Wiimote Controlled Robot Arm

About: Just a high school student building awesome robots and trying to stay out of trouble. Life is fantastic!
I received a robot arm as a birthday present, but after about the first day the controller that came with it became a bit dull to use. Later I bought the usb controller that was made for the robot, but once again the canned software was limited and dull after a while. I was planning to hack the arm anyway, so I started the solution to end my boredom.

Step 1: Components

Some programming experience would be nice, but it isn't required. I'll try to keep everything simple. (Knowing me things might not go according to plan)

Parts:
Computer (I used a raspberry pi) with a python compiler, along with libusb, python-pip, pyusb, and cwiid installed
Bluetooth Connection/Dongle (for Wiimote)
OWI-535 Robotic Arm Edge with USB extension kit
Spare time to have fun with it or show off to your coworkers and friends!

Step 2: Connecting to the Robot

Since I'm doing this on a raspberry pi, I will explain everything the way I got the arm to run on it. Most everything is well documented for Windows and Mac - only a google search away so it shouldn't be much of a problem.

First we need to install libusb. Open a terminal and type:    sudo apt-get install libusb-dev
Next we need to install python-pip. In the terminal type:     sudo apt-get install python-pip
And we need to install pyusb. In the terminal type:     sudo pip install pyusb

I assume that the robot is all built and everything functions properly; if not, I noticed several instructables on how to assemble it so I won't go over that.

Now, if your robot is connected through the usb you can use the List USB command by typing "lsusb" (without quotes of course) into the terminal. You should see a device with a vendor ID of 1267 and a product ID of 0. If not, double check your connections, batteries and see if the switch is on.

Step 3: A Much Better Controller

I couldn't think of any controller greater and funner to use than a game console controller. I used a wiimote because I actually have one, and it is really easy program. With that said, I'm sure other controllers would work just as well, and maybe they are easier to use (I don't have any others to try so I don't know).

The wiimote uses bluetooth to connect so you will need a bluetooth dongle if your computer doesn't have it built in. I'm using a cirago bluetooth/wifi dongle to connect, there are plenty of tutorials on installing the stuff needed to get bluetooth running on the raspberry pi. I installed bluez through the terminal, but I'll assume that you have bluetooth fully functioning.

We need one more download to connect to the wiimote. Pop open that terminal and type:    sudo apt-get install python-cwiid
You can see a list of the bluetooth devices by typing:    hcitool scan
Press one and two on the wiimote to set it in a discovery mode. Then the wiimote will pop up with its address and the name Nintendo will be there somewhere.
We are now ready to begin using the wiimote.

Step 4: Establishing a Connection

Someone super awesome reverse engineered the usb protocol for the robot arm. They posted all of their work here:   http://notbrainsurgery.livejournal.com/38622.html

Another really cool person came up with the python code for the arm and they were nice enough to post it in the Magpi, here is the link to that (Page 14 I believe):    http://magpi.finalart.hu/The-MagPi-issue-3-en.pdf

My plan was to merge this program with one that reads the wiimote sensors and buttons.

For our program we need to do several things.
    Connect to the robot arm
    Connect to the wiimote
    Tell the wiimote what it needs to do when each button is pressed, and then do it.

We first import all of the functions we need to establish a connection:

import usb.core, usb.util, cwiid, time

Then we connect to the arm with

while (Arm == None):
        Arm = usb.core.find(idVendor=0x1267, idProduct=0x0000)


Next we define a function that lets us control the arm

def ArmMove(Duration, ArmCmd):
        Arm.ctrl_transfer(0x40, 6, 0x100, 0, ArmCmd, 1000)
        time.sleep(1)

        ArmCmd=[0,0,0]
        Arm.ctrl_transfer(0x40, 6, 0x100, 0, ArmCmd, 1000)

Each arm command uses a byte of info that is sent through the usb to the controller on the arm. Our software just manipulates the info that the arm receives.

Once the program connects to the arm it need to connect with the wiimote. Pressing both 1 and 2 at the same time sets the wiimote into pairing mode so that it can connect through bluetooth.

    Wii = None
    while (Wii==None):
        try:
            Wii = cwiid.Wiimote()
        except: RuntimeError:
            print 'Error connecting to the wiimote, press 1 and 2 '

Step 5: The Code

I followed some of the websites listed above to get an idea of how the code works, but all of the code in my program is my own work. I hope I don't scare anyone away with it. 75% of it is mostly comments and the small portion remaining is actual code. My hope is that people will be able to understand it and make it their own. I'm sure that I did some over kill in it too and that it could be simplified quite a bit, but there are many ways to skin a cat.

You can control the arm with or without the nunchuk. I could never find a program that used all of the stuff in the nunchuk (the joystick, the buttons and the accelerometer) so I wanted to make sure that there was a program that had everything in it and was easy enough to understand so that people could do what ever they wanted with the wiimote and nunchuk. To accomplish this I made sure that every button or sensor or accessory was used so that people can customize it for their own purposes. For this reason, some of the code may seem redundant, but there is a reason behind it. The only things that I didn't use were the speaker (no one can get it to work yet) and the IR sensor.

Feel free to take this code and use it any way you want!

#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#   |T|A|Y|L|O|R| |B|O|A|R|D|M|A|N| | | |R|P|I| |A|R|M|
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

'''First we need to import some files (These files contain all the commands needed for our program)
We have usb.core and usb.util - these are used to control the usb port for our arm
Next we have cwiid which communicates with the wiimote
And we have the time libary which allows us to slow or pause things'''
import usb.core, usb.util, cwiid, time

#Give our robot arm an easy name so that we only need to specify all the junk required for the usb connection once
print 'Make sure the arm is ready to go.'
print ''
Armc = 1750
Arm  = None
while (Arm == None):
    #This connects to the usb
    Arm = usb.core.find(idVendor=0x1267, idProduct=0x0000)
    #This will wait for a second, and then if the program could not connect, it tells us and tries again
    Armc = Armc + 1
    if (Armc == 2000):
        print 'Could not connect to Arm, double check its connections.'
        print 'Program will continue when connection is established...'
        print ' '
        Armc = Armc/2000
        continue

#Set up our arm transfer protocol through the usb and define a Value we can change to control the arm
Duration = 1
ArmLight = 0

#Create delay variable that we can use (Seconds)
Delay = .1
Counter = 9999
def ArmMove(Duration, ArmCmd):

    #Start Movement
    Arm.ctrl_transfer(0x40,6,0x100,0,ArmCmd,1000)
    time.sleep(Duration)

    #Stop Movement
    ArmCmd=[0,0,ArmLight]
    Arm.ctrl_transfer(0x40,6,0x100,0,ArmCmd,1000)

#Establish a connection with the wiimote
print 'Connected to arm successfully.'
print ' '
print 'Press 1 and 2 on the wiimote at the same time.'
#Connect to mote and if it doesn't connect then it tells us and tries again
time.sleep(3)
print ''
print 'Establishing Connection... 5'
time.sleep(1)
print 'Establishing Connection... 4'
time.sleep(1)
print 'Establishing Connection... 3'
Wii = None
while (Wii==None):
    try:
        Wii = cwiid.Wiimote()
    except RuntimeError:
        print 'Error connecting to the wiimote, press 1 and 2.'
print 'Establishing Connection... 2'
time.sleep(1)
print 'Establishing Connection... 1'
time.sleep(1)
print ''

#Once a connection has been established with the two devices the rest of the program will continue; otherwise, it will keep on trying to connect to the two devices

#Rumble to indicate connection and turn on the LED
Wii.rumble = 1 #1 = on, 0 = off
print 'Connection Established.'
print 'Press any button to continue...'
print ''

''' Each number turns on different leds on the wiimote
    ex) if Wii.led = 1, then LED 1 is on
    2  = LED 2          3  = LED 3          4  = LED 4
    5  = LED 1, 3       6  = LED 2, 3       7  = LED 1,2,3
    8  = LED 4          9  = LED 1, 4       10 = LED 2,4
    11 = LED 1,2,4      12 = LED 3,4        13 = LED 1,3,4
    14 = LED 2,3,4      15 = LED 1,2,3,4
    It counts up in binary to 15'''
time.sleep(1)
Wii.rumble = 0
Wii.led = 15

# Set it so that we can tell when and what buttons are pushed, and make it so that the accelerometer input can be read
Wii.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC | cwiid.RPT_EXT
Wii.state

while True:

    #This deals with the accelerometer
    '''create a variable containing the x accelerometer value
    (changes if mote is turned or flicked left or right)
    flat or upside down = 120, if turned: 90 degrees cc = 95, 90 degrees c = 145'''
    Accx = (Wii.state['acc'][cwiid.X])

    '''create a variable containing the y accelerometer value
    (changes when mote is pointed or flicked up or down)
    flat = 120, IR pointing up = 95, IR pointing down = 145'''
    Accy = (Wii.state['acc'][cwiid.Y])

    '''create a variable containing the z accelerometer value
    (Changes with the motes rotation, or when pulled back or flicked up/down)
    flat = 145, 90 degrees cc or c, or 90 degrees up and down = 120, upside down = 95'''
    Accz = (Wii.state['acc'][cwiid.Z])


    #This deals with the buttons, we tell every button what we want it to do
    buttons = Wii.state['buttons']
    #Get battery life (as a percent of 100):
    #Just delete the nunber sign inn front
    #print Wii.state['battery']*100/cwiid.BATTERY_MAX

    # If the home button is pressed then rumble and quit, plus close program
    if (buttons & cwiid.BTN_HOME):
        print ''
        print 'Closing Connection...'
        ArmLight = 0
        ArmMove(.1,[0,0,0])
        Wii.rumble = 1
        time.sleep(.5)
        Wii.rumble = 0
        Wii.led = 0
        exit(Wii)

    ''' Arm Commands Defined by ArmMove are
    [0,1,0]   Rotate Base Clockwise
    [0,2,0]   Rotate Base C-Clockwise
    [64,0,0]  Shoulder Up
    [128,0,0] Shoulder Down
    [16,0,0]  Elbow Up
    [32,0,0]  Elbow Down
    [4,0,0]   Wrist Up
    [8,0,0]   Wrist Down
    [2,0,0]   Grip Open
    [1,0,0]   Grip Close
    [0,0,1]   Light On
    [0,0,0]   Light Off

    ex) ArmMove(Duration in seconds,[0,0,0])
    This example would stop all movement and turn off the LED'''

    #Check to see if other buttons are pressed
    if (buttons & cwiid.BTN_A):
        print 'A pressed'
        time.sleep(Delay)
        ArmMove(.1,[1,0,ArmLight])
    if (buttons & cwiid.BTN_B):
        print 'B pressed'
        time.sleep(Delay)
        ArmMove(.1,[2,0,ArmLight])
    if (buttons & cwiid.BTN_1):
        print '1 pressed'
        ArmMove(.1,[16,0,ArmLight])
    if (buttons & cwiid.BTN_2):
        print '2 pressed'
        ArmMove(.1,[32,0,ArmLight])
    if (buttons & cwiid.BTN_MINUS):
        print 'Minus pressed'
        ArmMove(.1,[8,0,ArmLight])
    if (buttons & cwiid.BTN_PLUS):
        print 'Plus pressed'
        ArmMove(.1,[4,0,ArmLight])
    if (buttons & cwiid.BTN_UP):
        print 'Up pressed'
        ArmMove(.1,[64,0,ArmLight])
    if (buttons & cwiid.BTN_DOWN):
        print 'Down pressed'
        ArmMove(.1,[128,0,ArmLight])
    if (buttons & cwiid.BTN_LEFT):
        print 'Left pressed'
        ArmMove(.1,[0,2,ArmLight])
    if (buttons & cwiid.BTN_RIGHT):
        print 'Right pressed'
        ArmMove(.1,[0,1,ArmLight])

    #Here we handle the nunchuk, along with the joystick and the buttons
    while(1):
        if Wii.state.has_key('nunchuk'):
            try:
                #Here is the data for the nunchuk stick:
                #X axis:LeftMax = 25, Middle = 125, RightMax = 225
                NunchukStickX = (Wii.state['nunchuk']['stick'][cwiid.X])
                #Y axis:DownMax = 30, Middle = 125, UpMax = 225
                NunchukStickY = (Wii.state['nunchuk']['stick'][cwiid.Y])
                #The 'NunchukStickX' and the 'NunchukStickY' variables now store the stick values

                #Here we take care of all of our data for the accelerometer

                #The nunchuk has an accelerometer that records in a similar manner to the wiimote, but the number range is different
                #The X range is: 70 if tilted 90 degrees to the left and 175 if tilted 90 degrees to the right
                NAccx = Wii.state['nunchuk']['acc'][cwiid.X]
                #The Y range is: 70 if tilted 90 degrees down (the buttons pointing down), and 175 if tilted 90 degrees up (buttons pointing up)
                NAccy = Wii.state['nunchuk']['acc'][cwiid.Y]
                #I still don't understand the z axis completely (on the wiimote and nunchuk), but as far as I can tell it's main change comes from directly pulling up the mote without tilting it
                NAccz = Wii.state['nunchuk']['acc'][cwiid.Z]

                #Make it so that we can control the arm with the joystick
                if (NunchukStickX < 60):
                    ArmMove(.1,[0,2,ArmLight])
                    print 'Moving Left'
                if (NunchukStickX > 190):
                    ArmMove(.1,[0,1,ArmLight])
                    print 'Moving Right'
                if (NunchukStickY < 60):
                    ArmMove(.1,[128,0,ArmLight])
                    print 'Moving Down'
                if (NunchukStickY > 190):
                    ArmMove(.1,[64,0,ArmLight])
                    print 'Moving Up'

                #Make it so that we can control the arm with tilt Functions
                #Left to Right
                if (Accx < 100 and NAccx < 90 ):
                    ArmMove(.1,[0,2,ArmLight])
                    print 'Moving Left'
                if (Accx > 135 and NAccx > 150):
                    ArmMove(.1,[0,1,ArmLight])
                    print 'Moving Right'

                #Up and Down
                if (Accy < 100 and NAccy < 90):
                    ArmMove(.1,[64,0,0])
                    print 'Moving Up'
                if (Accy > 135 and NAccy > 150):
                    ArmMove(.1,[128,0,0])
                    print 'Moving Down'

                #Here we create a variable to store the nunchuck button data
                #0 = no buttons pressed
                #1 = Z is pressed
                #2 = C is pressed
                #3 = Both C and Z are pressed

                ChukBtn = Wii.state['nunchuk']['buttons']
                if (ChukBtn == 1):
                    print 'Z pressed'
                    ArmLight = 0
                    ArmMove(.1,[0,0,ArmLight])
                if (ChukBtn == 2):
                    print 'C pressed'
                    ArmLight = 1
                    ArmMove(.1,[0,0,ArmLight])
                #If both are pressed the led blinks
                if (ChukBtn == 3):
                    print 'C and Z pressed'
                    ArmMove(.1,[0,0,0])
                    time.sleep(.25)
                    ArmMove(.1,[0,0,1])
                    time.sleep(.25)
                    ArmMove(.1,[0,0,0])
                    time.sleep(.25)
                    ArmMove(.1,[0,0,1])
                    time.sleep(.25)
                    ArmMove(.1,[0,0,0])
                    time.sleep(.25)
                    ArmMove(.1,[0,0,1])
                    time.sleep(.25)
                    ArmMove(.1,[0,0,0])

                #Any other actions that require the use of the nunchuk in any way must be put here for the error handling to function properly
                break


#This part down below is the part that tells us if no nunchuk is connected to the wiimote
            except KeyError:
                print 'No nunchuk detected.'
        else:           
            if (ArmLight == 0):
                if (Accz > 179 or Accz < 50):
                    ArmLight = 1
                    ArmMove(.1,[0,0,ArmLight])
                    time.sleep(.5)
            elif (ArmLight == 1):
                if (Accz > 179 or Accz < 50):
                    ArmLight = 0
                    ArmMove(.1,[0,0,ArmLight])
                    time.sleep(.5)

            if (Counter == 10000):
                print 'No nunchuk detected.'
                Counter = Counter/10000
                break
            Counter = Counter + 1
            break



Copy the code into a python editor and then save it out. If the editor is still open then you can run the program with F5. You can also run it by opening a terminal, navigating to the location of the program and then typing: sudo python filename.py
Just replace filename with the actual name of the file (you still have to copy the code into the editor and then save it).
The photo shows: sudo Nunchuk_W_Arm.py, but I forgot to add the python in there. It's supposed to be: sudo python Nunchuk_W_Arm.py
I'm now working on a version of the program that has an actual interface with buttons to control the arm and stuff that display the wiimote goodies. The wiimote can still be used to control the arm; its just a more visual program.

Step 6: Controlling the Robot

There are lots of things to control on the robot so I tried to keep everything organized. Pictures speak louder than words.

The nunchuk doesn't need to be connected to run everything, I just wanted to keep everything flexible. The only difference between using and not using the nunchuk are: with the nunchuk attached flicking the remote will not toggle the light on and off, the joystick adds another way to rotate the arm and move the base, C and Z are used to turn on and off the light, tilting both the nunchuk and the wiimote will rotate/control the base.

Microcontroller Contest

Participated in the
Microcontroller Contest