Arduino to Maya Communication via Python

Arduino + light sensor talking to a sphere in Maya

I’ve wanted for some time to get my Arduino to talk with my 3d application of choice, Maya.  There were a few hurdles to overcome first:

  1. The Arduino communicates to the computer over the serial port (easily, by default).
  2. Maya (to my knowledge), has no built-in serial communication.  If you can find a built in mel command or API call, let me know 😉
  3. Maya comes with its own version of the Python scripting language (2.6ish)
  4. Python (external to Maya) has it’s own (separately installed)  pySerial module.  BUT:
    1. pySerial is a 32-bit app  (no 64-bit build I can find, and I’m not smart enough to recompile it to 64-bit).
    2. I’m running a 64-bit version of Maya, with a 64-bit version of Python = I can’t use pySerial in Maya :-(

Maya can however receive incoming communication over a commandPort, which you can ‘pretend’ is a serial port.  Below I’ll describe how to do that.  A bunch of these steps I’d already discussed in previous blog posts here or on my mel wiki, which I’ll list individually first:

Overview of the process:

  1. Author Arduino code to read sensor data and send it over the serial port.
  2. Author Python code in Maya (Maya’s version of 64-bit Python 2.6) to setup a commandPort, and to do ‘something’ with the incoming data.
  3. Author Python code external to Maya (in 32-bit Python 2.6) to receive the Arduino serial data (using pySerial), and broadcast it to the open Maya commandPort.

Notes about the commandPort code below:

  • I’ve hard-coded the commandPort data below to the address of  “127.0.0.1:7777”.
  • 127.0.0.1 is the localHost address of your machine, you shouldn’t change that.  But the “7777” is an arbitrary port number I made up, feel free to change it.
  • The important thing is that it must be consistent in all the places referenced in the code below.

Step 1:  Author Arduino Code:

This is a very simple sketch showing you the bare-bones requirements. In my case, I’ve hooked up an analog sensor to pin 5 (in my case, it’s a light sensor).
Upload this to the Arduino and start broadcasting!  You can open the Arduino Serial Monitor to see what it’s up to, but be sure to close the monitor before you do any other work.

/**
SerialSend01
Eric Pavey 2011-01-26

Sketch will print the value from the sensor to the serial port.
Sensor is plugged into analog pin 5
*/

#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);
}

Step 2: Author Python code in Maya:

The below code could eventually be made into a well-packaged Maya-Python module, but for the time being you can just paste it into the Script Editor for execution.  Thing to note:

  • The Maya commandPort command has a ‘prefix’ parameter that takes the name of a mel procedure (not Python function) that can intercept the incoming data.  Because of this, we use Python to create a simple wrapper mel procedure that in turn calls to the Python function that does the work.
  • In the below example, I have the Python function query for the existence of a ‘pSphere1’ object in Maya, and if it finds it, will scale it based on the passed in Arduino sensor values.  This should obviously be changed to something way more cool for what you’re doing :-)
# Eric Pavey - 2011-01-26
# In Maya, via Python:
import maya.cmds as mc
import maya.mel as mm

# Our mel global proc.
melproc = """
global proc portData(string $arg){
    python(("portData(\\"" + $arg + "\\")"));
}
"""
mm.eval(melproc)

# Our Python function that can be changed to do whatever we want:
def portData(arg):
    """
    Read the 'serial' data passed in from the commandPort
    """
    print "Recieved!: ", arg

    # Some silly example code to scale a sphere:
    mappedVal = (float(arg)/1023.0) * 10
    if mc.objExists('pSphere1'):
        mc.setAttr('pSphere1.scale', mappedVal, mappedVal, mappedVal)

# Open the commandPort.  The 'prefix' argument string is calling to the defined
# mel script above (which then calls to our Python function of the same name):
mc.commandPort(name="127.0.0.1:7777", echoOutput=False, noreturn=False,
               prefix="portData", returnNumCommands=True)
mc.commandPort(name=":7777", echoOutput=False, noreturn=False,
               prefix="portData", returnNumCommands=True)

Step 3: Author Python module to receive Arduino serial data and broadcast to Maya:

You must make sure you’ve previously downloaded and installed pySerial to a place where your system-installed Python can see it.  And it goes without saying you also need to have Python 2.6 installed as well.

This code will intercept the Arduino serial data, and send it to Maya over the commandPort.  It will only send new data, meaning, it will only send data that has changed from the previous data received.

# arduinoRead.py
# Python module external to Maya
# Eric Pavey - 2011-01-26

import socket
import serial

ARDUINO =  "COM3"

def main():
    maya = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    maya.connect(("127.0.0.1", 7777))
    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:
                maya.send(str(serialValue))
                prevVal = serialValue
        except ValueError:
            pass

if __name__ == '__main__':
    main()

Save the above code as a Python module, and then execute it from a shell:

c:\pythonStuff\python arduinoRead.py

This should form the link between the broadcasting Arduino, and the listening Maya session, converting from serial data to data sent over Maya’s commandPort.

