People have done some cool stuff controlling Raspberry Pi robots with Nintendo Wiimotes. Now I don’t have any robot bits, but I do have an old Wii sitting unloved upstairs, so I found the remote, put batteries in it and started to think about what I could do.
I can’t drive a robot, but I can drive a turtle – a virtual Python graphics turtle. So I made a paint program that is controlled using a Wiimote. I based the code on the excellent example on the Raspberry Pi Spy web site – Python code below.
You are in effect driving the turtle, and as such I think this is possibly quite useful for teaching how Python turtles work as you have to think from the Turtle’s point of view: if it’s facing down you need to turn right to go left. I’ve added some code to get readings from the accelerometer to turn left & right as well as using the left & right arrow buttons.
Here’s what I did in order:
- Found an original Nintendo Wii remote (NOT a Wii U!), put fresh batteries in it.
- Got a fresh Raspberry Pi 3 (thank you Picademy!) with the current version of Raspbian – this has Bluetooth built in, no dongles needed.
- Installed the cwiid library by typing
sudo apt-get install python-cwiid
in the Terminal. - Turned on Bluetooth on the Pi using the desktop GUI and making the Pi discoverable. You should not need to pair the Pi and Wiimote using the Bluetooth GUI.
- Ran the Python code below in IDLE Python 2 – I used Python 2 because that’s what the original code used and the way I installed cwiid only made the library visible in Python 2.
Here’s how to use the program:
- Run it in Python 2. Press the 1 & 2 buttons at the same time on the Wiimote and wait. If you have problems connecting, try pressing the red button on the back of the Wiimote behind the battery cover.
- Move your turtle forward and backwards using the up & down arrows.
- The left and right arrows rotate – but do not move – your turtle in increments of 5 degrees.
- You can tilt the Wiimote left to turn left, tilt right to turn right.
- Press A to change colour.
- Press 2 to make the the line thicker, 1 to make it thinner.
- Press + for pen up, – for pen down.
- Press B to toggle ‘turbo’ mode – the turtle moves further with each press.
- Press the home button to return your turtle to the middle of the screen.
- Press home and B together to clear the screen (and get a little rumble!).
- Press – and + together to quit the program (and get a bigger rumble).
Lots could be added to this – using the accelerometer for motion or clearing or changing colour, implement an undo, add background colours, more colours… and I’d really love to be able to have a Jackson Pollock paint spatter mode! Any ideas on how to code that gratefully received.
#!/usr/bin/python # based on # wii_remote_1.py # Connect a Nintendo Wii Remote via Bluetooth # and read the button states in Python. # # Original Project URL : # http://www.raspberrypi-spy.co.uk/?p=1101 # # Author : Matt Hawkins # Date : 30/01/2013 # Modified by Giles Booth July 2017 to add paint program # www.suppertime.co.uk/blogmywiki # ----------------------- # Import required Python libraries # ----------------------- import cwiid import time import turtle button_delay = 0.1 print 'Press 1 + 2 on your Wii Remote now ...' time.sleep(1) # Connect to the Wii Remote. If it times out # then quit. try: wii=cwiid.Wiimote() except RuntimeError: print "Error opening wiimote connection" quit() print 'Wii Remote connected...\n' print 'Press some buttons!\n' print 'Press PLUS and MINUS together to disconnect and quit.\n' wii.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC fred = turtle.Turtle() distance = 5 turn = 5 colourlist = ['red','orange','yellow','green','blue','purple','violet','black'] ink = 7 width = 1 while True: buttons = wii.state['buttons'] AccVar = wii.state['acc'] # detect extreme left & right tilt for turning if AccVar[0] < 100: fred.left(turn) print 'tilt left' print 'heading',fred.heading() if AccVar[0] > 140: fred.right(turn) print 'tilt right' print 'heading',fred.heading() # If Plus and Minus buttons pressed # together then rumble and quit. if (buttons - cwiid.BTN_PLUS - cwiid.BTN_MINUS == 0): print '\nClosing connection ...' wii.rumble = 1 time.sleep(1) wii.rumble = 0 exit(wii) # If Home and B buttons pressed # together then rumble briefly and clear screen. if (buttons - cwiid.BTN_HOME - cwiid.BTN_B == 0): print 'Clear screen' wii.rumble = 1 time.sleep(0.5) wii.rumble = 0 fred.clear() # Check if other buttons are pressed by # doing a bitwise AND of the buttons number # and the predefined constant for that button. if (buttons & cwiid.BTN_LEFT): print 'rotate left', turn fred.left(turn) print 'heading',fred.heading() time.sleep(button_delay) if(buttons & cwiid.BTN_RIGHT): print 'rotate right',turn fred.right(turn) print 'heading',fred.heading() time.sleep(button_delay) if (buttons & cwiid.BTN_UP): print 'move forward',distance fred.forward(distance) time.sleep(button_delay) if (buttons & cwiid.BTN_DOWN): print 'move backward', distance fred.backward(distance) time.sleep(button_delay) if (buttons & cwiid.BTN_1): width = width - 1 if width < 1: width = 1 print 'thinner line',width fred.pensize(width) time.sleep(button_delay) if (buttons & cwiid.BTN_2): width = width + 1 print 'thicker line',width fred.width(width) time.sleep(button_delay) if (buttons & cwiid.BTN_A): ink = ink + 1 if ink > 7: ink = 0 fred.color(colourlist[ink]) print 'colour',colourlist[ink] time.sleep(button_delay) if (buttons & cwiid.BTN_B): if distance == 5: distance = 10 print 'turbo mode' else: distance = 5 print 'normal mode' time.sleep(button_delay) if (buttons & cwiid.BTN_HOME): if fred.isdown(): fred.penup() fred.home() fred.pendown() else: fred.home() print 'Home' time.sleep(button_delay) if (buttons & cwiid.BTN_MINUS): print 'pen down' fred.pendown() time.sleep(button_delay) if (buttons & cwiid.BTN_PLUS): print 'penup' fred.penup() time.sleep(button_delay)
This is awesome! Love it. the WII-mote is so useful, I wish the CWIID driver would get updates so we could use the newer and generic WII-mote hardware. It has to work the same, WII’s don’t have any issues with them working, it’s just the ID.