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

PyDrake搭建移动IIWA机械臂时Simulator报错求助

问题:PyDrake移动IIWA机械臂仿真报错:Error control wants to select step smaller than minimum allowed

团队用PyDrake搭建带平面移动基座的IIWA机械臂,通过两个移动关节(Prismatic)和一个旋转关节(Revolute)手动定义基座。基础箱体测试正常,但添加IIWA后仿真报错:

Traceback (most recent call last):
  File "planar_joint.py", line 107, in <module>
    simulator.AdvanceTo(12.0)
RuntimeError: Error control wants to select step smaller than minimum allowed (1e-14)

已知可能和奇异位姿或物理引擎无穷值有关,但未强制机器人进入奇异位姿,求修复方案。相关代码与场景文件如下:

主代码

meshcat = StartMeshcat()

meshcat.Flush()
builder = DiagramBuilder()
plant, scene_graph = AddMultibodyPlantSceneGraph(builder, time_step=0.0005)

parser = Parser(plant)

scene_models = parser.AddModels("cargobot-models/scene_without_robot.dmd.yaml")

iiwa = plant.GetModelInstanceByName("iiwa")

false_body = plant.AddRigidBody(
        "false_body", iiwa,
        SpatialInertia(0, [0, 0, 0], UnitInertia(0, 0, 0)))
false_body2 = plant.AddRigidBody(
        "false_body2", iiwa,
        SpatialInertia(0, [0, 0, 0], UnitInertia(0, 0, 0)))

mobile_base_y = plant.AddJoint(PrismaticJoint(
        "mobile_base_y", plant.GetFrameByName("world"), plant.GetFrameByName("false_body"), 
        [0, 1, 0], -3, 3))
plant.AddJointActuator("mobile_base_y_actuator", mobile_base_y)

mobile_base_x = plant.AddJoint(PrismaticJoint(
        "mobile_base_x", plant.GetFrameByName("false_body"), plant.GetFrameByName("false_body2"), 
        [1, 0, 0], -3, 3))
plant.AddJointActuator("mobile_base_x_actuator", mobile_base_x)

mobile_base_theta = plant.AddJoint(RevoluteJoint(
        "mobile_base_theta", plant.GetFrameByName("false_body2"), plant.GetFrameByName("iiwa_link_0"), 
        [0, 0, 1],  -np.pi, np.pi))
plant.AddJointActuator("mobile_base_theta_actuator", mobile_base_theta)

plant.Finalize()

visualizer = MeshcatVisualizer.AddToBuilder(
    builder, scene_graph, meshcat)

plant_context = plant.CreateDefaultContext()

kp=[100] * plant.num_positions()
ki=[1] * plant.num_positions()
kd=[20] * plant.num_positions()

planar_controller = builder.AddSystem(
    InverseDynamicsController(plant, kp, ki, kd, False))
planar_controller.set_name("planar_controller")
builder.Connect(plant.get_state_output_port(),
                planar_controller.get_input_port_estimated_state())
builder.Connect(planar_controller.get_output_port_control(),
                plant.get_actuation_input_port())

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

states = [1, 0, 0, -1.57, 0.1, 0, -1.2, 0, 1.6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
planar_controller.GetInputPort('desired_state').FixValue(
    planar_controller.GetMyMutableContextFromRoot(context), states)

simulator = Simulator(diagram, context)
visualizer.StartRecording()
simulator.AdvanceTo(12.0)
visualizer.StopRecording()
visualizer.PublishRecording()

场景YAML文件

directives:          
    - add_model:
        name: cargo-space
        file: file:///usr/cargobot/cargobot-project/trajopt/cargobot-models/cargo-space.sdf

    - add_weld:
        parent: world
        child: cargo-space::cargo-space
        X_PC:
            rotation: !Rpy { deg: [0, 90, 0 ]}
            translation: [-1.5, 0, 0.4]

    - add_frame: 
        name: table_top_center
        X_PF:
            base_frame: world
            rotation: !Rpy { deg: [0, 0, 0]}
            translation: [0, 0, -0.5]

    - add_model:
        name: table_top
        file: file:///usr/cargobot/cargobot-project/trajopt/cargobot-models/table_top.sdf

    - add_weld: 
        parent: table_top_center
        child: table_top_link

    - add_model:
        name: iiwa
        file: package://drake/manipulation/models/iiwa_description/iiwa7/iiwa7_no_collision.sdf
        default_joint_positions:
            iiwa_joint_1: [-1.57]
            iiwa_joint_2: [0.1]
            iiwa_joint_3: [0]
            iiwa_joint_4: [-1.2]
            iiwa_joint_5: [0]
            iiwa_joint_6: [ 1.6]
            iiwa_joint_7: [0]

    - add_model:
        name: wsg
        file: package://drake/manipulation/models/wsg_50_description/sdf/schunk_wsg_50_with_tip.sdf
    - add_weld:
        parent: iiwa::iiwa_link_7
        child: wsg::body
        X_PC:
            translation: [0, 0, 0.09]
            rotation: !Rpy { deg: [90, 0, 90]}

目标:让机器人左移1单位。


修复方案

1. 替换零惯性刚体

代码中添加的false_body和false_body2是零惯性刚体,PyDrake处理这类刚体时极易出现数值奇异,导致仿真步长崩溃。将其改为带微小惯性的刚体:

# 替换原零惯性刚体定义
small_mass = 1e-3
false_body = plant.AddRigidBody(
        "false_body", iiwa,
        SpatialInertia(small_mass, [0, 0, 0], UnitInertia(1e-3, 1e-3, 1e-3)))
false_body2 = plant.AddRigidBody(
        "false_body2", iiwa,
        SpatialInertia(small_mass, [0, 0, 0], UnitInertia(1e-3, 1e-3, 1e-3)))

2. 修正状态数组维度

当前states数组有24个元素,但系统实际状态量应为:3个移动基座关节(位姿+速度)+7个IIWA关节(位姿+速度)=20个元素。冗余的状态输入会导致控制器逻辑混乱,引发动力学异常。修正后的状态数组:

# 格式:[x, y, theta, j1, j2, j3, j4, j5, j6, j7, vx, vy, vtheta, vj1, vj2, vj3, vj4, vj5, vj6, vj7]
states = [1, 0, 0, -1.57, 0.1, 0, -1.2, 0, 1.6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

3. 优化控制器增益与时间步长

  • 时间步长0.0005过小,搭配高增益控制器容易触发数值震荡,建议调整为0.001或0.002
  • 移动基座与机械臂关节惯性差异大,统一增益会导致基座控制不稳定,设置差异化增益:
    # 前3个是移动基座关节,后7个是IIWA关节
    kp = [20, 20, 20] + [100]*7
    ki = [0.1, 0.1, 0.1] + [1]*7
    kd = [5, 5, 5] + [20]*7
    

4. 规避腕部奇异位姿

IIWA初始关节角度j4=-1.2、j6=1.6接近腕部奇异点,即使未强制进入,也可能在控制过程中触发数值问题。微调初始角度,比如将j4改为-1.0,j6改为1.5,降低奇异风险。


内容的提问来源于stack exchange,提问作者Berke Uçar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 20:57:13