为 C++ 绑定的系统覆盖动态
Overriding dynamics for systems which are C++ bindings
我正在尝试加载一个系统然后覆盖它的动态,这样 类 就像模拟器一样使用新的动态。这对于在 python 中声明的系统来说很简单,但似乎不适用于 C++ 绑定的系统——例如,下面的示例:
from pydrake.all import DirectCollocation, Simulator, VectorSystem
from pydrake.examples.pendulum import PendulumPlant
import numpy as np
class CustomVectorSystem(VectorSystem):
def __init__(self):
VectorSystem.__init__(self, 1, 0)
self.DeclareContinuousState(2)
def DoCalcVectorTimeDerivatives(self, context, u, x, x_dot):
x_dot[0] += u
class OverwrittenVectorSystem(CustomVectorSystem):
def __init__(self):
CustomVectorSystem.__init__(self)
def DoCalcVectorTimeDerivatives(self, context, u, x, x_dot):
x_dot = np.zeros_like(x_dot)
class OverwrittenPendulumPlant(PendulumPlant):
def __init__(self):
PendulumPlant.__init__(self)
def DoCalcTimeDerivatives(self, context, derivatives):
derivatives = np.zeros_like(derivatives)
def run_sim_step(sys, t=0.1):
context = sys.CreateDefaultContext()
simulator = Simulator(sys)
context = simulator.get_mutable_context()
context.SetContinuousState([0, 1])
context.FixInputPort(index=0, data=[1.0])
simulator.AdvanceTo(t)
return context.get_continuous_state_vector().get_value()
vector_sys = CustomVectorSystem()
overwritten_vector_sys = OverwrittenVectorSystem()
print(
"CustomVectorSystem results are {}, and {} for overwrite".format(
run_sim_step(vector_sys), run_sim_step(overwritten_vector_sys)
)
)
pendulum = PendulumPlant()
overwritten_pendulum = OverwrittenPendulumPlant()
print(
"PendulumPlant results are {}, and {} for overwrite".format(
run_sim_step(pendulum), run_sim_step(overwritten_pendulum)
)
)
returns 以下:
CustomVectorSystem results are [1.4075 1. ], and [0. 1.] for overwrite
PendulumPlant results are [0.11427129 1.24633296], and [0.11427129 1.24633296] for overwrite
对于离散系统也是如此。在这种情况下,有没有办法获得一种新方法来覆盖动力学?
这是我所期望的行为——允许重载的 C++ 系统在 pybind11 层中有一些特殊的 "trampoline" 逻辑。但这也不是我预期的工作流程。您实际上是在尝试使用 PendulumPlant
还是其他一些基数 class?从 VectorSystem
超载真的那么糟糕吗?
请注意,即使在 C++ 中,PendulumPlant
is marked final
,我们也不希望用户从中派生。 (我不认为这对您的代码有任何影响;我只是提到它作为我们设计思想的进一步证据)。
我正在尝试加载一个系统然后覆盖它的动态,这样 类 就像模拟器一样使用新的动态。这对于在 python 中声明的系统来说很简单,但似乎不适用于 C++ 绑定的系统——例如,下面的示例:
from pydrake.all import DirectCollocation, Simulator, VectorSystem
from pydrake.examples.pendulum import PendulumPlant
import numpy as np
class CustomVectorSystem(VectorSystem):
def __init__(self):
VectorSystem.__init__(self, 1, 0)
self.DeclareContinuousState(2)
def DoCalcVectorTimeDerivatives(self, context, u, x, x_dot):
x_dot[0] += u
class OverwrittenVectorSystem(CustomVectorSystem):
def __init__(self):
CustomVectorSystem.__init__(self)
def DoCalcVectorTimeDerivatives(self, context, u, x, x_dot):
x_dot = np.zeros_like(x_dot)
class OverwrittenPendulumPlant(PendulumPlant):
def __init__(self):
PendulumPlant.__init__(self)
def DoCalcTimeDerivatives(self, context, derivatives):
derivatives = np.zeros_like(derivatives)
def run_sim_step(sys, t=0.1):
context = sys.CreateDefaultContext()
simulator = Simulator(sys)
context = simulator.get_mutable_context()
context.SetContinuousState([0, 1])
context.FixInputPort(index=0, data=[1.0])
simulator.AdvanceTo(t)
return context.get_continuous_state_vector().get_value()
vector_sys = CustomVectorSystem()
overwritten_vector_sys = OverwrittenVectorSystem()
print(
"CustomVectorSystem results are {}, and {} for overwrite".format(
run_sim_step(vector_sys), run_sim_step(overwritten_vector_sys)
)
)
pendulum = PendulumPlant()
overwritten_pendulum = OverwrittenPendulumPlant()
print(
"PendulumPlant results are {}, and {} for overwrite".format(
run_sim_step(pendulum), run_sim_step(overwritten_pendulum)
)
)
returns 以下:
CustomVectorSystem results are [1.4075 1. ], and [0. 1.] for overwrite
PendulumPlant results are [0.11427129 1.24633296], and [0.11427129 1.24633296] for overwrite
对于离散系统也是如此。在这种情况下,有没有办法获得一种新方法来覆盖动力学?
这是我所期望的行为——允许重载的 C++ 系统在 pybind11 层中有一些特殊的 "trampoline" 逻辑。但这也不是我预期的工作流程。您实际上是在尝试使用 PendulumPlant
还是其他一些基数 class?从 VectorSystem
超载真的那么糟糕吗?
请注意,即使在 C++ 中,PendulumPlant
is marked final
,我们也不希望用户从中派生。 (我不认为这对您的代码有任何影响;我只是提到它作为我们设计思想的进一步证据)。