I am new to Blender and Python, but have made a living as a programmer. I discovered Blender while researching 3D graphics to illustrate a concept I am working on. I found the Arduino the same way. I was pleased to find out that the two had been connected by a few people in interesting ways, so I thought I’d see if I could animate my idea in real time by using inputs from the Arduino to manipulate the Blender object I had in mind.
I found several examples, but as a ‘noob’ I hit some problems right away. Not the least of which was that the documentation lags well behind the current versions of both Blender and Python and I was trying to work in the latest (stable) releases, Blender 2.6 and Python 3.2. Another problem was that most of the examples that I found were written in earlier versions of both.
However, I have found that the best way to learn a new system is to dive right in with a problem to solve and figure it out. And I have for the most part. So, I’m posting the solution in order that one, others who are trying to do something similar may find my solution useful, and two, that I can receive any constructive comment on this approach. There are always other possibly better ways to do things.
This solution is intended to manipulate an arm bone at the shoulder joint. From a position of the arm extended out to the side, the rotation on the X axis would be around the long axis of the humerus. Rotation around the Y axis would have the effect of raising and lowering the ‘arm’ laterally. And rotation on the Z axis would sweep the ‘arm’ forward and back.
I used this code found on line for the Arduino. It waits to receive a character ‘a’ and replies with 5 values in a string over the serial USB connection. (I am only using three values at this time.) I’d give credit, but the author didn’t sign it.
/*
Analog input, serial output
Reads an analog input pin, maps the result to a range from 0 to 255 and prints the results to the serial monitor.
The circuit:
* potentiometers connected to analog pin 0,1,2,3,4.
Center pin of the potentiometer goes to the analog pin.
side pins of the potentiometer go to +5V and ground
This example code is in the public domain.
*/
// These constants won't change. They're used to give names
// to the pins used:
const int analogInPin1 = A0; // Analog input pin that the potentiometer is attached to
const int analogInPin2 = A1; // Analog input pin that the potentiometer is attached to
const int analogInPin3 = A2; // Analog input pin that the potentiometer is attached to
const int analogInPin4 = A3; // Analog input pin that the potentiometer is attached to
const int analogInPin5 = A4; // Analog input pin that the potentiometer is attached to
const int analogOutPin = 11; // Analog output pin that the LED is attached to
int sensorValue1 = 0; // value read from the pot
int sensorValue2 = 0;
int sensorValue3 = 0;
int sensorValue4 = 0;
int sensorValue5 = 0;
int outputValue=0;
void setup() {
// initialize serial communications at 9600 bps:
Serial.begin(9600);
analogWrite(analogOutPin, outputValue);
}
void loop() {
if ( Serial.available()) {
char ch = Serial.read();
if ('a'==ch) {
// val = analogRead(potPin)/4;
// Serial.write(val);
// read the analog in value:
sensorValue1 = analogRead(analogInPin1)/4;
sensorValue2 = analogRead(analogInPin2)/4;
sensorValue3 = analogRead(analogInPin3)/4;
sensorValue4 = analogRead(analogInPin4)/4;
sensorValue5 = analogRead(analogInPin5)/4;
// map it to the range of the analog out:
outputValue = map(sensorValue1, 0, 1023, 0, 255);
// change the analog out value:
analogWrite(analogOutPin, outputValue);
// print the results to the serial monitor:
Serial.print(sensorValue1);
Serial.print(" ");
Serial.print(sensorValue2);
Serial.print(" ");
Serial.print(sensorValue3);
Serial.print(" ");
Serial.print(sensorValue4);
Serial.print(" ");
Serial.print(sensorValue5);
Serial.print(" ");
Serial.println();
}
}
// wait 10 milliseconds before the next loop
// for the analog-to-digital converter to settle
// after the last reading:
delay(10);
}
This is the Python script:
# doSerial.py -- Daedelus 11/8/2011
# Script to read serial values from Arduino and use them to rotate a beam.
# Values are in the range of 0 to 255 from analog input to Arduino.
# Want to rotate the beam around three axis.
import bge
import serial
from math import pi
cont = bge.logic.getCurrentController()
obj = cont.owner
sens = cont.sensors["readSer"]
serialport = serial.Serial('COM4', 9600)
p = pi/255 # pi radians = 180 degrees so since Arduino input is 0 to 255,
# in order to spread the 255 over pi radians, devide by 255
x0=[0.0,0.0,0.0] #current val from Arduino
x1=[0.0,0.0,0.0] #calculated rotation
x2=[0.0,0.0,0.0] #previous rotation
nPoints=3 # three for now
def readSer():
if sens.positive: #only want one value set from the sensor each loop
try:
serialport.write('a'.encode('ascii')) # tell Arduino to send valuse
line=serialport.readline() #read a line from the serial port
for i in range(nPoints):
x0[i]=(float)(line.split()[i]) - 127 #read each value of a line
x1[i]= (x0[i] - x2[i]) * p # calc the difference to new position
x2[i] = x0[i] # save the position
#print('x={0}, y={1}, z={2}' .format(x0[0], x0[1], x0[2]))
obj.applyRotation([-x1[0], -x1[1], -x1[2]], 0) # apply the rotation to the beam
except:
print("Exception")
One logic ‘Always’ sensor block with a positive pulse button is connected to a controller block that calls the Python module doSerial.readSer.
Thanks to all the people who provided tips and examples that I found.
<iframe width=“420” height=“315” src=“http://www.youtube.com/embed/zIje3HGcXME” frameborder=“0” allowfullscreen></iframe>