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
相关产品推荐
相关产品推荐

