How to use threads in python scripts in Blender Game Engine

Hello everyone!

I need some help again.

Are there any disadvantages to using threads in the game engine?

I receive information from a serial connection and then according to the value received I apply rotation to an object. I already did it in a script, but now I want to put this logic in one thread so that the data reception and the application of this logic would be separated from the others.

So I did it:

import serial #Comunicacion Serial
import bge #Funciones propias de blender
import bpy
import math
from bpy.props import *
from mathutils import Vector
from threading import Thread

class lerDados(Thread):
 def __init__ (self, num):
   Thread.__init__(self)
   self.num = num


 def run(self):
  ser = serial.Serial('COM5', baudrate = 9600, timeout = 1)     
  while (True):       
   #ser = serial.Serial('COM5', baudrate = 9600, timeout = 1)

   leitura = ser.readline() 
   leitura = leitura.decode("utf_8") 
   if leitura[0] == "&" :

     leitura = leitura[1:] #Eliminamos el detector de errores
     leitura = leitura[:-1] #Eliminamos el final de linea
     leitura = int(leitura)
   
     if (leitura >= 180 and leitura <= 360):
      leitura = (leitura - 360) 
    
  
     angulo = math.radians(leitura) 

     
     cont = bge.logic.getCurrentController()
     objects = cont.owner  
    
     main = bge.logic.getCurrentScene()
     cont = logic.getCurrentController()
     objects = cont.owner
     main = logic.getCurrenteScene()

     timao = main.objects["Timao"]
     leme = main.objects["Leme"]
     angulo_text = main.objects["angulo_text"]
     texto = str(angulo)
    
     angulo_text.text = texto

     rotation = timao.localOrientation.to_euler()
     rotation_leme = leme.localOrientation.to_euler()
    
     rot_degree = math.radians(5)
    
     rotacao_atual = rotation.y 
     rotacao_atual_leme = rotation_leme.z
   
     angulo = round(angulo, 1)
     rotacao_atual = round(rotacao_atual, 1)
     rotacao_atual_leme = round(rotacao_atual_leme, 1)
      
     #print('angulo e: ', angulo)
     #print('rotacao e: ', rotacao_atual)
    

    
     
     if (rotacao_atual != angulo):
      if (angulo >= 0):
        if (rotacao_atual < angulo):
          if ((angulo -rotacao_atual) > math.radians(180)):   
            rotation.y -= rot_degree   
          else:
            rotation.y += rot_degree   
        elif (rotacao_atual > angulo):
            rotation.y -= rot_degree        
                 
                     
      elif (angulo < 0):
       if(rotacao_atual > 0):
        if(rotacao_atual < angulo):
            rotation.y += rot_degree 
        elif(rotacao_atual > angulo):
             rotation.y += rot_degree
       elif(rotacao_atual < 0):
          if(rotacao_atual > angulo):
             rotation.y -= rot_degree   
          elif(rotacao_atual < angulo):
              rotation.y += rot_degree        
                 
     timao.localOrientation = rotation


     if (rotacao_atual_leme != angulo):
      if (angulo >= 0):
        if (rotacao_atual_leme < angulo):
           if ((angulo -rotacao_atual_leme) > math.radians(180)):   
              rotation_leme.z -= rot_degree   
           else:
               rotation_leme.z += rot_degree   
        elif (rotacao_atual_leme > angulo):
          rotation_leme.z -= rot_degree        
                 
                     
      elif (angulo < 0):
          if(rotacao_atual_leme > 0):
            if(rotacao_atual_leme < angulo):
              rotation_leme.z += rot_degree 
            elif(rotacao_atual_leme > angulo):
                rotation_leme.z += rot_degree
          elif(rotacao_atual_leme < 0):
             if(rotacao_atual_leme > angulo):
               rotation.y -= rot_degree   
             elif(rotacao_atual_leme < angulo):
               rotation_leme.z += rot_degree        
                 
     leme.localOrientation = rotation_leme

   ser.close()
                 

                 
receber = lerDados(None)
receber.start()

Then I get the error:

File “main.py”, line 35, in run
SystemError: bge.logic.getCurrentController (), this function is running outside the python controllers context, or blenders internal state is corrupt.

Google do not find any reference to this error, I suppose it is because when calling the thread context has been lost. But aren’t threads mini-processes within a larger process, where they share memory space? Why then do I see this error?

Rather than trying to modify things in the BGE from inside the thread, save the changes you want to make to a property on the class. Then, set up a script that runs every pulse that checks your class for changes, and applies those changes to the objects in the BGE.

By the way, the thread won’t automatically stop when you stop the BGE. I would suggest making a script that is bound to the ESC (or whatever you use to close the BGE) that shuts down the thread before stopping the BGE.

don’t put bge functions inside a thread, keep it pure python.

1 Like

you can take a look at this (th-test.blend (469.9 KB) ) you might find some useful information.

hi.I couldn’t understand your example well. I’m trying to migrate to unity if I can’t get what I want in blender, but in unity I can’t even open a serial connection.

Can you resend your sample code with comments on each line please, I would appreciate it very much

What I recommend you is to effectively run the ser.readline() bit in a thread, but use a common or global variable to store the result and then read from it using a logic script each frame to do your processing. Add a lock around it to avoid concurrent accesses, should do the trick.

Basically, when you need it, spawn the thread and make it write in a place that another script can read from. The thread will do the while true: ser.readline() bit on its own, and a regular Python script should run and feed itself from it (basically your whole processing with .getCurrentController and whatnot).

most of the stuff used in the example comes from here
https://docs.python.org/3.6/library/multiprocessing.html

here is a simplified version, all the stuff not need for basic operation is removed.
th-test1.blend (461 KB)

Hi

See if you can help me, I provide an example on bge and you return me using multiprocessing or thread?

There are a few things to consider that I don’t understand very well:

First and about the use of “while”:

I have a function to raise or lower an object

In this example, I call the rotateMotor function with parameter 1, I have on the object a sensor of the type always with true level triggered. I can understand what happens there, the sensor will always be running my script indefinitely, which causes the object to go to the position of the variable, angulo_subida.

Now why is this not possible? what is the secret?
See that I have a stop condition for my while, and made sure to tap the code to execute only once.

so blender stops completely, why?

Now suppose I have this function (rotateMotor) and want it to run in parallel with other functions. Suppose I have another function called (“shift_cano”) and it is responsible for shifting a pipe indefinitely. How can I separate these two functions to work in parallel?

my archive

i am not so sure what you are trying to do here but i did make some changes to you blend.
arduino.blend (571.4 KB)

press keys 1,2,3 to rotate the thing.

Because rotation_motor_atual never equals angulo_subida.
Blender won’t move on to the next frame until it’s finished running through that script. Because your while loop never ends, the script never finishes, thus Blender locks up because it can’t continue.