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

PyDrake状态向量使用关系运算符触发RuntimeError的解决咨询

Drake中DoCalcTimeDerivatives条件判断的RuntimeError解决方法

问题背景

我在为植物模型编写DoCalcTimeDerivatives方法时,通过大量条件语句定义导数,但构建Diagram时触发如下RuntimeError:

RuntimeError: You should not call __bool__ / __nonzero__ on Formula. If you are trying to make a map with Variable, Expression, or Polynomial as keys (and then access the map in Python), please use pydrake.common.containers.EqualToDict`.

尝试用pydrake提供的lt函数替代原生比较运算符后,仍出现相同错误。

复现代码

from pydrake.all import (
    DiagramBuilder,
    LeafSystem_,
    SceneGraph,
    namedview,
    lt,
)

TestState = namedview(
    "TestState", ["x", "xdot"]
)

@TemplateSystem.define("TestPlant_")
def TestPlant_(T):
    class Impl(LeafSystem_[T]):
        def _construct(self, converter=None):
            LeafSystem_[T].__init__(self, converter)
            self.DeclareVectorInputPort("force", 1)
            self.DeclareContinuousState(2)
            self.DeclareVectorOutputPort("state", 2, self.CopyStateOut)

        def _construct_copy(self, other, converter=None):
            Impl._construct(self, converter=converter)

        def DoCalcTimeDerivatives(self, context, derivatives):
            s = TestState(
                context.get_mutable_continuous_state_vector().CopyToVector()
            )
            force = self.EvalVectorInput(context, 0)[0]

            sdot = TestState(s[:])
            sdot[0] = s[1]
            if (s[0] < 0):
                sdot[1] = force
            else:
                sdot[1] = 2*force
            derivatives.get_mutable_vector().SetFromVector(sdot[:])

        def CopyStateOut(self, context, output):
            x = context.get_continuous_state_vector().CopyToVector()
            output.SetFromVector(x)
    return Impl


TestPlant = TestPlant_[None]
builder = DiagramBuilder()
glider = builder.AddSystem(TestPlant())
scene_graph = builder.AddSystem(SceneGraph())
diagram = builder.Build()

报错详情

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Cell In[18], line 49
     47 glider = builder.AddSystem(TestPlant())
     48 scene_graph = builder.AddSystem(SceneGraph())
---&gt; 49 diagram = builder.Build()

Cell In[18], line 33, in TestPlant_..Impl.DoCalcTimeDerivatives(self, context, derivatives)
     31 sdot = TestState(s[:])
     32 sdot[0] = s[1]
---&gt; 33 if (s[0] < 0):
     34     sdot[1] = force
     35 else:

RuntimeError: You should not call `__bool__` / `__nonzero__` on `Formula`. If you are trying to make a map with `Variable`, `Expression`, or `Polynomial` as keys (and then access the map in Python), please use pydrake.common.containers.EqualToDict`.

已尝试的方案

从官方文档看到说明:

As a workaround, this module provides the following vectorized operators, following suit with the operator builtin module: lt, le, eq, ne, ge, and gt.

于是将判断语句改为:

if (lt(s[0],0)):         # instead of if (s[0] < 0):

但仍触发相同错误:

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Cell In[19], line 49
     47 glider = builder.AddSystem(TestPlant())
     48 scene_graph = builder.AddSystem(SceneGraph())
---&gt; 49 diagram = builder.Build()

Cell In[19], line 33, in TestPlant_..Impl.DoCalcTimeDerivatives(self, context, derivatives)
     31 sdot = TestState(s[:])
     32 sdot[0] = s[1]
---&gt; 33 if (lt(s[0],0)):
     34     sdot[1] = force
     35 else:

RuntimeError: You should not call `__bool__` / `__nonzero__` on `Formula`. If you are trying to make a map with `Variable`, `Expression`, or `Polynomial` as keys (and then access the map in Python), please use pydrake.common.containers.EqualToDict`.

解决方案

问题核心:不能用Python原生if语句判断Drake的Expression/Formula对象。当系统模板参数为None(符号模式)时,s[0]是Expression类型,lt(s[0],0)返回Formula对象,Python的if会尝试调用其__bool__方法,这在Drake中是被禁止的。

正确做法是用分段表达式替代Python条件分支,使用Drake提供的if_then_else函数构建符号化的条件逻辑:

修改后的DoCalcTimeDerivatives方法:

from pydrake.all import if_then_else

# ... 其他代码保持不变 ...

def DoCalcTimeDerivatives(self, context, derivatives):
    s = TestState(
        context.get_mutable_continuous_state_vector().CopyToVector()
    )
    force = self.EvalVectorInput(context, 0)[0]

    sdot = TestState(s[:])
    sdot[0] = s[1]
    # 用if_then_else构建分段表达式,替代Python原生if分支
    sdot[1] = if_then_else(s[0] < 0, force, 2*force)
    derivatives.get_mutable_vector().SetFromVector(sdot[:])

原理说明

  • if_then_else(condition, true_val, false_val)会生成一个符号表达式,在符号模式下完整保留条件逻辑,不会触发__bool__调用。
  • 系统运行在数值模式时,该表达式会自动计算对应分支的值,行为与原生条件分支一致。
  • 复杂多分支场景可嵌套使用if_then_else,或通过PiecewiseFunction类管理。

内容的提问来源于stack exchange,提问作者Jay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 03:47:03