I'm trying to simulate a simple dynamic system with Simulink (a bouncing ball) but the Simulink's 3D really sucks (because I'm on Linux and don't have the V-Realm Builder) so I was thinking to use Blender as a 3D world. I made a ball above a floor and I was thinking to change the ball's position using the data generated from a Simulink model. I'm using UDP to exchange data (and it works fine) but I can't achieve to update the scene in real-time because the refresh is really really slow. I'd like to move on the next step using data from an IMU and update the scene in real-time but I'm stuck on that.
I'd like to achieve something like this
How can I obtain a decent refresh rate?
Python code
import socket
import struct
import bpy
port = 8888
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
address = "127.0.0.1"
s.bind((address, port))
print("Waiting for data...\n")
sphere = bpy.data.objects["Sphere"]
sphere.location = (0, 0, 20)
for i in range(1000):
data, addr = s.recvfrom(1024)
data = struct.unpack('!d', data)
z = data[0]
sphere.location = (0, 0, z)
print("Location:", sphere.location)
bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
EDIT
Solution #1
I found a possible solution in this related question, which says that you'll have to edit the template. In my case, it will be something like this (and it works fine; now the only problem is that I have got some delay, maybe because of the UDP)
import bpy
import math
import socket
import struct
port = 8888
address = "127.0.0.1"
base = 20
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((address, port))
sphere = bpy.data.objects['Sphere']
sphere.location = (0, 0, base)
class ModalTimerOperator(bpy.types.Operator):
"""Operator which runs its self from a timer"""
bl_idname = "wm.modal_timer_operator"
bl_label = "Modal Timer Operator"
_timer = None
def modal(self, context, event):
if event.type in {'RIGHTMOUSE', 'ESC'}:
self.cancel(context)
s.close()
sphere.location = (0, 0, base)
return {'CANCELLED'}
if event.type == 'TIMER':
data, addr = s.recvfrom(16)
data = struct.unpack('!d', data)
z = data[0]
sphere.location = (0, 0, z)
print("Z:", z)
return {'PASS_THROUGH'}
def execute(self, context):
wm = context.window_manager
self._timer = wm.event_timer_add(0.1, context.window)
wm.modal_handler_add(self)
return {'RUNNING_MODAL'}
def cancel(self, context):
wm = context.window_manager
wm.event_timer_remove(self._timer)
def register():
bpy.utils.register_class(ModalTimerOperator)
def unregister():
bpy.utils.unregister_class(ModalTimerOperator)
if __name__ == "__main__":
register()
# test call
bpy.ops.wm.modal_timer_operator()
(I'm confident that there is a simpler way to achieve that)