Timed Modal Operator causes delay for serial data

I want to apply data send by an Arduino to a blender object to rotate it. Now I use this script, which works, but blocks blender so I can not see the rotation:

obj = bpy.data.objects['cube']
obj.rotation_mode = 'QUATERNION'

ser = serial.Serial(SerialConnectionPath,57600, timeout=1)
time.sleep(2)
ser.write('x'.encode('ascii'))

while 1:
try :
print(x)

# apply rotation here....
except ValueError:
error = "Error"

ser.close()


The next way I tried is to use a timed modal operator from the templates which I only changed slightly. The one I use looks the following:

class cl(bpy.types.Operator):
"""Operator which runs its self from a timer"""
bl_idname = "object.op"
bl_label = "Modal Timer Operator"

_timer = None
ser = None
obj = None

def __init__(self):
self.ser = serial.Serial(SerialConnectionPath,57600, timeout=1)
time.sleep(2)
self.ser.write('x'.encode('ascii'))     #tell the arduino to begin sending data

self.obj = bpy.data.objects['cube']

def modal(self, context, event):
if event.type in {'RIGHTMOUSE', 'ESC'}:
self.cancel(context)
self.ser.close()
return {'CANCELLED'}

if event.type == 'TIMER':
try :
print(x)

# apply rotation here

except ValueError:
error = "SomeError"

return {'PASS_THROUGH'}

def execute(self, context):
wm = context.window_manager
return {'RUNNING_MODAL'}

def cancel(self, context):
wm = context.window_manager
wm.event_timer_remove(self._timer)
return {'CANCELLED'}

def register():
bpy.utils.register_class(cl)

def unregister():
bpy.utils.unregister_class(cl)

if __name__ == "__main__":
register()
bpy.ops.object.op()


The problem is, that it works, it prints out the received values, but there is a massive delay in the data (about a few seconds). Does anyone know what could cause this? Another strange thing, is that it works maybe one out of ten times when I run the script.

• – lemon Mar 15 '17 at 18:45
• Thank you for your answer. Even though I've read that thread several times before, reading it again made me discover the solution. Adding while self.ser.in_waiting !=0: in front of the try, solved the issue for me. Using if instead of while however doesn't work. Can someone maybe explain why? And this also doesn't work if I want to use multiple serial connections, because the while blocks the one connection as long as there is data available and never lets the second connection transfer its data. Would it be possible to do this with threads? – Thyra Mar 25 '17 at 17:40
• Just reading your last comment, it is difficult to visualize what is your code with several serial inputs. Could you add this code to your question or in a link in the comments? Also, by the way, what is the need to have a timer here? – lemon Mar 25 '17 at 17:49