py_trees库中如何在非主线程调用BehaviourTree.setup()方法并解决ValueError: signal only works in main thread错误
解决py_trees BehaviourTree.setup()在非主线程的信号错误
我之前也碰到过一模一样的问题,根源在于py_trees的默认setup()流程会尝试注册SIGUSR1信号来处理超时,但Python的signal模块只允许在主线程中操作信号。要在不把setup()移到主线程的前提下解决,这里有几个实用的方案:
方案1:绕过信号注册,手动调用底层setup函数
py_trees的BehaviourTree.setup()其实是封装了py_trees.trees.setup()函数,而这个底层函数允许你通过interrupt_handler参数跳过信号注册逻辑。直接调用这个底层函数,传入interrupt_handler=None就能避开信号操作:
from py_trees import trees # 替代原来的 behaviour_tree.setup(timeout=15.0) trees.setup( root=behaviour_tree.root, timeout=15.0, interrupt_handler=None, # 关键:禁用信号式超时处理 visitor=behaviour_tree.visitor )
这个方法的核心逻辑是:当interrupt_handler设为None时,setup流程会跳过信号注册的代码块,自然也就不会触发signal only works in main thread的错误。同时,它依然会递归调用所有行为树节点的setup()方法,完成正常的初始化工作。
方案2:自定义超时处理(如果需要保留超时功能)
如果你的场景必须保留setup的超时检测,但又不能依赖信号,可以自己实现基于线程的超时逻辑:
import threading from py_trees import trees def setup_with_timeout(tree, timeout): setup_completed = threading.Event() def setup_task(): # 无信号的setup调用 trees.setup( root=tree.root, timeout=None, # 关闭内置超时,用自定义逻辑替代 interrupt_handler=None, visitor=tree.visitor ) setup_completed.set() # 启动setup任务线程 setup_thread = threading.Thread(target=setup_task) setup_thread.start() # 等待超时或任务完成 if not setup_completed.wait(timeout=timeout): # 自定义超时处理,比如抛出异常或记录日志 raise TimeoutError("BehaviourTree setup timed out")
这个方法通过线程事件来监控setup的完成状态,既避开了信号依赖,又保留了超时检测的能力。
为什么会出现这个错误?
Python的signal模块有严格的限制:只有主线程可以注册或修改信号处理函数。py_trees的默认setup()流程会注册SIGUSR1信号,用于在setup超时时中断初始化流程,这就导致在非主线程调用时直接触发ValueError。
内容的提问来源于stack exchange,提问作者Jakob Domislović
相关产品推荐
相关产品推荐

