Archive for the ‘ CG ’ Category

openFrameworks + Code::Blocks Install

A while back I picked up the book Programming Interactivity, since it deals with Processing, Arduino, and openFrameworks.  I know a bit of Processing and Arduino, I mainly got it as a primer to help me wrap my head around c++ through openFrameworks.  As I quickly learned though, as a c++ \ openFrameworks noob, there were some serious holes in getting the install working.  I’m sure people that are more versed in the languages take this stuff for granted, but it took me a bit of searching.  I was also surprised that I could find no all-inclusive install tutorial for using openFrameworks with Code::Blocks, the IDE the book (and apparently openFrameworks) recommend using.  Took me a while to get it working, so I will log my steps here for future generations to follow.  I should point out this is being done on a WinXP system.

Install Code::Blocks

openFrameworks does have a install process for Code::Blocks here.  I followed that exactly after downloading the Code::Blocks binary release.

Download openFrameworks

I downloaded the ‘code blocks FAT’ file and unzipped it.  One of the key pieces that was missing was where to pit this data.  I had tried a variety of subdirs on my computer, but couldn’t ever get any of the openFrameworks projects to compile.  Finally after a lot of web searching, I learned I needed to put it in:

c:\openframeworks

So that’s exactly what I did, and things started working better.

Run Some Examples

In Code::Blocks, I opened the ‘workspace’:
C:\openframeworks\apps\examples\textureExample\textureExample.workspace
(or any example workspace for that matter) and promptly bonked the ‘Build and Run’ button.  But an error occurred:

error: 'exit' is not a member of 'std'|

After doing a bit of web searching, I ran across this post, which gives directions on how to modify the ‘ofConstants.h’ file (located C:\openframeworks\libs\openFrameworks\utils) to correct the issue.

After that, ‘Build and Run’ was appeased, and my openFrameworks career has officially started.

Find Euler rotation values of Maya matrix

Sparse posting lately:  New home + new job = very busy :)

From over on my Mel Wiki, I’ve finally figure out (thanks to this post) how to extract Euler rotation values from a Maya matrix via the OpenMaya Python API.  Not sure why I’ve wanted to know how to do this, but I’m glad I now can.

Note: Below is all updated bloggin’ goodness (as of 2011-02-18)  from the original post, since I’ve learned some new tricks:

—-

After learning more from the API, I realized the differences between the MMatrix class and the MTransformationMatrix class:  MMatrix purely holds matrix data, not unlike a MVector storing vector data and nothing else. the MTransformationMatrix does everything a MMatrix does, but it has knowledge of how Maya wants it, so provides many convenience methods for accessing the data and interaction with a Maya transform node..

The big takeaway I found is this:  MTransformationMatrix objects will keep track of rotations past 360 degrees & rotation order of the node, while MMatrix objects will not. It makes sense: A matrix itself stores orientations as vectors, which have no concept how how far they’ve been ‘rotated’, so the MMatrix object doesn’t track this data. But behind the scenes, the MTransformationMatrix does track this info, which the below examples illustrate.

One more very important piece of data: When extracting a MTransformationMatrixfrom a node via a MFnTransform function, what you’re actually getting is the local transformation matrix of that node (since the MTransformationMatrix appears to track transformations specific to that node, relative to its parent).  So if you were expecting the world-space matrix, prepare to be disappointed. You can build a MTransformationMatrix out of a worldspace-acquired MMatrix, but at that point ‘rotations past 360’ would be lost.

# Python code
import math
import maya.cmds as mc
import maya.OpenMaya as om

# Define a node to pull a matrix from.
node = 'pCube1'
# Set some rotation values for comparison later:
mc.setAttr('%s.rotate'%node, 15, -45, 1000)
mc.setAttr('%s.scale'%node, 3, 3, 3)
# Change the rot order, to make sure returned euler values are correct:
mc.setAttr('%s.rotateOrder'%node, 3)

Method A: Using MTransformationMatrix

This, in my opinion, is the best solution. Via the API, you get an MDagPath object for your node, wrapper it in a MFnTransform object, and then directly extract a MTransformationMatrix object from it. This object tracks the rotation order (so you don’t have to), and rotation values past 360.

#-------------------------------------------
# Part 1: Get a MTransformationMatrix from an object for the sake of the example.
# You can use your own MTransformationMatrix if it already exists of course.

