英文:
Custom meshcat contact visualizer not drawing contact forces correctly
问题
我有一个`TrajectoryVisualizer`对象,其中包括一个用于可视化轨迹和沿着轨迹的接触力的图表及其上下文。
然而,我意识到如果我删除了接触力,并尝试绘制相同的轨迹,接触力将不再显示:
```python
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
的构造可能会很昂贵,这就是为什么它只在TrajectoryVisualizer
的构造函数中构造一次的原因。我的理解正确吗?
我相信创建一个新的上下文会起作用,但我想找到最有效的可视化方式。```
英文:
I have a TrajectoryVisualizer
object that includes a diagram and its context, used for visualizing trajectories and the contact forces along the trajectories.
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()
However, I realized that if I delete the contact forces, and try to draw the the same trajectory, the contact forces do not show up anymore:
vis = TrajectoryVisualizer()
vis.publish_trajectory(h, q_knots, contact_results_list) # drawing for the first time, ok.
vis.meshcat.Delete("contact_forces")
vis.publish_trajectory(h, q_knots, contact_results_list) # contact forces do not show up anymore.
I have two questions:
- Is the failure due to caching? If so, how do I fix it?
- A possible solution is to create a new context every time I call
vis.publish_trajectory(...)
, but my impression has always been thatContext
can be expensive to construct, which is why it is constructed only once in the constructor ofTrajectoryVisualizer
. Is my understanding correct?
I believe creating a new context would work, but want to find out the most efficient way to visualize.
答案1
得分: 1
不要有别的内容。只返回翻译好的部分:
"Instead of calling general function meshcat.Delete("contact_forces")
to clear the contact visualization, call the purpose-built contact_visualizer.Delete()
instead. The ContactVisualizer
owns the entire /contact_forces/...
path tree in Meshcat. You are not supposed to be manually screwing with that tree outside of its control.
Specifically -- for speed, the ContactVisualizer
uses an internal cache of whether or not a contact pair / surface is being shown. If you manually change the Meshcat
paths that are owned by the ContactVisualizer
without telling it, the visualization will no longer work correctly.
As an alternative to contact_visualizer.Delete()
, another way to reset would be to ensure that the delete_on_initialization_event
option is enabled in the params (it is enabled by default), and then just re-initialize the self.context
each time instead of calling Delete()
. This would be more future-proof against any visualization systems that gain re-initialization logic down the road, and is the best way to ensure you're starting from a clean slate each time."
英文:
Instead of calling general function meshcat.Delete("contact_forces")
to clear the contact visualization, call the purpose-built contact_visualizer.Delete()
instead. The ContactVisualizer
owns the entire /contact_forces/...
path tree in Meshcat. You are not supposed to be manually screwing with that tree outside of its control.
Specifically -- for speed, the ContactVisualizer
uses an internal cache of whether or not a contact pair / surface is being shown. If you manually change the Meshcat
paths that are owned by the ContactVisualizer
without telling it, the visualization will no longer work correctly.
As an alternative to contact_visualizer.Delete()
, another way to reset would be to ensure that the delete_on_initialization_event
option is enabled in the params (it is enabled by default), and then just re-initialize the self.context
each time instead of calling Delete()
. This would be more future-proof against any visualization systems that gain re-initialization logic down the road, and is the best way to ensure you're starting from a clean slate each time.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论