2
$\begingroup$

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 :-(
Any comments welcome and many thanks in advance!

    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)
       threading.Timer(0.05, moveObj, [val]).start()

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

taskmanager

$\endgroup$
  • 1
    $\begingroup$ 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. $\endgroup$ – rjg Oct 9 at 18:16
  • 1
    $\begingroup$ @Petra Welcome to Blender.SE. What does "plc" in the title mean? $\endgroup$ – Leander Oct 9 at 18:52
  • $\begingroup$ Many, many thanks for all your comments! @rjg: i'm trying at the moment, it seems to work well! I will post the result! $\endgroup$ – Petra Berlina Oct 10 at 8:50
  • $\begingroup$ @leander: plc means programmable logic controller - you can find these these devices in every switching cubical link $\endgroup$ – Petra Berlina Oct 10 at 8:50
4
$\begingroup$

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

$\endgroup$
2
$\begingroup$

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’})
                context.window_manager.modal_handler_add(self)
            xTimer = context.window_manager.event_timer_add(0.1, window=context.window)
        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()

enter image description here

New contributor
Petra Berlina is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.