BGE Python + OSC Performance issues

I’m working on connecting some things into the game engine over OSC, and I’m running into some frustrating performance issues. Essentially, if I’m streaming more than one or two values, I get this terrible lag (several seconds), and it seems to get worse the longer the game is running.

My main interest is in working with the Wiimote, which does send a lot of data constantly.

First, I followed this great tutorial http://www.local-guru.net/blog/2009/03/08/using-the-blendergameengine-as-osc-client.

that worked fine, I can send a single value from Pd and get realtime response in Blender. I extended that code to take data sent from Marije Baalman’s WiiOSC http://www.nescivi.nl/?p=73

It works, but the lag is awful, particularly noticeable for the buttons. Similar python code works great standalone, so it’s not an issue with slowness in python, pybluez, or the python osc library; it seems to be something unique to Blender. Any suggestion on what might be going on?

I’m testing this on two platforms - Kubuntu 8.04, with Blender 2.45, and OSX 10.4, with Blender 2.48. The behavior is the same on both platforms.

Here’s the code I’m using Blender:


import GameLogic
import Blender
import Rasterizer
from Blender import Material
import socket
import osc

Rasterizer.showMouse(1)
cont = GameLogic.getCurrentController()
own = cont.getOwner()

if not own.connected:
    print "Connecting.."
    own.connected = 1

    mesh = own.getMesh()
    for i in range(mesh.getVertexArrayLength(0)):
        v = mesh.getVertex(0,i)
        v.color = [0.0, 1.0, 0.0, 1.0]

    GameLogic.socket = socket.socket( socket.AF_INET, socket.    SOCK_DGRAM )
    
    GameLogic.socket.bind(('localhost', 9001))
    GameLogic.socket.setblocking(0)
    GameLogic.socket.settimeout(0.1)
    
else:
    try:
        data = GameLogic.socket.recv(1024)
        msglist = osc.decodeOSC(data)    
        if type(msglist[0]) == list:
            for msg in msglist:
                address=msg[0]
                
                if address=="/wii/acc/x":
                    x=msg[3] * 5
                    own.setPosition([x,0,0])
                elif address=="/wii/keys/a":
                    value=msg[3]
                    if value==1:
                        own.scaling=[2,2,2]
                    else:
                        own.scaling=[1,1,1]
            
    except socket.error:
        pass        

At first I thought this might be a python issue, so I put together a standalone test listener using the same python osc library (I’m using simpleOSC.py from ixi: http://www.ixi-audio.net/content/body_backyard_python.html)

My standalone app works great, no lag at all:


import osc
import time
import sys
import socket

keys={}

accels=[0,0,0]

wiimoteX = 0
wiimoteY = 0

def handleMessage(msg):
    global keys
    global accels
    s=msg[0]
    v=msg[3]
    
    msgpath = s.split('/')
    
    if msgpath[1]=='wii':
        if msgpath[2]=='keys':
            k=msgpath[3]
            keys[k]=v
            
        elif msgpath[2]=='acc':
            axis=msgpath[3]
            if axis=='x':
                accels[0]=v
            elif axis=='y':
                accels[1]=v
            elif axis=='z':
                accels[2]=v
                
def getOSCData():
    global oscListener
    data=None
    try:
        data = oscListener.recv(1024)
    except:
        pass
    if data != None:
        message=osc.decodeOSC(data)
        #print message
        if type(message[0])==str:
            handleMessage(message)
        elif type(message[0])==list:
            for msg in message:
                handleMessage(msg)

oscListener = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)
oscListener.bind(('',9001))
oscListener.setblocking(0)


print oscListener
print 'ready to receive messages on port 9001'

while 1:
    getOSCData()
    print "Accels: %.3f %.3f %.3f" % (accels[0], accels[1], accels[2]),
    print keys


thanks

I did a little more experimenting with sending OSC messages from Pd. Here’s what I’ve found so far.

I made a test patch, extending that demo from local-guru, and adding more messages and automating them with sine waves. So, now it sends a 3-float message for color and a 3-float message for scaling.

The quickest way to measure lag seemed to be to stop the message flow, and see how long it takes for Blender to catch up. Setting the update delay (how fast Pd throws OSC messages out) affected the lag.

With a delay of 33 ( approx 30 fps), there’s no noticeable lag. At higher fps, the lag starts to appear, going up to 6 seconds.

I attached an image of the pd patch (it won’t let me upload the actual .pd file …), and my .blend, if anyone wants to try it out.

Has anyone else had this experience with OSC->Blender?

Attachments


blender_osc_local-guru_2.blend (117 KB)

I don’t have any experience with OSC, but just glancing over your code I noticed that you’re using the Blender module in the game engine, which is generally not a good idea even if it somehow works, because that module is not carried over in BGE standalones (if you ever plan to make one).

Also, I don’t know if this works now, but as far back as I can remember the owner object could only be assigned the types which are available in the logic buttons menu (stuff you can make with the “add property” button), assigning anything else to it (like a list) makes for weird behavior.

So make sure that lists you assign to own are properly stored.

Good luck.

Hi.
I have the same issue here. In fact it seems that, even if OSC is threaded, it run at logic thick rate. So if you send more information per second than your tickrates, he will begin to stack information and restore it after.
I saw two solutions but didn’t realized to implement both :

  • drop information if the last isn’t treated
  • have real thread working for network in BGE.

Any idea for one of this?

I hope to be forgiven for bumping a relative old thread but here it goes:
I’m starting experiments with OSC. But from the look of it it’s not different from any other application that sends UDP sockets. The UDP socket goes from your server application to the OS, and from the OS to the client. If the server sends more fast than the client receives the OS buffer the data.

1. How to test it?
In your standalone application add a time.sleep(2) after you read the data. It will quickly reveals that the data received is not the recent one but the buffered.

2. How to solve it?
Here we are trashing data. In other words, to receive data from the server until the buffer is empty (what will raise an exception). Now you can use the last valid data before the exception and make sure it’s the most fresh one.
Example of code you can use every frame:
(for a stand-alone move it inside a while loop)


def read_fresh_socket(s_in):
    try:
        # getting first data value from buffer
        data, port = s_in.recvfrom(1024)

        # keep trying to get new data until buffer is empty
        try:
            trash = data
                while(True):
                    data = trash
                    trash, port = s_in.recvfrom(1024)
            except:
                # we force this exception to happen
                # that way we know the buffer is empty
                pass

        except Exception as E:
            # print (E)
            pass
        else:
            # use the data
            print (data)

It works for regular UDP it should work for OSC as well (I’ll test it this week so I really hope it works :slight_smile: )