Peripheral Input with Blender

I can’t seem to find anything about this here or on Google, but I am hoping it can be done…I want to see if I can make Blender create points based on coordinates sent over a serial connection. I know 3D Studio Max can do it with MaxScript, but I don’t have the money for that.

There’s not really much more elaboration to it than that. Given a USB device that sends serial values in the form of coordinates, could I have Blender create points at those given coordinates?

Any help would be much appreciated.

(I know this isn’t particularly interfacing with other software, but in that case any way to have it interact with the Arduino serial logger or Processing would be equally good)

EDIT: Rereading, I suppose that isn’t really very descriptive. I am using an Arduino-based machine to take input values from 3D real-life space and output the real world coordinates to a 3D program (ideally, Blender). I have found enough to know that I would probably use Python, but I don’t know how or where to start. I have experience with 3D art but not programming. I don’t know if I can handle the math within the processor, I may need to do that when the computer receives it (because the coordinates are determined based on the angle of a set of potentiometers).

I just spend a weekend by experimenting Arduino and Blender. It is not hard at all if you have a basic idea of using Python with Blender.

I made a very simple test case with game-engine where you could bounce a ball by shadowing a photoresistor with you hand. So simple but it just fun to see software reacting to your movements :slight_smile:

I’ll post more info when I’m back to machine where I have my arduino tests.

i’m interested in this thread, plz post your tests if u can… Thanks a lot guys!

I have been working on having blender control a servo (hoping to be multiple servos). I used the pySerial and pyWin32 modules for the scripts i used. it is as simple as


import serial

s = serial.Serial("COM4")  # or whatever the name is
s.write('c')
s.close()

Since the arduino uses the usb like a serial port, pyserial looks at the usb like a serial port…how neat is that! I have not had to do anything with the arduino communicating with blender, just blender to the arduino.

Here is a link to the thread ive started.
http://blenderartists.org/forum/showthread.php?t=151128

Here is the youtube link

All very creative uses of the Arduino/Blender connection capability! Mine is definitely shaping up (I’m getting the hardware design nailed down, but the software side is going slower), and I’m really liking Blender so far. I never thought I’d ever see a free program that can do so much!

So to get a little more specific, and since I am a Python noob, could anyone give a detailed idea of how I should set this up or, on a broader scale, any good tutorials on Blender/Python implementation (basic Python plugins, etc.).

For my case, what I need is a mostly passive serial connection to Blender. I want to essentially have a value capture application that runs inside Blender (either started when I want it running (good) or when Blender is running and there is a serial connection present (less good, but still usable)). Can anybody give an example of how I could implement a script to run these steps:

This runs once each time the designated button is pressed:

  1. Open serial connection
  2. Receive serial string data (would be in the format “X Y Z”)
  3. Interpret the string (set three variables pulled from the space-delimited string?)
    3.5) Convert the variables’ raw data from polar to cartesian coordinates*
  4. Create a point at the coordinates determined by the string’s values
  5. Close the connection

That’s it in a nutshell. Step 3.5 is a half step because the math itself is not important right now, I’ll deal with that part. The main hitches that I don’t know the syntax for are the main-numbered steps.

If anyone has any thoughts, I’d be much appreciative. If I have any epiphanies, I’ll be sure to keep everyone up to date and show any cool progress!

Ok, I’m quite new on this Arduino stuff and I may have misunderstood something. But anyway, here are some observations of using Arduino and Blender’s game engine.

There is a one catch when reading data from Arduino to Blender. And that’s the fact that python scripts are executed on every frame and that mean that you’ll read data from serial port prox. 60 times per second.

However, Arduino is sending data much faster. As a result, you’ll see a horrible delay in Blender. That’s because the data arduino sent is buffered and you are actually reading from buffer. So you’ll get “histororical” values from port, not the current values. And for interactive application that is not wanted.

There are couple of ways to fix this:

The simplest way is to program Arduino to send data more rarely. You could use delay function if there is nothing else that Arduino should do (delay halts everything in Arduino).

Second way is to tell Arduino when we want to get a value. So when we want a value, we sent a signal to arduino and then we read the value. This way we’ll always get the current values no matter of how high or low our framerates are.