Result:

In Maya, make a sphere, and rename it to ‘pSphere1’ if it’s not already.  If all the code is working, you should see the script editor print the received Arduino data whenever it changes, and you should see the scale of your sphere be effected by that data.  Magic!

Android Adventures, part 8: On a Mac?
Verlet physics in Processing
  • Trackback are closed
  • Comments (18)
    • matzerium
    • March 3rd, 2011 1:40pm

    hello,

    thank you for this tutorial. do you have any ideas, how i have to setup my external python-code to build a simple sphere? i always get the “recieved” infront of my code…

    thanks

  1. You’re getting ‘received’ in front of your code from line 19, in step 2 above. It’s just a print statement, telling you the data you received. You’re not actually receiving the string ‘received’, it’s just part of the print. If you wanted to make a simple sphere, you’d make that in step 2 as well: On line 23&24 I scale a pre-existing sphere, you could instead just put mel code in to make a sphere. But… you’ll probably end up creating thousands of spheres very quickly…

    • Kannan
    • October 30th, 2011 11:20pm

    This is something i’ve been looking for my project, thanks. My idea is to control the screen avatar using an action figure rigged with a bunch of pots and switches which is read by arduino and send it over serial port.I find UI slider manipulation using mouse is tiresome.

    So maya listens on its web server at a given port to which I can send values from even a web browser right?

    Cheers/
    Kannan

  2. In theory, yes, although I’ve never tried to issue commands from a web browser. But if you can broadcast to that port, Maya should be able to hear it just fine.

    • Kannan
    • October 31st, 2011 9:52am

    Oh my, from the browser it is not working, but from Java sockets it is OK. Still there are kinks to be ironed out, script editor reports procedure ‘w’ not found very often even though i never requested any such thing.

    More fiddling on the works.

    Thanks

  3. Well, if you get it working you should post up the solution. Interesting stuff 😉

    • Kannan
    • October 31st, 2011 10:46am

    Here it is, but before trying to run it one should open the port in maya script editor with this

    commandPort -n “:2222”

    and compile the following java application and run it.

    import java.io.*;

    import java.net.*;
    public class Class2{
    Socket socket;
    ObjectOutputStream out;
    String cmd = “file -n -new”;//move -r 1 1 1.5n”;maya commands
    Class2(){}
    void run()
    {
    try{
    socket = new Socket(“localhost”, 2222);
    out = new ObjectOutputStream(socket.getOutputStream());
    out.write(cmd.getBytes());
    out.flush();

    System.out.println(cmd);
    }
    catch(UnknownHostException unknownHost){
    System.err.println(“Unknown host!”);
    }
    catch(IOException ioException){
    ioException.printStackTrace();
    }
    finally{
    try{
    out.close();
    socket.close();
    }
    catch(IOException ioException){
    ioException.printStackTrace();
    }
    }
    }

    public static void main(String args[])
    {
    Class2 client = new Class2();
    client.run();
    }
    }

    Cheers/

  4. Cool, glad to hear you got it working 😉

  5. hey, thanks so much for the tutorial – wanted to get into this but have not known where to start.

    i got this working on mac – only thing i had to change was “COM3” to “/dev/tty/usbmodem3a21”

    best,

    matt

  6. The ports vary from OS to OS, no way you can get it right for everyone 😉 I have a PC at work, but a mac at home… what ya gonna do? 😉

    • dragon
    • November 23rd, 2011 3:12am

    What should I alter in your python script to receive data from OSCulator into Maya so I can drive a sphere ?

  7. It depends on what type of data OSCulator is passing out. In the example above, the function portData() receives a string from the port (which was passed from the Arduino, but in your case would be OSCulator), which it converts to a float. You would have to change that function to parse the passed in data the way you see fit.

    • dragon
    • November 24th, 2011 1:54pm

    thanks AKeric.

    Do you think you will be able to write a simple MEL/Python that receives data from OSCulator which has connections in a UI that you can hookup to locators and spheres? Let OSCulator drive the locators and sphere just a small simple example please?

  8. Thanks a lot!!! With many challenges on my way, I howewer made it work on mac osX and maya 2015! Akeric, could you show if you’ve done smth else with this idea?

  9. I’ve actually not done anything with it yet 😉 One of those things that seems cool, but I have yet to find any practical application for, at least in my hobbies\work.

  10. I intend to make device with two inputs for 3d artist: sliders for keyframe animation & smth like spherical 3d mouse. So, your base project could rise its usage if someone find a convenient and easy way to setup&use such devices in production.

    • itisieric
    • April 6th, 2016 7:42pm

    Thanks for the tutorial. Can you tell me how to go the other way? I would like to control the rotation of an object and then have it mach the rotation on a servo controlled with an arduino
    I would love any help you can give
    Thanks for your time

    • Lovsander
    • April 7th, 2016 12:07am

    @itisieric
    hi! do you want to do it exact with Maya? Or possible to use blendfer for example?

Comment are closed.