Skip to content

Blender IO

Intro

Blender has a python interface that you can use to interface with the external world, you can connect networked sensors to blender and use the inputs in real-time, you can control some leds connected to your arduino, or plan the path your robot is going to follow.

Scripting interface

Python console

First of all you need a place to interact with blender via python, for that we use the Python Console:

Interacting

As a start point you can start playing with the default cube:

cube = bpy.data.objects['Cube'] cube.location.x cube.location = (2,3,4.5)

Remember that the dir() python function can give a lot of information about what on object can do and hit properties.

You can use auto-completion, if you hit the Tab key on an incomplete line Blender will ofer you the possible options to complete your sentence:

You can copy blender operators from the interface: if you open the add menu and hover your mouse over some object, you can type Ctrl-c to copy the python operator

and then got to the console or text editor and hit Ctrl-v

If you want to know more about the function you just copied you can go to the Blender Python API Documentation and in the search field type Ctrl-V

Enable python tooltips

In the preferences window Interface tabyou can enable Python Tooltips, this will give you extra python information on onrmal blender tooltips.

The blender python API

The blender documentation has a lot of information on python scripting inside blender.

The bpy python object will give you access to all the data inside blender.

Python accesses Blender’s data in the same way as the animation system and user interface; this implies that any setting that can be changed via a button can also be changed from Python.

Data Access (bpy.data)

Accessing data from the currently loaded blend file is done with the module bpy.data. This gives access to library data.

```

bpy.data.objects[‘Cube’] ```

Context Access (bpy.context)

While it’s useful to be able to access data directly by name or as a list, it’s more common to operate on the user’s selection. The context is always available from bpy.context and can be used to get the active object, scene, tool settings along with many other attributes.

```

bpy.context.object bpy.context.selected_objects bpy.context.visible_bones ```

Operators (bpy.ops)

Operators are tools generally accessed by the user from buttons, menu items or key shortcuts. From the user perspective they are a tool but Python can run these with its own settings through the bpy.ops module.

```

bpy.ops.mesh.flip_normals() {‘FINISHED’} bpy.ops.mesh.hide(unselected=False) {‘FINISHED’} bpy.ops.object.scale_apply() {‘FINISHED’} ```

Hands on

Reading mobile phone sensors »

To send SmartPhone sensor data via UDP packets to our computer in order to use it inside blender we can use any of the available apps, for this example we are going to use Sensor stream IMU+GPS android app.

Phone side

On the phone side we only need to set the ip address of our computer (in my case is 192.168.0.12), select a port (5555) and check UDP Stream. On the Toggle Sensors tab we turn on the desired sensors (the first tree are always enabled) in our case we are going to use Orientation, we also need to check the Include User-Checked… option.

Testing this app, we get the best results using the Fast speed option. To start sending data just click the Switch Stream ON button.

Blender side

Using an already written template for a python blender operator called Operator Modal Timmer is the simplest option.

This script is designed to run nay python instructions based on a timer until the user press de Esc key or the right mouse button.

We only need to add the code that allow us to connect to the UDP stream and some code to parse the data we receive. On the network side we use the socket python library, we need to add a line for importing this library:

import bpy import socket

Some code to setup the connection, this goes inside the Class but outside the defined methods, just under the timer = None line.

```

Setup UDP socket

host = ‘192.168.0.12’ port = 5555 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) s.bind((host, port)) ```

And inside the modal method under TIMER event we substitute the default code with our code to parse the received data.

```

Receive data

try: message, address = self.s.recvfrom(8192)

x = float(message.split(b',')[-2]) * 0.01745
y = float(message.split(b',')[-1]) * 0.01745
z = float(message.split(b',')[-3]) * 0.01745
print(x,y,z)

context.object.rotation_euler.x = x
context.object.rotation_euler.y = y
context.object.rotation_euler.z = z

except: pass ```

The data is received in the form of a long text string comma separated.