# get a MDagPath for our node:
selList = om.MSelectionList() # make a sel list # MSelectionList
selList.add(node) # add our node by name
mDagPath = om.MDagPath() # create an empty dag path # MDagPath
selList.getDagPath(0, mDagPath) # fill the dag path with our node

# Create a MFnTransform object for our MDagPath,
# and extract a MTransformationMatrix from it:
transformFunc = om.MFnTransform(mDagPath) # MFnTransform
mTransformMtx = transformFunc.transformation() # MTransformationMatrix

#-------------------------------------------
# Part 2, get the euler values
# Get an MEulerRotation object
eulerRot = mTransformMtx.eulerRotation() # MEulerRotation
# note, we *don't* have to set the rot order here...

# Convert from radians to degrees:
angles = [math.degrees(angle) for angle in (eulerRot.x, eulerRot.y, eulerRot.z)]
print angles, "MTransformationMatrix"

Method B: Using MMatrix

While this method works well, it doesn’t track rotation values past 360: We create a MMatrix object directly from the worldMatrixattr queried on our node. We then convert that to a MTransformationMatrix object so we can extract the MEulerRotation object. However, the MMatrix doesn’t pass along the rotation order of the node, and has no knowledge of rotations past 360, so the resultant MTransformationMatrix won’t know that stuff either. To get accurate rotation values, we have to save the rotation order value ahead of time, and then apply it back before retrieving values from our MEulreRotation object.

#-------------------------------------------
# Part 1:  Get a MMatrix from an object for the sake of the example.
# You can use your own MMatrix if it already exists of course.

# Get the node's rotate order value:
rotOrder = mc.getAttr('%s.rotateOrder'%node)
# Get the world matrix as a list
matrixList = mc.getAttr('%s.worldMatrix'%node) # len(matrixList) = 16
# Create an empty MMatrix:
mMatrix = om.MMatrix() # MMatrix
# And populate the MMatrix object with the matrix list data:
om.MScriptUtil.createMatrixFromList(matrixList, mMatrix)

#-------------------------------------------
# Part 2, get the euler values
# Convert to MTransformationMatrix to extract rotations:
mTransformMtx = om.MTransformationMatrix(mMatrix)
# Get an MEulerRotation object
eulerRot = mTransformMtx.eulerRotation() # MEulerRotation
# Update rotate order to match original object, since the orig MMatrix has
# no knoweldge of it:
eulerRot.reorderIt(rotOrder)

# Convert from radians to degrees:
angles = [math.degrees(angle) for angle in (eulerRot.x, eulerRot.y, eulerRot.z)]
print angles, "MMatrix"

Running the above code prints (and I reformatted the float precision issues, just so it’s easier to compare to the above values):

[15, -45, 1000] MTransformationMatrix
[15, -45, -80] MMatrix

As you can see, the MTransformationMatrix stores the rotation values past 360 deg, while the MMatrix doesn’t.

Sparse posting…

…for a bit.  I just moved (one mile south), and work is busy.  Just got cable hooked up, and still can’t find my router (in a box somewhere).  Two van-loads to Good Will, and one to the dump, and we still have more stuff than we should.  Kind of creepy how much one can acquire over time…

In the meantime, Maya 2011 new features!

http://area.autodesk.com/blogs/cory/what_s_new_in_2011

Pickling Python data to Maya attributes

Recently I made the connection that A:  It’s really easy to serialize (pickle) data in Python, and B: You can make string attributes on nodes in Maya.  It’s not that I was unaware of these topics, it’s just that they’d never occurred in the same mental conversation simultaneously before.  But when they did, it was sort of an ‘eureka moment’, and I wrote two functions to make use of this new-found power.

Making use of the cPickle module, I pickle the Python data to a string object and store to a string attr on a Maya node.  To retrieve the data, I unpickle the string attributes value back to Python data.
http://docs.python.org/library/pickle.html
http://docs.python.org/library/pickle.html#module-cPickle

import cPickle
import maya.cmds as mc