I think that it would be also possible to run a separate python thread for Arduino input and just read values from that thread.

Here is a very simple demo using photoresistor to control a box’s position. A top of box there is a ball so you can bounce the ball with adjusting the amount of light.

Here is the blender code:

from Blender.Mathutils import Vector
import serial

port = '/dev/ttyUSB0'
pin = 0

try:
    GameLogic.SerialPort
except:
    GameLogic.SerialPort = serial.Serial(port,9600) 


# read data
valo = GameLogic.SerialPort.readline()
val = float(valo)/200

# BLENDER stuff
objs = GameLogic.getCurrentScene().getObjectList()
cube = objs["OBbox"]

cube.setPosition([1.0,1.0,val])

And in Arduino end:

/* Arduino reading photo resistor to serial
 * 
 *
 */


int analogPin=0;
int analogVal=0;


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

void loop()
{
  // get the value from photoresistor
  analogVal = analogRead(analogPin);
  Serial.println(analogVal);
  delay(100);
}

That’s it!

Attachments


Very Neat! I would recommend that, when blender needs data it sends a byte to the arduino board, and then the board sends data back. That way, like you said, the frame rate doesn’t matter. It would not slow it down anything noticeably.

However, i do see a problem! On every frame, you are opening and closing the serial port. Which in computer cycles could add up to a significant amount of time. That is the same thing i ask to solve in the thread i posted above! So i would suggest reading that to see some things to solve that.

Thanks! I made a test with request/response model and it seems to work fine.

However, i do see a problem! On every frame, you are opening and closing the serial port. Which in computer cycles could add up to a significant amount of time. That is the same thing i ask to solve in the thread i posted above! So i would suggest reading that to see some things to solve that.

You are right about about opening and closing on every frame is bad. But the code actually opens the serial port only once. The GameLogic.SerialPort is a global variable (yes, bad programming) and it is set only once in try/except clause.

Here is the code for request/response pattern. I added some checks. In linux, if you unplug Arduino and then plug it back, the port number chances. The previous port is still in /dev but you cannot write to it. That’s why I test if one can successfully write to it.

port = '/dev/ttyUSB0' 
pin = 0 
 
try: 
    GameLogic.SerialPort 
except: 
    try: 
        GameLogic.SerialPort = serial.Serial(port,9600,timeout=1)  
        print 'Port ' + port + 'found!' 
         
        #ok, we have a port. Let's test if we can write to it 
        try: 
            GameLogic.SerialPort.write('x') 
            GameLogic.serialRead = False 
            GameLogic.serialOk = True 
              
        except: 
            GameLogic.serialOk = False 
            print 'could not write to port ' + port + '!' 
         
         
    except: 
        GameLogic.serialOk = False 
        print 'no port ' + port + ' found!' 
     
 
 
# do stuff if serial port is OK 
if GameLogic.serialOk: 
    if GameLogic.serialRead: 
        valo = GameLogic.SerialPort.readline() 
        val = float(valo)/100 
        GameLogic.serialRead = False     
    else: 
        GameLogic.SerialPort.write('a') 
        GameLogic.serialRead = True     
     
 
    # BLENDER stuff 
    if GameLogic.serialRead == False: 
        objs = GameLogic.getCurrentScene().getObjectList() 
        cube = objs["OBbox"] 
        cube.setPosition([1.0,1.0,val])

And in Arduino end:

/* Arduino getting commands from serial
 * 
 * send analog value when serial receives 'a'
 *
 */

int analogPin=0;
int analogVal=0;

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

void loop() {
  if ( Serial.available()) {
    char ch = Serial.read();
    if ('a'==ch) {
      analogVal = analogRead(analogPin);
      Serial.println(analogVal);
    }
  }
}

And .blend file as a attachment.

Attachments

arduino_analog_read2.blend (152 KB)

And just one remark more. I fixed the problem with port numbers by adding a file 97-arduino.rules in /etc/udev/rules.d/ and adding following rule:

kernel=="ttyUSB*", SYSFS{idVendor}=="0403", SYSFS{idProduct}=="6001", SYMLINK="Arduino"

So now I can always trust that Arduino is in /dev/Arduino