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

Drake弹跳球模拟异常:触地后无弹跳问题排查

问题:弹跳球模拟未出现弹跳行为

尝试在Drake中实现简单的弹跳球模拟,但球触地后并未弹跳,而是保持水平直线运动,垂直速度完全丢失。推测是未配置恢复系数相关行为,预期球会呈现弹跳运动,实际触地后轨迹变为水平直线。

相关实现代码
import numpy as np
import matplotlib.pyplot as plt

from pydrake.all import (
    MultibodyPlant, DiagramBuilder, RigidTransform,
    SpatialInertia, UnitInertia, CoulombFriction,
    AddMultibodyPlantSceneGraph, Simulator
)
from pydrake.geometry import Box, Sphere
from pydrake.multibody.math import SpatialVelocity

def create_bouncing_ball_sim():
    builder = DiagramBuilder()
    
    # Discrete plant with small time step
    plant, scene_graph = AddMultibodyPlantSceneGraph(builder, time_step=0.0001)

    # Ground
    ground_shape = Box(2.0, 2.0, 0.1)
    ground_pose = RigidTransform([0, 0, -0.05])
    plant.RegisterCollisionGeometry(
        plant.world_body(), ground_pose,
        ground_shape, "ground_collision",
        CoulombFriction(0.9, 0.8)
    )
    plant.RegisterVisualGeometry(
        plant.world_body(), ground_pose,
        ground_shape, "ground_visual",
        [0.5, 0.5, 0.5, 1.0]
    )

    # Ball
    radius = 0.05
    mass = 0.1
    inertia = UnitInertia.SolidSphere(radius)
    spatial_inertia = SpatialInertia(mass=mass, p_PScm_E=np.zeros(3), G_SP_E=inertia)

    ball_body = plant.AddRigidBody("ball", spatial_inertia)
    plant.RegisterCollisionGeometry(
        ball_body, RigidTransform(),
        Sphere(radius), "ball_collision",
        CoulombFriction(0.8, 0.6)
    )
    plant.RegisterVisualGeometry(
        ball_body, RigidTransform(),
        Sphere(radius), "ball_visual",
        [0.8, 0.1, 0.1, 1.0]
    )

    # Gravity
    plant.mutable_gravity_field().set_gravity_vector([0, 0, -9.81])
    plant.Finalize()

    diagram = builder.Build()
    context = diagram.CreateDefaultContext()

    plant_context = plant.GetMyMutableContextFromRoot(context)
    plant.SetFreeBodyPose(plant_context, ball_body, RigidTransform([0, 0, 1.0]))
    plant.SetFreeBodySpatialVelocity(ball_body, SpatialVelocity(np.zeros(3), np.zeros(3)), plant_context)

    simulator = Simulator(diagram, context)
    simulator.set_target_realtime_rate(1.0)

    return simulator, plant, ball_body

# Run simulation
simulator, plant, ball_body = create_bouncing_ball_sim()

# Simulate and collect data
time_steps = []
z_positions = []

sim_time = 2.0
dt = 0.001
simulator.Initialize()

while simulator.get_context().get_time() < sim_time:
    context = simulator.get_context()
    plant_context = plant.GetMyContextFromRoot(context)
    pose = plant.EvalBodyPoseInWorld(plant_context, ball_body)
    z = pose.translation()[2]
    t = context.get_time()

    z_positions.append(z)
    time_steps.append(t)

    simulator.AdvanceTo(t + dt)

# Plotting
plt.figure(figsize=(8, 4))
plt.plot(time_steps, z_positions, label="Ball height (z)")
plt.xlabel("Time [s]")
plt.ylabel("Height [m]")
plt.title("Bouncing Ball Simulation in Drake")
plt.grid(True)
plt.legend()
plt.show()
解决方案

Drake默认采用完全非弹性碰撞规则,触地后不会产生弹跳效果,必须显式设置恢复系数(restitution)才能实现预期的弹跳行为。

修改步骤

在注册地面和球体的碰撞几何时,为RegisterCollisionGeometry方法添加restitution参数,取值范围为0到1:

  • 0代表完全非弹性碰撞(无弹跳)
  • 1代表完全弹性碰撞(无能量损失)
  • 实际场景可设置0.8-0.9模拟真实弹跳

修改后的地面碰撞几何代码

plant.RegisterCollisionGeometry(
    plant.world_body(), ground_pose,
    ground_shape, "ground_collision",
    CoulombFriction(0.9, 0.8),
    restitution=0.9  # 添加恢复系数
)

修改后的球体碰撞几何代码

plant.RegisterCollisionGeometry(
    ball_body, RigidTransform(),
    Sphere(radius), "ball_collision",
    CoulombFriction(0.8, 0.6),
    restitution=0.9  # 添加恢复系数
)

修改后重新运行模拟,球体会呈现正常的弹跳运动,每次碰撞后高度因能量损失逐渐降低。

内容的提问来源于stack exchange,提问作者Kaushik S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 13:53:11