适配Drake变量的numpy.sign()与numpy.clip()替代方案咨询
Drake中处理符号变量的sign与clip替代方案
问题描述
当尝试用numpy的np.sign()和np.clip()处理Drake的符号变量时会触发报错,示例代码如下:
from pydrake.all import Variable q = Variable('q') u = 1 + np.sign(q) # 无法运行 u = 1 + np.clip(q, -1, 1) # 无法运行 # 将u传入SymbolicVectorSystem的动力学模型
报错信息:
RuntimeError: You should not call
__bool__/__nonzero__onFormula. If you are trying to make a map withVariable,Expression, orPolynomialas keys (and then access the map in Python), please use pydrake.common.containers.EqualToDict`.
错误原因
numpy的sign和clip函数内部会尝试对输入值进行布尔判断(比如判断是否大于0),而Drake的符号变量(Variable/Expression)对应的Formula对象不允许直接调用__bool__方法——符号表达式在未赋值前无法确定布尔值,因此触发了上述错误。
解决方案
1. 符号表达式层面直接实现(最简便)
无需额外搭建系统模块,直接用Drake的IfThenElse函数构建等价的符号表达式,生成的结果可直接传入SymbolicVectorSystem的动力学模型:
- sign函数等价实现:
from pydrake.all import IfThenElse, Variable q = Variable('q') sign_q = IfThenElse(q > 0, 1, IfThenElse(q < 0, -1, 0)) u = 1 + sign_q - clip函数等价实现:
clip_q = IfThenElse(q > 1, 1, IfThenElse(q < -1, -1, q)) u = 1 + clip_q
2. 系统模块层面组合(适合复杂系统拆分)
如果需要将功能作为独立模块嵌入系统,可使用Drake内置模块:
- 饱和函数(clip等价):直接用
Saturation模块,无需手动搭建:from pydrake.all import Saturation saturation = Saturation(min_value=-1, max_value=1) # 将saturation模块与其他系统连接 - 符号函数:可以用
PiecewiseAffineSystem实现分段线性的符号函数,或者用上述IfThenElse表达式构建SymbolicVectorSystem作为独立模块,比port switch的方式更直接。
方案对比
- 符号表达式层面的实现最简洁,适合将函数直接嵌入动力学方程或控制器的符号表达式中,是这类场景的最优解。
- 系统模块层面的拆分适合需要功能模块化复用的复杂系统,你考虑的port switch+Saturation方式可行,但并非最简便的选择。
内容的提问来源于stack exchange,提问作者Shao Yuan Chew Chia
相关产品推荐
相关产品推荐

