# Moving objects by plc

I have to move an object (cube, camera, ...) according to a value from a industrial plc. In principle that works fine - but after a short while Blender (2.80) stops working. I saw, that the Windows Taskmanager shows a continiously increasing number of handles, the nuber of Threads is nearly constant. Do i have to dispose or kill anything? I can't find any hint :-(

    import bpy, time, threading
def moveObj(val): # reduced to make it easier to understand
val = val + 0.05
if val > 20:
val=0

bpy.data.objects['MyObject'].location=(val, -val, val*0.5)

moveObj(2) #call the method with start-value


• For every call to moveObj you're creating a thread that in itself runs moveObj again. You've got an infinite recursion. Use a modal operator with a timer instead in order to execute a function every x seconds. – Robert Gützkow Oct 9 '19 at 18:16
• @Petra Welcome to Blender.SE. What does "plc" in the title mean? – Leander Oct 9 '19 at 18:52
• Many, many thanks for all your comments! @rjg: i'm trying at the moment, it seems to work well! I will post the result! – Petra Berlina Oct 10 '19 at 8:50
• @leander: plc means programmable logic controller - you can find these these devices in every switching cubical link – Petra Berlina Oct 10 '19 at 8:50

Your code performs infinite recursions. For every call to moveObj you're creating a thread that in itself calls moveObj again. A solution for your goal is to use a modal operator in combination with a timer to execute a function every x seconds. An example for this can be found in operator_modal_timer.py

many thanks for your hints - this is my current solution. It works but of course it's less then ideal (using global variables, ...) Anyhow, maybe somebody can use parts of it - and also of course - comments are very welcome! Cheers Petra

import bpy
from bpy.utils import register_class, unregister_class

xTimer = None
enable = False

class ModalTimer(bpy.types.Operator):
bl_idname = "plc.modal_timer_operator"
bl_label = "timer"
val = 0

def modal(self, context, event):
if event.type == 'TIMER' and enable == True:
self.val += 0.5
if self.val > 20:
self.val=0
print("trigger, new Value: ", self.val)
bpy.data.objects['MyObject'].location=(self.val, -self.val, self.val*0.5)
return {'PASS_THROUGH'}

def execute(self, context):
global xTimer
if enable == True:
if xTimer == None:
# Add a modal handler to the window manager, for the given modal operator (called by invoke() with self,
# just before returning {‘RUNNING_MODAL’})
else:
if xTimer != None:
context.window_manager.event_timer_remove(xTimer)
return {'RUNNING_MODAL'}

class PanelPlc(bpy.types.Panel):
bl_label = "plc handling"
bl_category = "programable logic controller"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_idname = "PLC_PT_panel"

def draw(self, context):
layout = self.layout
col = layout.column(align=True)
row = col.row(align=True)
row.operator("plc.enable", text='use plc values')
row = self.layout.row()
row.operator("plc.disable", text='stop using plc values')

class Button(bpy.types.Operator):
"""enable the plc to refresh parameters"""  # tooltip
bl_idname = "plc.enable"
bl_label = "enable plc"

def execute(self, context):
global enable
enable = True
bpy.ops.plc.modal_timer_operator()
return{'FINISHED'}

class ButtonStop(bpy.types.Operator):
"""disable plc access"""    # tooltip
bl_idname = "plc.disable"
bl_label = "disable plc"

def execute(self, context):
global enable
enable = False
bpy.ops.plc.modal_timer_operator()
print('Stop')
return{'FINISHED'}

def register():
bpy.utils.register_class(ModalTimer)
bpy.utils.register_class(PanelPlc)
bpy.utils.register_class(Button)
bpy.utils.register_class(ButtonStop)

def unregister():
bpy.utils.unregister_class(ModalTimer)
bpy.utils.unregister_class(PanelPlc)
bpy.utils.unregister_class(Button)
bpy.utils.unregister_class(ButtonStop)

if __name__ == "__main__":
register()