You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Drake添加足部地面转动关节时提示形成闭环机器人报错排查

LQR腿部平衡控制足部地面连接报错排查

通过销接关节约束足部到地面的实现思路触发Drake闭环报错,导入两个URDF后得到的机器人拓扑结构如下:
拓扑图

报错核心原因

  • Drake的Joint(底层对应Mobilizer)仅支持构建无环开式运动树:每个刚体(Body)有且仅有一个入端(inboard)mobilizer连接到运动树的上游节点,最终所有节点都追溯到唯一根节点——世界坐标系。
  • 你当前的场景里已经存在两条独立的开链:
    • 加载ground.urdf时,ground刚体默认通过固定关节锚定到世界坐标系,形成静态固定链路:世界 → (固定关节) ground
    • 加载腿部URDF时,由于没有手动指定腿部和世界的连接,Drake自动给顶层的base_link添加了6自由度浮动关节,形成第二条开链:世界 → (6DoF浮动关节) base_link → 各运动连杆 → Link_foot,这也是你误以为base_link未连接世界的认知偏差来源。
  • 你尝试添加的RevoluteJoint连接Link_foot和ground后,两条开链首尾闭合形成环:世界 → ground → foot → 各连杆 → base_link → 世界;且ground刚体本身已经存在一个入端固定关节,新增的关节相当于给它加了第二个入端mobilizer,直接触发闭环报错。拓扑图里的箭头方向就是mobilizer从父(上游)指向子(下游)的方向,和URDF定义的父/子连杆逻辑一致,本身不存在问题,你写的base_link为父连杆的prismatic关节定义也没有错误。

正确实现方案

结合LQR控制对模型线性化的需求,优先选择无约束的开链建模方式(避免微分代数方程影响线性化精度),如果不想调整现有URDF加载逻辑,也可以通过运动约束实现:

方案1:开链建模(推荐,适配LQR)

不需要单独导入地面URDF,直接将足部通过销接旋转关节连接到世界帧,把整个腿部构建为以足部铰接点为根的无环开链,从根源避免闭环问题。

builder = DiagramBuilder()
plant, scene_graph = AddMultibodyPlantSceneGraph(builder, time_step=0.0)
# 仅加载腿部模型,地面后续通过注册几何体实现
leg_instance = Parser(plant).AddModelFromFile("HoppingLeg/leg_v2/urdf/LEG_002_Foot_Hinge.urdf")

# 移除Drake自动给base_link添加的6自由度浮动关节
float_joint = plant.GetJointByName("base_link")
plant.RemoveJoint(float_joint)

# 将足部通过绕x轴的旋转关节直接连接到世界帧(地面固定点)
frame_foot = plant.GetFrameByName("Link_foot")
joint_ground = RevoluteJoint(
    name="foot_ground",
    frame_on_parent=plant.world_frame(),
    frame_on_child=frame_foot,
    axis=np.array([1., 0., 0.]),
    damping=0.0
)
plant.AddJoint(joint_ground)

# 注册地面碰撞与可视化几何体(替代单独的ground URDF)
plant.RegisterCollisionGeometry(
    plant.world_body(),
    RigidTransform(),
    HalfSpace(),
    "ground_collision",
    CoulombFriction(1.0, 1.0)
)

plant.Finalize()

方案2:闭环约束实现(保留原有URDF加载逻辑)

如果需要保留机器人、地面两个URDF分开导入的逻辑,不能使用Joint连接两个已接入运动树的刚体,改用RevoluteConstraint添加闭环运动限制,该约束会锁死足部和地面之间除绕x轴旋转外的所有相对自由度,实现销接效果。

builder = DiagramBuilder()
plant, scene_graph = AddMultibodyPlantSceneGraph(builder, time_step=0.0)
leg_instance = Parser(plant).AddModelFromFile("HoppingLeg/leg_v2/urdf/LEG_002_Foot_Hinge.urdf")
ground_instance = Parser(plant).AddModelFromFile("HoppingLeg/leg_v2/urdf/ground.urdf")

frame_foot = plant.GetFrameByName("Link_foot")
frame_ground = plant.GetFrameByName("ground")

# 添加旋转约束实现销接,而非新增Joint
plant.AddConstraint(
    RevoluteConstraint(
        frame_on_body1=frame_ground,
        axis_on_body1=np.array([1.,0.,0.]),
        frame_on_body2=frame_foot,
        axis_on_body2=np.array([1.,0.,0.]),
        threshold=1e-6
    )
)

plant.Finalize()

注意:方案2引入了闭环约束,系统模型为微分代数方程(DAE),做LQR线性化时需要确认线性化接口支持对应约束的线性化,控制场景下优先使用方案1的纯开链建模。


内容的提问来源于stack exchange,提问作者Noah Wechtler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 01:27:27