So we split the readings, take the last 3 and convert them to radians. Then we update the rotation of the selected object.

Controlling arduino built in led «

To start lets control the built in led on an arduino uno with a simple on/off switch

Arduino side

``` int state = 0;

void setup() { pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); Serial.begin(115200); }

void loop() {

if (Serial.available()) state = Serial.parseInt(); // Get the value while (Serial.available()) Serial.read(); // Clean the Serial port

if (state > 0) digitalWrite(LED_BUILTIN, HIGH); // Turn on the led else digitalWrite(LED_BUILTIN, LOW); // or off

delay(200); } ```

The green box has movement constrains so it can only move in X axis and in limited amount. In the python script we check his position and when it arrives to one size we send a value via the serial port to the arduino.

``` import bpy from bpy.props import IntProperty, FloatProperty import serial

class ModalOperator(bpy.types.Operator): “”“Move an object with the mouse, example”“” bl_idname = “object.modal_operator” bl_label = “Led control”

first_mouse_x: IntProperty()
first_value: FloatProperty()

# Setup serial port
ser = serial.Serial('/dev/ttyUSB1', 115200)

def modal(self, context, event):
    if event.type == 'MOUSEMOVE':
        delta = self.first_mouse_x - event.mouse_x
        context.object.location.x = self.first_value - delta * 0.01
        if context.object.location.x <= -3: 
            context.object.location.x = -3
            self.ser.write(b'0 ')
        if context.object.location.x > 3:
            context.object.location.x = 3
            self.ser.write(b'1 ')

```

Led strip fun

Moving an arrow in blender we control a moving light through the led strip

Arduino code

Turns on the leds depending on the value it receives on the serial port.

```

include

define PIN 6

define NUMPIXELS 20

Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

int value = 0;

void setup() { Serial.begin(115200); pixels.begin(); }

void loop() {

if (Serial.available()) value = Serial.parseInt(); while (Serial.available()) Serial.read();

for(int i=0; i<NUMPIXELS; i++) { if (i == value) { pixels.setPixelColor(i, pixels.Color(0, 250, 0)); } else if (abs(i - value) == 1) { pixels.setPixelColor(i, pixels.Color(0,15, 0)); } else if (abs(i - value) == 2) { pixels.setPixelColor(i, pixels.Color(0, 1, 0)); } else { pixels.setPixelColor(i, pixels.Color(0, 0, 0)); } pixels.show(); }

delay(20); } ```

Blender python script

Based on Operator Modal template (you can load this templates in blender text editor via the Templates menu). The added lines are indicated with # « This script sends a value from 0 to 20 depending on the position of the selected object (the arrow in this case), it only sends data when it changes. The result is pretty responsive and robust.

``` import bpy from bpy.props import IntProperty, FloatProperty import serial # «

class ModalOperator(bpy.types.Operator): “”“Move an object with the mouse, example”“” bl_idname = “object.modal_operator” bl_label = “Led Strip control”

first_mouse_x: IntProperty()
first_value: FloatProperty()

led = 0 # «
prevLed = 0 # «
ser = serial.Serial('/dev/ttyUSB1', 115200)  # «  # Setup serial port


def modal(self, context, event):
    if event.type == 'MOUSEMOVE':
        delta = self.first_mouse_x - event.mouse_x

        context.object.location.x = self.first_value - delta * 0.1
        if context.object.location.x < -50: context.object.location.x = -50  # «
        elif context.object.location.x > 50: context.object.location.x = 50  # «
        self.led = int(((context.object.location.x + 50) * 2) /10)   # «

        if self.led != self.prevLed: # «
            send = str(self.led) + ' '  # «
            self.ser.write(send.encode('utf8'))  # «
            print(self.led)  # «
            self.prevLed = self.led  # «

```

More ideas for trying

  • Object reacting to microphone data (a Smartcitizen kit via serial port can be used for this). Try to link different data properties: scale, rotation, moving faces along normals, etc.

  • Servo motor that copies the rotation of blender object.