def pyToAttr(objAttr, data):
    """
    Write (pickle) Python data to the given Maya obj.attr.  This data can
    later be read back (unpickled) via attrToPy().

    Arguments:
    objAttr : string : a valid object.attribute name in the scene.  If the
        object exists, but the attribute doesn't, the attribute will be added.
        The if the attribute already exists, it must be of type 'string', so
        the Python data can be written to it.
    data : some Python data :  Data that will be pickled to the attribute
        in question.
    """
    obj, attr = objAttr.split('.')
    # Add the attr if it doesn't exist:
    if not mc.objExists(objAttr):
        mc.addAttr(obj, longName=attr, dataType='string')
    # Make sure it is the correct type before modifing:
    if mc.getAttr(objAttr, type=True) != 'string':
        raise Exception("Object '%s' already has an attribute called '%s', but it isn't type 'string'"%(obj,attr))

    # Pickle the data and return the coresponding string value:
    stringData = cPickle.dumps(data)
    # Make sure attr is unlocked before edit:
    mc.setAttr(objAttr, edit=True, lock=False)
    # Set attr to string value:
    mc.setAttr(objAttr, stringData, type='string')
    # And lock it for safety:
    mc.setAttr(objAttr, edit=True, lock=True)

def attrToPy(objAttr):
    """
    Take previously stored (pickled) data on a Maya attribute (put there via
    pyToAttr() ) and read it back (unpickle) to valid Python values.

    Arguments:
    objAttr : string : A valid object.attribute name in the scene.  And of course,
        it must have already had valid Python data pickled to it.

    Return : some Python data :  The reconstituted, unpickled Python data.
    """
    # Get the string representation of the pickled data.  Maya attrs return
    # unicode vals, and cPickle wants string, so we convert:
    stringAttrData = str(mc.getAttr(objAttr))
    # Un-pickle the string data:
    loadedData = cPickle.loads(stringAttrData)

    return loadedData

And here is some sample usage:

# Make some really special Python data you want to store to a Maya node:
specialData = {'red':52, 'green':63.3, 'blue':"ASDF"}
print "Python data to store to Maya obj.attr:"
print specialData
#Python data to store to Maya obj.attr:
#{'blue': 'ASDF', 'green': 63.299999999999997, 'red': 52}

# Define our node and attr name based on the selected object:
node = mc.ls(selection=True)[0]
objAttr = '%s.pyPickle'%node

# Store data to our node:
pyToAttr(objAttr, specialData)

# Later, get data back:
storedData = attrToPy(objAttr)
print "Restored Python Data:"
print storedData
#Restored Python Data:
#{'blue': 'ASDF', 'green': 63.299999999999997, 'red': 52}

Arduino talks to Processing, Python…

Note:  This post has been updated, see notes below.

Been enjoying tinkering around with the Arduino and the Electronic Brick Kit I recently got. It’s easy to send data from the computer to the Arduino and run sketches there, but what about the other way? The Arduino can talk back with the computer over its serial port, so at that point any language that can read the serial port can read the Arduino’s data.  Since I’m most comfortable with Python and Processing, that’s what the below code covers.

Few things to note:

  • Python has no built-in serial modules\packages (to my knowledge), but I found several references to pySerial, that appears to be the go-to source for cross-platform serial info in Python.  So you will need that.
  • Update:  After a bit of thinking, I have got Python working independently from Pygame, see notes below.
    • (Old subject):  I couldn’t get Python working directly:  When I’d run a loop to capture the serial data, it would hang the shell.  I figured this was because it wasn’t ‘advancing in time’ (just looping endlessly on the first item), so I popped the code into Pygame, and it started working flawlessly.  There probably is a way to do this in Python, but this is my first stab at reading any kind of serial data.  So the Python example is implemented via Pygame.
  • This is all authored on  Win2k OS.  Serial ports on different OS’s are handled differently.  For the Python and Processing code I define a variable that sets which com port the Arduino is on (in my case, it’s COM5), which is something that you should have already defined via the Arduino IDE.  Just make sure those values match.  And again, if you’re on Linux of Mac, the serial port values will be different.
  • On both the Processing and (the old)  Python examples, they will draw a window with a circle inside that will change in size based on the passed in serial data. Based on the sensor I was using (twist sensor) on an analog pin, this maps the voltage of the sensor into values 0-1023, which are easy to then map into the on-screen graphics. The code will also print out to the shell\IDE the captured serial values.
  • Finally, I should point out I pulled a lot of info from the book Getting Started with Arduino.

Dependencies:

Begin:

Arduino:

Here is the Arduino code.  I have a rotational sensor on analog pin 5.  But you can use any kind of sensor that you want.  I picked the rotational sensor since it’s easy to see the values change.

/**
serialSensor
Eric Pavey 2009-12-26

Sketch will print the value from the sensor to the serial port
*/

#define SENSOR 5

int val = 0;

void setup(){
  Serial.begin(9600);
}

