我可以假定 LeafSystem 的 CalcOutput 函数的 运行 顺序吗?
Can I assume the running order of LeafSystem's CalcOutput function?
我正在这样的 LeafSystem 上工作:
class exampleLeafSystem(LeafSystem):
def __init__(self, plant):
self._plant = plant
self._plant_context = plant.CreateDefaultContext()
self.DeclareVectorIutputPort("q_v", BasicVector(6))
self.DeclareVectorOutputPort("tau", BasicVector(3), self.TauCalcOutput)
self.DeclareVectorOutputPort("xe", BasicVector(3), self.xeCalcOutput)
def TauCalcOutput(self, context, output):
q_v = self.get_input_port(0).Eval(context)
self._plant.SetPositionsAndVelocities(self._plant_context, q_v)
# Do some calculation with self._plant and self._plant_context to get the output
output.SetFromVector(tau)
def xeCalcOutput(self, context, output):
q_v = self.get_input_port(0).Eval(context)
self._plant.SetPositionsAndVelocities(self._plant_context, q_v)
# Do some calculation with self._plant and self._plant_context to get the output
output.SetFromVector(xe)
这里TauCalcOutput
和xeCalcOutput
这两个方法,我需要先更新MultibodyPlant
的状态信息,然后再进行计算,计算输出。但是,由于我不知道这两个 CalcOutput
方法被调用的顺序,为了让这两个方法使用最新的状态信息,我必须写
q_v = self.get_input_port(0).Eval(context)
self._plant.SetPositionsAndVelocities(self._plant_context, q_v)
在这两种方法中,这似乎有点不必要。如果我可以假定正在运行的 CalcOutput
方法的顺序,例如,假设 TauCalcOutput
总是先运行,那么我只能有
q_v = self.get_input_port(0).Eval(context)
self._plant.SetPositionsAndVelocities(self._plant_context, q_v)
在TauCalcOutput
方法中,不用担心XeCalcOutput
方法会使用MultibodyPlant
滞后一步的状态信息。
所以我的问题是 CalcOutput
方法的调用有特定的顺序吗?
没有。合同是输出端口可以随时以任何顺序调用,并且仅在评估时调用(例如,由下游系统)。它们被调用的顺序将取决于图中的其他系统;它们可能不会在单个模拟步骤中全部被调用(例如,如果一个系统被时间步长为 0.1 的离散时间系统消耗,而另一个系统被时间步长为 0.2),或者如果它们未连接则可能根本不会被调用。用户甚至可以手动调用 get_output_port().Eval()
。
对于避免输出端口重复计算的一般方法,您应该将共享计算的结果存储在 Context
中,作为状态或作为“缓存条目”。有关详细信息,请参阅 DeclareCacheEntry
。
对于此工作流程,具体来说,最简单的解决方案可能是检查位置和速度是否已设置为相同的值,只是为了避免重复运动学评估,例如您在此处看到的:
https://github.com/RobotLocomotion/drake/blob/6e6e37ffa677362245773f13c0628f0042b47414/multibody/inverse_kinematics/kinematic_constraint_utilities.cc#L47-L54
我正在这样的 LeafSystem 上工作:
class exampleLeafSystem(LeafSystem):
def __init__(self, plant):
self._plant = plant
self._plant_context = plant.CreateDefaultContext()
self.DeclareVectorIutputPort("q_v", BasicVector(6))
self.DeclareVectorOutputPort("tau", BasicVector(3), self.TauCalcOutput)
self.DeclareVectorOutputPort("xe", BasicVector(3), self.xeCalcOutput)
def TauCalcOutput(self, context, output):
q_v = self.get_input_port(0).Eval(context)
self._plant.SetPositionsAndVelocities(self._plant_context, q_v)
# Do some calculation with self._plant and self._plant_context to get the output
output.SetFromVector(tau)
def xeCalcOutput(self, context, output):
q_v = self.get_input_port(0).Eval(context)
self._plant.SetPositionsAndVelocities(self._plant_context, q_v)
# Do some calculation with self._plant and self._plant_context to get the output
output.SetFromVector(xe)
这里TauCalcOutput
和xeCalcOutput
这两个方法,我需要先更新MultibodyPlant
的状态信息,然后再进行计算,计算输出。但是,由于我不知道这两个 CalcOutput
方法被调用的顺序,为了让这两个方法使用最新的状态信息,我必须写
q_v = self.get_input_port(0).Eval(context)
self._plant.SetPositionsAndVelocities(self._plant_context, q_v)
在这两种方法中,这似乎有点不必要。如果我可以假定正在运行的 CalcOutput
方法的顺序,例如,假设 TauCalcOutput
总是先运行,那么我只能有
q_v = self.get_input_port(0).Eval(context)
self._plant.SetPositionsAndVelocities(self._plant_context, q_v)
在TauCalcOutput
方法中,不用担心XeCalcOutput
方法会使用MultibodyPlant
滞后一步的状态信息。
所以我的问题是 CalcOutput
方法的调用有特定的顺序吗?
没有。合同是输出端口可以随时以任何顺序调用,并且仅在评估时调用(例如,由下游系统)。它们被调用的顺序将取决于图中的其他系统;它们可能不会在单个模拟步骤中全部被调用(例如,如果一个系统被时间步长为 0.1 的离散时间系统消耗,而另一个系统被时间步长为 0.2),或者如果它们未连接则可能根本不会被调用。用户甚至可以手动调用 get_output_port().Eval()
。
对于避免输出端口重复计算的一般方法,您应该将共享计算的结果存储在 Context
中,作为状态或作为“缓存条目”。有关详细信息,请参阅 DeclareCacheEntry
。
对于此工作流程,具体来说,最简单的解决方案可能是检查位置和速度是否已设置为相同的值,只是为了避免重复运动学评估,例如您在此处看到的: https://github.com/RobotLocomotion/drake/blob/6e6e37ffa677362245773f13c0628f0042b47414/multibody/inverse_kinematics/kinematic_constraint_utilities.cc#L47-L54