Drake中AutoDiffXd Plant无法获取接触信息及梯度相关问询
问题1:Double与AutoDiffXd类型MultibodyPlant获取接触信息的差异
核心原因是AutoDiffXd版本中SceneGraph与MultibodyPlant的上下文未同步。接触检测由SceneGraph负责,MultibodyPlant的contact_results_output_port依赖SceneGraph输出的GeometryQuery数据。你的Double版本能正常工作,是因为对应的Diagram中两者已正确连接且上下文状态同步;但AutoDiffXd版本仅转换了MultibodyPlant,未确保SceneGraph的内部状态(如碰撞检测缓存)被更新,即便位置数值一致,仍会返回0个接触。
解决步骤:
- 确保AutoDiffXd版本的Diagram中,MultibodyPlant与SceneGraph端口正确连接(参考问题2的修正方案)。
- 调用接触结果端口前,先同步SceneGraph上下文状态:
# 获取SceneGraph的上下文 diagram_AD = builder_AD.Build() root_context_AD = diagram_AD.CreateDefaultContext() scene_graph_context = connected_sceneGraphAD.GetMyContextFromRoot(root_context_AD) # 将MultibodyPlant的几何查询数据传入SceneGraph connected_plantAD.get_geometry_query_input_port().FixValue(scene_graph_context, AD_query_object) # 重新计算接触结果 contact_results_AD = contact_info_port_AD.Eval(mutable_plant_contextAD_list[0])
问题2:AutoDiffXd版本代码的端口连接错误
你的转换逻辑存在关键问题:直接对已Finalize的Double类型Plant调用ToScalarType,再通过AddMultibodyPlantSceneGraph添加到新Diagram,会破坏原有的SceneGraph关联。AddMultibodyPlantSceneGraph用于从头构建包含Plant和SceneGraph的系统,不适合转换已有的Plant实例。
正确的转换方式是将完整的Double类型Diagram转换为AutoDiffXd类型,保留所有系统的连接关系:
# 先完成Double版本的Diagram构建 builder = DiagramBuilder() plant, scene_graph = AddMultibodyPlantSceneGraph(builder, time_step=h) # 解析模型、焊接帧等操作 parser = Parser(plant) table_model_index = parser.AddModels(tablefile)[0] box_model_index = parser.AddModels(boxfile)[0] hand_model_index = parser.AddModels(handfile)[0] table_top_frame = plant.GetFrameByName("table_top_center") plant.WeldFrames(plant.world_frame(), table_top_frame, X_W_table) plant.Finalize() # 构建完整Diagram diagram = builder.Build() # 转换为AutoDiffXd版本 diagram_AD = diagram.ToScalarType[AutoDiffXd]() plant_AD = diagram_AD.GetSubsystemByName(plant.get_name()) scene_graph_AD = diagram_AD.GetSubsystemByName(scene_graph.get_name())
问题3:约束函数中梯度的处理与稀疏结构
在Drake中:
- 梯度自动处理:使用AutoDiffXd类型的MultibodyPlant和上下文时,所有通过
Eval调用的计算都会自动携带梯度信息,无需手动实现梯度逻辑。Drake的AutoDiff机制会自动追踪变量依赖关系,计算函数对输入变量的导数。 - 稀疏梯度支持:AutoDiffXd原生支持稀疏梯度存储,求解器(如SNOPT、IPOPT)会自动识别并利用梯度的稀疏性。若需显式获取稀疏梯度,可使用
ExtractGradient函数:from drake.autodiffutils import ExtractGradient # 假设constraint_value为AutoDiffXd类型的约束结果 sparse_gradient = ExtractGradient(constraint_value, sparse=True)
实践参考:
- Drake的
InverseKinematics模块默认使用AutoDiff计算梯度,可参考其官方示例(如熊猫机器人逆运动学案例)。 - 自定义约束函数时,只需将输入变量转为AutoDiffXd类型,调用Plant的方法(如计算位置、接触力),返回的结果即可直接传递给求解器,梯度会被自动处理。
内容的提问来源于stack exchange,提问作者Xiao
相关产品推荐
相关产品推荐