void loop(){
  val = analogRead(SENSOR);
  // Print to the serial port:
  Serial.println(val);
  delay(100);
}

When that is uploaded to the Arduino you can hit the ‘Serial Monitor’ button in the IDE, which will pop up a new window that shows the values captured from the serial port:  When I twist my rotational sensor, I see the result print in the serial monitor.  Pretty straight-forward.  Be sure to close the serial monitor window before you run any of the below code, or they will be blocked from accessing the serial port.

Processing:

The IDE’s for Processing and Arduino are very similar; the Arduino docs say it was ‘built on’ Processing, and the resembelence is strong.  When executed, will create a window, with a white circle inside thats size is controlled by the sensor data passed through the serial port.

Here is the Processing code:

/**
 * readArduinoSerial
 * Eric Pavey 2009-12-26
 * Read data from the computers serial port, that is being fed
 * by an Arduino sketch.  It's expecting values from 0->1023.
 */

import processing.serial.*;

// Create object from Serial class
Serial myPort;  

// Converted data received from the serial port
float val = 1.0;
float prevVal = 1.0;
int minSerial = 0;
int maxSerial = 1023;
// Define which port the Arduino is on:
String arduino = "COM5";

void setup(){
  smooth();
  frameRate(30);
  size(200, 200);
  myPort = new Serial(this, arduino, 9600);
}

void draw(){
  if ( myPort.available() > 0){
    String portVal = myPort.readString();
    // Trim off any extra chars that have no meaning
    // to our sketch.  If we don't do this, we can get
    // NaN float vals when converted.
    String trimmed = portVal.trim();
    if(trimmed.length() > 0){
      // if we have a valid value, update it:
      val = float(portVal);
    }
  }
  if(val != prevVal){
    println("New val: " + val);
    prevVal = val;
  }

  background(0);
  float mapVal = map(val, minSerial, maxSerial, 1, width);
  fill(255);
  ellipse(width/2, height/2, mapVal, mapVal);
}

Python / Pygame:

Like Processing, when executed, will create a window, with a white circle inside thats size is controlled by the sensor data passed through the serial port.

Here is the Python / Pygame code:

"""
readArduinoSerial.py
Eric Pavey - 2009-12-27

Read data from the computers serial port, that is being fed
by an Arduino sketch.  It's expecting values from 0->1023.
"""

import serial
import pygame
from pygame.locals import *
pygame.init()

WIDTH = 256
HEIGHT = 256
FRAMERATE = 30
# Define which com port the Arduino is on:
ARDUINO = "COM5"

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Arduino Serial Com.")
clock = pygame.time.Clock()

ser = serial.Serial(ARDUINO, timeout=1)
floatVal = 1.0
prevVal = 1.0

def main():
    global floatVal
    global prevVal
    cirCol = Color("white")
    looping = True

    while looping:
        clock.tick(FRAMERATE)
        screen.fill(0)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                looping = False

        # Read the serial value
        ser.flushInput()
        serialValue = ser.readline().strip()

        # Catch any bad serial data:
        try:
            floatVal = float(serialValue)/8.0
            if floatVal != prevVal:
                # Print the value if it differs from the prevVal:
                print "New Val: ", floatVal
                prevVal = floatVal
        except ValueError:
            pass
        pygame.draw.circle(screen, cirCol, (WIDTH/2, HEIGHT/2), floatVal)

        # update our display:
        pygame.display.update()

if __name__ == "__main__":
    main()

Update: Here is the new Python code sans-Pygame. It will print results directly to the shell it was executed from:

import serial

ARDUINO =  "COM4"

def main():
    ser =  serial.Serial(ARDUINO, timeout=1)
    prevVal = None
    while 1:
        # Read the serial value
        ser.flushInput()
        serialValue = ser.readline().strip()
        # Catch any bad serial data:
        try:
            if serialValue != prevVal:
                # Print the value if it differs from the prevVal:
                print "New Val: ", serialValue
                prevVal = serialValue
        except ValueError:
            pass

if __name__ == '__main__':
    main()

In Conclusion…

So while the implementation in Processing \Python is pretty simple, it opens doors into what could be.  Another interesting observation is that the Processing sketch was really ‘jumpy’:  It seems to capture values that aren’t being reported by the Arduino sketch, causing the circle to ‘jump’ in size occasionally.  However, the Pygame (and updated pure Python) app seems pretty rock solid, and no ‘jumping’ is reported.