离散回调中修改的State未在连续回调中生效,求解析
问题描述
以下是我实现的Drake LeafSystem代码:
class TestSystem(LeafSystem): def __init__(self, num_internal_bodies, internal_object_list): self.dummy_idx = self.DeclareDiscreteState(1) self.spatial_forces_output_port = self.DeclareAbstractOutputPort( "spatial_forces_output", lambda: forces_cls(), self.DoCalcAbstractOutput ) self.DeclarePeriodicDiscreteUpdateEvent( period_sec=2e-3, # 原注释有误,实际为2ms步长 offset_sec=0.0, # 第一个事件在t=0触发 update=self.Update) # 调用下方定义的Update方法 def Update(self, context, discrete_state): context.get_mutable_discrete_state(self.dummy_idx).set_value([1.0]) def DoCalcAbstractOutput(self, context, spatial_out): is_on = context.get_mutable_discrete_state(self.dummy_idx).value() # 打印is_on得到的是0.0,而非预期的1.0
我遇到的问题是:离散状态在Update方法中被设置为1.0,但在DoCalcAbstractOutput中读取到的值始终是初始的0.0,无任何报错,状态修改的结果完全没被输出计算感知到。
原因分析
这是Drake中事件执行顺序优先级导致的问题:
- 默认情况下,
DeclarePeriodicDiscreteUpdateEvent的优先级为0,输出端口的计算(DoCalcAbstractOutput)优先级也为0。 - 初始时刻(t=0),同优先级事件按声明顺序执行——你先声明了输出端口,再声明离散更新事件,因此输出计算先执行,此时离散状态还未被
Update修改,读取到的是初始值0.0。 - 后续时间步中,如果输出计算的触发时机未依赖离散状态更新,也可能出现读取旧值的情况。
另外,DoCalcAbstractOutput中使用get_mutable_discrete_state不符合规范,该方法用于修改状态,输出计算逻辑应仅读取状态,改用get_discrete_state更合理,但这不是值不更新的核心原因。
解决方案
方案1:提高离散更新事件的优先级
声明离散更新事件时,显式设置更高优先级(如priority=1),确保它在输出计算前执行:
self.DeclarePeriodicDiscreteUpdateEvent( period_sec=2e-3, offset_sec=0.0, update=self.Update, priority=1 # 设置更高优先级 )
方案2:让输出端口依赖离散状态
通过DeclareAbstractOutputPort的dependencies参数,明确指定输出依赖离散状态,让Drake自动处理执行顺序:
self.spatial_forces_output_port = self.DeclareAbstractOutputPort( "spatial_forces_output", lambda: forces_cls(), self.DoCalcAbstractOutput, dependencies=[self.dummy_idx] # 声明依赖离散状态 )
方案3:修正状态读取方式(规范代码)
在DoCalcAbstractOutput中改用只读方法读取离散状态:
def DoCalcAbstractOutput(self, context, spatial_out): is_on = context.get_discrete_state(self.dummy_idx).value()
内容的提问来源于stack exchange,提问作者HoliInn
相关产品推荐
相关产品推荐

