This page is about my interests, projects, and profession (video games industry). I code in Python (& PyGame), MEL (Maya Embedded Language), and Processing (Java), so you’ll see topics revolving around those languages. In addition, I enjoy a bit of photography, electronic projects (LEDs, soldering, solar gizmos, etc), making music (right now my time is vested in the harmonica), and doing art (watercolors, pen and ink), so they’ll slip in from time to time as well.
I also maintain several other ‘informative wikis’ external to this site, which are linked to via the left sidebar (also showing their current RSS feeds). They are usually updated far more often than this site, so hook into their RSS feeds if you’re interested. And most of my photography can be found over on Flickr.
Speaking of Processing and Python (PyGame), you can link to my various programs via the above title bar.
(Video Note: The flickering you see is based on the camera capture, it doesn’t actually do that…)
After making it… what to do with it? I thought it would be fun to make a Python \ Arduino library that would allow you to send Pygame graphics to the lolshield, and that’s what I implemented.
There are two main parts to the library:
The Python module pylolgraph.py for sending graphics to the Arduino\lolshield.
It requires Pygame, and pyserial. Was made with Python 2.6.5, and Pygame 1.9.1
The Arduino sketch pylolgraph.pde for receiving serial data, and displaying it.
You can also download all three in a zip here pylolgraph.zip
How to use:
My system is WinXP. Not tested on anything else.
Download pylolgraph.pde, and upload it to your Arduino. Make sure the BAUD variable matches that in your Python module (below).
Download pylolgraph.py, put it in your Python path.
Download example01.py: Set it’s BAUD variable to match that in pylolgraph.pde, and set its PORT variable to be the port your Arduino is on (will vary depending on your OS).
Start pylolgraph.pde on the Arduino. Run example01.py from the command-line or double-click the icon: You should see a small Pygame window pop up: When you click the LMB, a white donut will appear in the Pygame window. The same donut should then appear on the lolshield.
Inspect the documentation in pylolgraph.py for more details on implementation. Here is example pseudo-code for writing your own Pygame application with the code:
import pygame
import pylolgraph
# Setup some constants:
# Create a resolution that corresponds to the lolshield.
# See docs on the pylolgraph.LOLShield.setSurface() method
# for acceptable resolutions.
WIDTH, HEIGHT = (448, 288)
# Baud rate must be the same as setup in pylolgraph.pde
BAUD = 28800
# Port the Arduino is on, on my WinXP box.
PORT = 'COM4'
# Start Pygame application:
# Make surface that will have its data sent to lolshield:
screenSurf = pygame.display.set_mode((WIDTH, HEIGHT))
# Setup lolshield object:
lolshield = pylolgraph.LolShield(port=PORT, baudrate=BAUD)
# Set the surface that will have its pixel data sent to the Arduino\lolshield:
lolshield.setSurface(screenSurf)
# inside main loop:
# Draw stuff to screenSurf. Then:
lolshield.sendData()
My son and I recently soldered together a lolshield (‘lots of LEDs’) for the Arduino. The ultimate goal for this is to have Python, via Pygame (most likely) run graphics on the lolshield as if it was a mini-flatscreen. But first I need to get something sent from Python to Arduino, and this was surprisingly hard.
First, the internets came to my aid and I got some sample code allowing the Arduino to read a single character from the serial port, and blink an LED that number of times. The source was by Tod E. Kurt, and I got it off his page here. My modified version is below (modified mainly with docs so I could understand what’s going on…)
// Arduino Code:
// Below, 'character' types are defined: They hold 1 byte of data, 256 values.
// A char can be interpreted as a small number (0-255) or as a member of the
// ASCII set (which is what we deal with below). Characters expressed as
// ASCII are surrounded in single-quotes, like '5'.
// Thus each char has a corresponding numeric value can thus be tested against.
int ledPin = 13; // select the pin for the LED
int val = 0; // variable to store the data from the serial port
void setup() {
pinMode(ledPin,OUTPUT); // declare the LED's pin as output
Serial.begin(9600); // connect to the serial port
}
void loop () {
if (Serial.available()) {
// For the below examples, let's pretend that the passed-in serial
// value is character '5'.
// Since the declared variable val is an int, it converts the char
// value passed in into an int.
// If char val = '5', the numeric representation is 53.
val = Serial.read(); // read the serial port
// If the stored value is a single-digit number, blink the LED
// that number of times.
// Here we compare the int value of val against the int values
// of the string.
// Characters '0' and '9' are equivalent to integer 48 and 57.
if (val > '0' && val <= '9' ) {
Serial.println(val);
// Convert from char to int:
// From above, int conversion of val, which is char '5', is 53.
// int conversion of char '0' is 48.
// 53-48 = 5 : blink that # of times
val = val - '0';
for(int i=0; i<val; i++) {
Serial.println("blink!");
digitalWrite(ledPin,HIGH);
delay(150);
digitalWrite(ledPin, LOW);
delay(150);
}
}
}
}
Now for the Python stuff. On the ‘Arduino: Playground‘ site, I found this example Python code using the pySerial libary:
>>> import serial # if you have not already done so
>>> ser = serial.Serial('/dev/tty.usbserial', 9600)
>>> ser.write('5')
And it works, presuming you’re in the interactive Python shell. If however you try to make a module out of the same code and execute it, it will fail: No multi-blinking LED. After researching several posts of other people that had similar issue (here, here, here, and here) I tracked down the main culprit: When you make a connection to the serial port via Python, it sends a reset command to the Arduino. If you immediately send your data to the port immediately after, the Arduino won’t be initialized and ready to receive it. To solve this, we simply pause the module for a bit while the Arduino does its thing:
# simpleSerialSend.py
import sys
import serial
import time
PORT = 'COM4' # The port my Arduino is on, on my WinXP box.
def main(val=5):
# Open a connection to the serial port. This will reset the Arduino, and
# make the LED flash once:
ser = serial.Serial(PORT)
# Must given Arduino time to rest.
# Any time less than this does not seem to work...
time.sleep(1.5)
# Now we can start sending data to it:
written = ser.write(val)
ser.close()
print "Bytes Written to port:", written
print "Value written to port: '%s'"%val
if __name__ == '__main__':
args = sys.argv
try:
main(args[1])
except IndexError:
main()
This module can now be ran from the command prompt, and you can optionally pass in (from 0->9) the number of times you want the LED to blink:
c:\pyModules\simpleSerialSend.py 5
When this runs, you’ll see the LED blink once when the reset happens, a 1.5 second pause, and then the LED will blink 5 times.
What’s interesting is I tried this same thing with Processing, and failed, and I presume for the same reason: The Processing sketch was executing too fast to allow the Arduino time to warm up. And, there doesn’t seem to be a ‘pauses \ sleep \ wait’ function in Processing. I tried using java.lang.Thread, but it didn’t seem to pause the sketch until it was done running. So I need to do some more research there. Had I got that working, then the title of this blog post would probably be different
I really dig Python. It just (seemingly) has no built-in graphics capabilities, which makes me sad. Or DOES it? It ships with the Tkinter module, right? Which can display built-in graphics via its canvas widget. Based on that, presumably you can start to do some simple interactive graphical applications a-la Pygame \ Processing. Right?
Well, I thought I’d give it a shot. Considering I’ve not ever used Tkinter, this was my first real foray into that arena. But you can display graphics and bind callbacks to events, so it has the foundation for doing what I want.
My first attempt is listed below. Some things I learned:
How to query the mouse position in the Tkinter window.
How to create a rectangle, that will follow the mouse around.
How to… make a Tkinter window with callbacks that make all the magic happen.
Not very impressive on it’s own: All you get is a small window with a blue rectangle that follows the mouse. But baby steps here. I’m interested to see how far this can go.
from Tkinter import *
class Rect(object):
def __init__(self, canvas, width, height):
self.canvas = canvas
self.width = width
self.height = height
self.x = 0
self.y = 0
coord = self.getCoordinates()
self.rect = self.canvas.create_rectangle(coord[0], coord[1],
coord[2], coord[2],
fill="blue")
def getCoordinates(self):
# Used to define the sides of the rect based on a starting x,y position.
left = -self.width/2 + self.x
top = -self.height/2 + self.y
right = self.width/2 + self.x
bottom = self.height/2 + self.y
return left, top, bottom, right
def move(self, x, y):
# Move the Rect object to a new location. What is called to by the
# UI callback moveRect()
deltaX = x - self.x
deltaY = y - self.y
self.canvas.move(self.rect, deltaX, deltaY)
self.x = x
self.y = y
class App(object):
def __init__(self, width=256, height=256):
self.width = width
self.height = height
self.root = Tk()
self.root.title("tkinter_test01")
self.root.geometry("%sx%s"%(self.width, self.height))
self.canvas = Canvas(self.root, width=self.width, height=self.height)
# Bind the event to move our Rect:
self.canvas.bind("<Motion>", self.moveRect)
self.canvas.pack()
# Create our Rect object:
self.rect = Rect(self.canvas, 32, 32)
self.root.mainloop()
def moveRect(self, event):
# Callback that will move our Rect object
self.rect.move(event.x, event.y)
if __name__ == "__main__":
App()
Maya makes it easy to create an instance of a node, but I’ve found no built-in way to query what nodes in the scene are instanced. Poking around a bit in the API however, it only takes a few lines of code:
# Python code
import maya.cmds as mc
import maya.OpenMaya as om
def getInstances():
instances = []
iterDag = om.MItDag(om.MItDag.kBreadthFirst)
while not iterDag.isDone():
instanced = om.MItDag.isInstanced(iterDag)
if instanced:
instances.append(iterDag.fullPathName())
iterDag.next()
return instances
This function will return a list of all the instances in the scene, nice! I have yet to find any other function that can do this via mel.
But how would you actually uninstance them? I worked on this problem quite a bit: If you simply have a bunch of leaf nodes that are instanced, it’s not hard to do. But if you have a say ten spheres all instanced, then you make two groups of five, then instance those groups, and parent all the groups, then instance that parent… very quickly things get hairy: You try and uninstance a leaf by duplicating it, and now the duplicate appears in every other parental instance!
Like I just mentioned, most solutions I’ve found explain you can just ‘duplicate the instance’ to solve this problem, and this works on an individual instance that has no parent node that is an instance. But when you have the situation I list above, the solution I found is this: You can actually duplicate the instances parent, then delete the original parent, which will (via a loop) cleanly uninstance everything in the scene. And since the getInstances() function returns a list parent-first, this works out great:
Starting using a couple shorthand techniques today via map and lambda to save on screen real estate when authoring Python modules in Maya. I often times will troll the scene for info and want to print stuff:
Here, I find the transform name for all mesh in the scene, then print them all with tabs in front:
import sys
import maya.cmds as mc
# Get transform for each mesh:
shapes = mc.ls(type='mesh')
transforms = map(lambda x: mc.listRelatives(x, parent=True)[0], shapes)
# print with tab in front:
map(lambda x: sys.stdout.write('\t%s\n'%x), transforms)
By using our map / lambda combo, I’m able to side-step the need to write any loops. Here’s how it would look otherwise:
import maya.cmds as mc
# Get transform for each mesh:
shapes = mc.ls(type='mesh')
transforms = []
for s in shapes:
transforms.append(mc.listRelatives(s, parent=True)[0])
# print with tab in front:
for tran in transforms:
print '\t', tran
Not counting imports and comments, I halved the number of lines of code. One could argue the bottom example is possibly more readable however.