You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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ć

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 06:42:35