Meshcat接触可视化工具删除后无法重绘接触力问题咨询
问题背景
我有一个包含图(diagram)及其上下文(context)的TrajectoryVisualizer对象,用于可视化轨迹及轨迹上的接触力,代码如下:
class TrajectoryVisualizer: def __init__(self,): self.diagram = make_diagram_with_plant_and_scene_graph_and_visualizer_and_contact_visualizer() self.meshcat # Meshcat object self.contact_vis # ContactVisualizer object self.meshcat_vis # MeshcatVisualizer object self.plant # MultibodyPlant object self.context = self.diagram.CreateDefaultContext() self.context_meshcat = self.meshcat_vis.GetMyMutableContextFromRoot( self.context ) self.context_contact_vis = ( self.contact_vis.GetMyMutableContextFromRoot(self.context) ) self.context_plant = self.plant.GetMyMutableContextFromRoot(self.context) def publish_trajectory( self, h: float, q_knots: np.ndarray, contact_results_list: List[ContactResults], ): """ q_knots: (T + 1, n_q) array. contact_results_list: (T,) list. For 1 <= i <= T, contact_results_list[i - 1] is the contact forces at configuration q_knots[i]. """ assert len(q_knots) == len(contact_results_list) + 1 self.meshcat_vis.DeleteRecording() self.meshcat_vis.StartRecording(False) for i, t in enumerate(np.arange(len(q_knots)) * h): self.context.SetTime(t) self.plant.SetPositions(self.context_plant) self.meshcat_vis.ForcedPublish(self.context_meshcat) if i > 0: # Contact forces self.contact_vis.GetInputPort("contact_results").FixValue( self.context_contact_vis, AbstractValue.Make(contact_results_list[i - 1]), ) self.contact_vis.ForcedPublish(self.context_contact_vis) self.meshcat_vis.StopRecording() self.meshcat_vis.PublishRecording()
但发现删除接触力后,再次绘制相同轨迹时接触力不再显示:
vis = TrajectoryVisualizer() vis.publish_trajectory(h, q_knots, contact_results_list) # 首次绘制正常 vis.meshcat.Delete("contact_forces") vis.publish_trajectory(h, q_knots, contact_results_list) # 接触力不再显示
我有两个问题:
- 该故障是否由缓存导致?若是,如何修复?
- 可行方案是每次调用
vis.publish_trajectory(...)时创建新Context,但我认为Context构造成本较高,因此仅在构造函数中创建一次,该理解是否正确?
我认为创建新Context可解决问题,但希望找到最高效的可视化方式。
解答
问题1:故障原因与修复方案
这个故障不是由Context缓存导致,而是因为调用vis.meshcat.Delete("contact_forces")直接删除了Meshcat中承载接触力的节点结构,而ContactVisualizer默认不会自动重建已被删除的Meshcat节点。
修复方案有两种:
- 方案一:重新初始化ContactVisualizer节点
在每次发布轨迹前调用contact_vis.Reinitialize(),它会重新创建contact_forces节点及子结构。修改publish_trajectory方法:def publish_trajectory(...): # 新增初始化逻辑 self.contact_vis.Reinitialize() self.meshcat_vis.DeleteRecording() # 后续原有代码不变 - 方案二:隐藏而非删除节点
替代vis.meshcat.Delete("contact_forces"),使用vis.meshcat.SetProperty("contact_forces", "visible", False)隐藏接触力;需要显示时再设为True,这样节点结构不会被破坏,后续发布轨迹时能正常更新显示。
问题2:Context创建成本的理解与高效方案
你的理解是正确的:Diagram.CreateDefaultContext()的成本确实较高,因为它需要为整个图的所有组件(包括Plant、Visualizer等)分配并初始化上下文状态,频繁创建会带来不必要的性能开销,因此在构造函数中创建一次并复用是更高效的选择。
不需要每次发布轨迹都创建新Context,问题1的修复方案已经能在复用Context的前提下解决接触力不显示的问题。如果后续遇到其他Context状态污染问题,也可以通过重置Context到默认状态替代创建新Context,开销远低于新建操作:
# 在publish_trajectory开头添加重置逻辑 self.diagram.SetDefaultContext(self.context) # 重新获取子组件的上下文引用(可选,若之前的引用未失效) self.context_meshcat = self.meshcat_vis.GetMyMutableContextFromRoot(self.context) self.context_contact_vis = self.contact_vis.GetMyMutableContextFromRoot(self.context) self.context_plant = self.plant.GetMyMutableContextFromRoot(self.context)
内容的提问来源于stack exchange,提问作者Pang
相关产品推荐
相关产品推荐

