物理模拟服务器

一个用于AI助手与PyBullet物理模拟交互的模型上下文协议服务器,支持通过自然语言控制物理模拟项目。

  • by M1ndSmith
  • Python
  • 本地部署
  • 1 星标
  • 更新于
在 GitHub 查看 M1ndSmith/pybullet-mcp-server

使用说明

PyBullet MCP服务器

模型上下文协议(MCP)服务器,使AI助手能够与PyBullet物理模拟进行交互。通过与AI代理的自然语言交互构建基于物理的项目。

特性

  • 37 MCP工具:用于物理模拟控制(包括机器人关节控制)的全面API
  • 仿真管理:使用可配置的重力创建和管理多个独立的物理模拟
  • 对象操纵:添加具有完整属性控制的基本体形状(长方体、球体、圆柱体、胶囊)和URDF模型
  • 机器人控制:查询关节信息,控制电机(位置/速度/扭矩),并计算反向运动学
  • 物理控制:使用可配置的时间步长施加力、扭矩和逐步模拟
  • 状态持久性:在JSON文件中保存和加载完整的模拟状态
  • 约束条件:在对象之间创建关节(固定、棱柱、球形)
  • 碰撞检测:查询具有详细碰撞信息的联系点
  • 可视化:可选的GUI模式,带有调试可视化和摄像头控制
  • 错误处理:带有描述性错误消息的全面验证

重要说明

  • 坐标要求:所有矢量必须作为完整的3D坐标[x,y,z]提供
    • 重力: [0, 0, -9.81] (不是 [-9.81])
    • 位置: [x, y, z] (不是 [x, y] 或 [x])
    • 力/扭矩: [fx, fy, fz] (不是 [fx])
    • 方向: [x, y, z, w] 四元数(不是 [w])
  • 质量约束:对象质量必须为正(质量>0)。对静态对象使用大质量(例如1000)
  • GUI限制:一次只能激活一个GUI模拟(PyBullet限制)
  • URDF路径:使用绝对路径或相对于服务器工作目录的路径
  • 转动关节: create_constraint 不支持 "revolute" --使用 generate_revolute_joint + load_urdf 相反。始终传递一个明确的 output_path 在工作空间内 generate_revolute_joint否则,生成的URDF将着陆 /tmp/ 和 load_urdf 将拒绝它。

安装

先决条件

  • Python 3.9或更高版本
  • pip包管理器
  • 虚拟环境(推荐)

安装依赖项

  1. 创建并激活虚拟环境:
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
  1. 安装FastMCP和PyBullet:
pip install fastmcp pybullet
  1. 对于开发(包括测试工具):
pip install fastmcp pybullet pytest hypothesis pytest-cov

验证安装

检查是否安装了所需的软件包:

python -c "import pybullet; import mcp; print('Installation successful!')"

快速开始

运行服务器

看 QUICKSTART.md 有关以下内容的详细说明:

  • 启动服务器
  • 配置Claude桌面
  • 探索所有功能的示例提示
  • 常见工作流程和用例

快速命令:

source venv/bin/activate  # On Windows: venv\Scripts\activate
python -m src.server

服务器将启动并监听来自AI助手的MCP协议连接。

MCP客户端使用示例

一旦连接到MCP客户端(如Claude Desktop),您就可以通过自然语言进行交互:

1.创建模拟:

Create a new physics simulation with Earth gravity

这叫 create_simulation 有重力 [0, 0, -9.81].

重要:重力必须是三维矢量。服务器接受以下简写 [-9.81] 并将其扩展为 [0, 0, -9.81].

2.添加对象:

Add a red box at position (0, 0, 1) with dimensions 0.5x0.5x0.5 and mass 1.0

这叫 add_box 创建一个长方体对象。位置会自动扩展为 [0, 0, 1].

Add a sphere at (2, 0, 1) with radius 0.3

这叫 add_sphere 创建一个球体。

备注:质量必须为正。对于静态对象(如地平面),使用较大的质量值(例如1000)。

3.运行模拟:

Step the simulation forward 100 times

这叫 step_simulation 步数=100。

4.查询对象状态:

What is the position and velocity of object 0?

这叫 get_object_state 检索位置、方向和速度。

5.施加力:

Apply a force of [10, 0, 0] to object 0

这叫 apply_force 推动物体。

6.保存模拟:

Save the current simulation state to simulation.json

这叫 save_simulation 坚持国家。

7.加载模拟:

Load the simulation from simulation.json

这叫 load_simulation 以恢复保存的状态。

MCP配置

要将此服务器与Cursor或任何其他MCP兼容客户端一起使用,请将以下内容添加到MCP配置文件中:

{
  "mcpServers": {
    "pybullet": {
      "url": "http://localhost:8000/mcp",
      "disabled": false
    }
  }
}

默认情况下,服务器运行HTTP传输。您可以通过在中编辑入口点来更改传输方法 server.py:

if __name__ == "__main__":
    mcp.run(transport="http", port=8000)

更新配置后重新启动MCP客户端。

可用工具

服务器通过MCP协议公开了37个工具:

仿真管理(5个工具)

  • create_simulation:使用可配置的重力和可选的GUI初始化新的物理模拟

    • 参数: gravity (列表[float],默认值:[0,0,-9.81]), gui (bool,默认值:false)
    • 返回:simulation_id、重力、gui_enabled
  • list_simulations:获取所有活动的模拟ID

    • 返回:模拟ID列表
  • destroy_simulation:清理并删除模拟

    • 参数: sim_id (str)
    • 返回:确认消息
  • step_simulation:通过一个或多个时间步推进模拟

    • 参数: sim_id (str), steps (int,默认值:1)
    • 返回:simulation_id、steps_taked、current_time
  • set_timestep:配置模拟的时间步长持续时间

    • 参数: sim_id (str), timestep (浮动)
    • 返回:确认消息

对象操作(9个工具)

  • add_box:将长方体形状添加到模拟中

    • 参数: sim_id, dimensions (列表[浮动]), position (列表[浮动]), mass (浮点数,默认值:1.0), color (列表[float],可选)
    • 返回:object_id、shape、position
  • add_sphere:将球体形状添加到模拟中

    • 参数: sim_id, radius (浮动), position (列表[浮动]), mass (浮点数,默认值:1.0), color (列表[float],可选)
    • 返回:object_id、shape、position
  • add_cylinder:将圆柱体形状添加到模拟中

    • 参数: sim_id, radius (浮动), height (浮动), position (列表[浮动]), mass (浮点数,默认值:1.0), color (列表[float],可选)
    • 返回:object_id、shape、position
  • add_capsule:将胶囊形状添加到模拟中

    • 参数: sim_id, radius (浮动), height (浮动), position (列表[浮动]), mass (浮点数,默认值:1.0), color (列表[float],可选)
    • 返回:object_id、shape、position
  • load_urdf:从URDF文件加载机器人模型

    • 参数: sim_id, file_path (str), position (列表[浮动]), orientation (列表[float],可选)
    • 返回:object_id、file_path、position
  • set_object_pose:更新对象位置和方向

    • 参数: sim_id, object_id (int), position (列表[浮动]), orientation (列表[浮动])
    • 返回:确认消息
  • get_object_state:查询完整对象状态

    • 参数: sim_id, object_id (int)
    • 返回:位置、方向、线速度、角速度
  • apply_force:将力矢量应用于对象

    • 参数: sim_id, object_id (int), force (列表[浮动]), position (列表[float],可选)
    • 返回:确认消息
  • apply_torque:对物体施加旋转力

    • 参数: sim_id, object_id (int), torque (列表[浮动])
    • 返回:确认消息
  • set_object_velocity:直接设置对象的线速度和/或角速度

    • 参数: sim_id, object_id (int), linear_velocity (列表[float],可选), angular_velocity (列表[float],可选)
    • 返回:确认消息
  • change_dynamics:在运行时修改对象物理属性

    • 参数: sim_id, object_id (int), link_index (int,默认值:-1), mass (浮动,可选), lateral_friction (浮动,可选), spinning_friction (浮动,可选), rolling_friction (浮动,可选), restitution (浮动,可选), linear_damping (浮动,可选), angular_damping (浮动,可选), contact_stiffness (浮动,可选), contact_damping (浮动,可选)
    • 返回:确认消息
  • get_dynamics_info:查询对象的当前动态属性

    • 参数: sim_id, object_id (int), link_index (int,默认值:-1)
    • 返回:质量、侧向摩擦力、局部惯性对角线、恢复力、滚动摩擦力、旋转摩擦力、接触阻尼、接触刚度、身体类型、碰撞刚度

光线投射(2个工具)

  • ray_test:投射一条光线来探测障碍物并测量距离

    • 参数: sim_id, ray_from (列表[浮动]), ray_to (列表[浮动])
    • 返回:hit(bool)、object_id、link_index、hit_fract、hit_position、hit_normal
  • ray_test_batch:为激光雷达/传感器模拟高效地投射多条光线

    • 参数: sim_id, rays_from (列表[list[float]]), rays_to (列表[list[float]])
    • 返回:命中结果列表(与每条射线的ray_test字段相同)

摄影机渲染(4个工具)

  • compute_view_matrix:根据摄像机眼睛/目标/向上矢量计算视图矩阵

    • 参数: camera_eye_position (列表[浮动]), camera_target_position (列表[浮动]), camera_up_vector (列表[浮动])
    • 返回:将矩阵视为16个浮点数的列表
  • compute_view_matrix_from_yaw_pitch:根据球坐标计算视图矩阵(轨道相机)

    • 参数: distance (浮动), yaw (浮动), pitch (浮动), target_position (列表[浮动]), up_axis_index (int,默认值:2)
    • 返回:将矩阵视为16个浮点数的列表
  • compute_projection_matrix:根据相机参数计算投影矩阵

    • 参数: fov (浮动), aspect (浮动), near_plane (浮动), far_plane (浮动)
    • 返回:投影矩阵为16个浮点数的列表
  • get_camera_image:渲染来自虚拟相机的RGB、深度和分割图像

    • 参数: sim_id, width (int), height (int), view_matrix (列表[浮动]), projection_matrix (列表[浮动]), renderer (str,默认值:“ER_BULLET_HARDWARE_OPENGL”)
    • 返回:宽度、高度、rgb(base64 PNG)、深度(list[float])、分段(list[int])

约束管理(2个工具)

  • create_constraint:在两个对象之间创建关节

    • 参数: sim_id, parent_id (int), child_id (int), joint_type (str), joint_axis (列表[float],可选), parent_frame_position (列表[float],可选), child_frame_position (列表[float],可选)
    • 接头类型:“固定”、“棱柱”、“球形”
    • 返回:constraint_id、joint_type
    • 注: "revolute" 此处不支持--请使用 generate_revolute_joint + load_urdf 相反。
  • remove_constraint:从模拟中删除约束

    • 参数: sim_id, constraint_id (int)
    • 返回:确认消息

旋转(铰链)接头——解决方法

PyBullet的运行时约束API不支持旋转关节。解决方法是使用这两个工具分两步进行:

步骤1——使用旋转关节生成URDF:

  • generate_revolute_joint:生成包含由旋转关节连接的两个形状的URDF文件
    • 参数: parent_shape (str:“盒子”/“球体”/“圆柱体”), child_shape (str), parent_dimensions (列表[浮动]), child_dimensions (列表[浮动]), parent_mass (浮动), child_mass (浮动), joint_axis (列表[浮动]), joint_origin (列表[float],可选), joint_lower_limit (浮点数,默认值:-π), joint_upper_limit (浮点数,默认值:π), max_effort (浮动), max_velocity (浮动), output_path (str)
    • 返回:urdf_path、parent_shape、child_shape,joint_type、joint_axis、joint_limits
    • output_path 必须设置为服务器工作目录内的路径。 如果省略,则将文件写入系统临时目录(/tmp/)这超出了允许的路径,将导致 load_urdf 由于访问被拒绝错误而失败。

步骤2——加载生成的URDF:

  • 呼叫 load_urdf 随着 urdf_path 从...返回 generate_revolute_joint
  • 然后使用 set_joint_motor_control 驱动关节

碰撞检测(2个工具)

  • get_all_collisions:查询模拟中的所有接触点

    • 参数: sim_id
    • 返回:具有位置、法线、力的接触点列表
  • get_collisions_for_pair:查询特定对象之间的联系点

    • 参数: sim_id, obj_a (int), obj_b (int)
    • 返回:该对的接触点列表

可视化(2个工具)

  • enable_debug_visualization:启用触点和框架的调试渲染

    • 参数: sim_id, show_contacts (bool,默认值:true), show_frames (bool,默认值:false)
    • 返回:确认消息
  • set_camera:为GUI模式配置相机位置和目标

    • 参数: sim_id, distance (浮动), yaw (浮动), pitch (浮动), target (列表[浮动])
    • 返回:确认消息

持久性(2个工具)

  • save_simulation:将模拟状态保存到JSON文件

    • 参数: sim_id, file_path (str)
    • 返回:确认文件路径
  • load_simulation:从JSON文件加载模拟状态

    • 参数: file_path (str), gui (bool,默认值:false)
    • 返回:new simulation_id,file_path

机器人控制(5个工具)

  • get_num_joints:查询URDF模型中的关节数

    • 参数: sim_id (str), object_id (int)
    • 返回值:关节数(int)
  • get_joint_info:获取详细的关节属性

    • 参数: sim_id (str), object_id (int), joint_index (int)
    • 返回:joint_name、joint_type、lower_limit、upper_limit
  • get_joint_state:获取当前关节状态

    • 参数: sim_id (str), object_id (int), joint_index (int)
    • 返回值:joint_position、joint_speed、反作用力、电机扭矩
  • set_joint_motor_control:控制机器人关节

    • 参数: sim_id (str), object_id (int), joint_index (int), control_mode (str), target_position (浮动,可选), target_velocity (浮动,可选), force (浮动,可选), position_gain (浮动,可选), velocity_gain (浮动,可选)
    • 控制模式:“位置控制”、“速度控制”和“扭矩控制”
    • 返回:确认消息
  • calculate_inverse_kinematics:计算目标末端执行器姿势的关节角度

    • 参数: sim_id (str), object_id (int), end_effector_link_index (int), target_position (列表[浮动]), target_orientation (列表[float],可选), lower_limits (列表[float],可选), upper_limits (列表[float],可选), joint_ranges (列表[float],可选), rest_poses (列表[float],可选)
    • 返回:关节位置列表

示例工作流

基本落箱

创建一个简单的模拟,其中一个盒子在重力作用下下落:

# Through MCP client (natural language):
"Create a simulation with Earth gravity"
"Add a box at position (0, 0, 5) with dimensions 1x1x1"
"Step the simulation 200 times"
"What is the position of object 0?"

堆叠物体

创建一堆对象:

"Create a simulation"
"Add a box at (0, 0, 0.5) with dimensions 10x10x1 and mass 1000"  # Ground
"Add a box at (0, 0, 1.5) with dimensions 1x1x1"
"Add a sphere at (0, 0, 3) with radius 0.5"
"Step the simulation 300 times"
"Get all collisions"

受约束对象

创建由关节连接的对象:

"Create a simulation"
"Add a box at (0, 0, 2) with dimensions 1x1x1"  # Object 0
"Add a sphere at (2, 0, 2) with radius 0.5"     # Object 1
"Create a fixed constraint between object 0 and object 1"
"Apply a torque of [0, 0, 10] to object 1"
"Step the simulation 200 times"

保存和加载

坚持模拟:

"Create a simulation"
"Add a box at (0, 0, 1)"
"Add a sphere at (1, 0, 1)"
"Step the simulation 50 times"
"Save the simulation to my_sim.json"

# Later...
"Load the simulation from my_sim.json"
"Step the simulation 50 more times"

机器人仿真

加载并控制URDF机器人模型:

"Create a simulation with GUI enabled"
"Load URDF from /path/to/robot.urdf at position (0, 0, 1)"
"How many joints does object 0 have?"
"Get information about joint 0 of object 0"
"Get the current state of joint 0"
"Set joint 0 to position 1.57 with position control and force 100"
"Step the simulation 100 times"
"Get the state of joint 0 again to see it moved"
"Calculate inverse kinematics for object 0 end-effector link 6 at position [0.5, 0, 0.5]"

机器人控制功能:

  • 查询关节数量和关节属性(类型、限制、轴)
  • 读取关节状态(位置、速度、力、扭矩)
  • 控制接头有三种模式:
    • 位置控制:将关节移动到目标角度/位置
    • 速度控制:以目标速度旋转关节
    • 扭矩控制:对接头施加直接扭矩
  • 计算末端执行器定位的反向运动学

持久性文件格式

模拟状态保存为具有以下结构的JSON文件:

{
  "gravity": [0.0, 0.0, -9.81],
  "timestep": 0.01,
  "objects": [
    {
      "object_id": 0,
      "type": "primitive",
      "shape": "box",
      "dimensions": [0.5, 0.5, 0.5],
      "position": [0.0, 0.0, 1.0],
      "orientation": [0.0, 0.0, 0.0, 1.0],
      "linear_velocity": [0.0, 0.0, -0.98],
      "angular_velocity": [0.0, 0.0, 0.0],
      "mass": 1.0,
      "color": [1.0, 0.0, 0.0, 1.0]
    },
    {
      "object_id": 1,
      "type": "urdf",
      "urdf_path": "/path/to/model.urdf",
      "position": [2.0, 0.0, 0.5],
      "orientation": [0.0, 0.0, 0.0, 1.0],
      "linear_velocity": [0.0, 0.0, 0.0],
      "angular_velocity": [0.0, 0.0, 0.0]
    }
  ],
  "constraints": [
    {
      "constraint_id": 0,
      "parent_id": 0,
      "child_id": 1,
      "joint_type": "fixed"
    }
  ]
}

兼容性说明

  • 对象标识:加载时重新分配对象ID(可能与保存的ID不同)
  • URDF文件:加载时URDF文件路径必须有效。使用绝对路径保证可靠性
  • 模拟ID:加载时生成新的模拟ID
  • 格式版本:当前格式与PyBullet 3.2.5兼容+
  • 约束条件:约束已完全序列化并恢复

常见问题及解决方法

坐标误差

问题: "force needs a 3 coordinates [x,y,z]" 或类似错误

解决方案:始终提供完整的3D矢量:

# Wrong
gravity = [-9.81]
position = [1, 2]
force = [10]

# Correct
gravity = [0, 0, -9.81]
position = [1, 2, 0]
force = [10, 0, 0]

批量验证错误

问题: "Mass must be positive, got 0.0"

解决方案:PyBullet需要正质量。对于静态对象,请使用大质量:

# Wrong
add_box(mass=0)  # Error!

# Correct
add_box(mass=1000)  # Heavy static object

GUI窗口未出现

问题:GUI窗口在以下情况下不显示 gui=true

解决方案:

  • 每个服务器实例只允许一个GUI模拟
  • 在创建新的GUI模拟之前,先销毁现有的GUI模拟
  • 某些环境(Docker、没有X11的SSH)不支持GUI
  • 在Linux上,确保X11可用: echo $DISPLAY

URDF加载失败

问题: "Failed to load URDF: File not found"

解决方案:

  • 使用绝对路径: /full/path/to/robot.urdf
  • 或者使用相对于服务器工作目录的路径
  • 验证文件是否存在: ls -la /path/to/robot.urdf
  • 检查URDF中引用的网格文件是否也可访问

物体从地面坠落

问题:物体穿过地平面

解决方案:

  • 确保您正在逐步进行模拟: step_simulation(steps=100)
  • 使用适当的时间步长(默认0.01通常很好)
  • 为接地平面提供大尺寸和高质量(例如1000)
  • 验证对象是否具有正质量

故障排除

常见问题

1.启动服务器时导入错误

ModuleNotFoundError: No module named 'mcp' or 'pybullet'

解决方案:确保您的虚拟环境已激活并安装了依赖项:

source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install fastmcp pybullet

2.Python版本错误

SyntaxError or version compatibility issues

解决方案:检查Python版本(必须是3.9+):

python --version

如果需要,使用特定的Python版本创建一个venv:

python3.9 -m venv venv

3.PyBullet GUI未显示

GUI window doesn't appear when gui=true

解决方案:

  • 必须明确启用GUI模式: create_simulation(gui=true)
  • 某些系统(服务器、Docker)不支持GUI模式,请改用无头模式
  • 在Linux上,确保X11可用: echo $DISPLAY

4.文件权限错误

PermissionError when saving/loading simulations

解决方案:

  • 确保目标目录中的写入权限
  • 使用绝对路径: /full/path/to/simulation.json
  • 检查磁盘空间: df -h

5.MCP客户端无法连接到服务器

Server not responding

解决方案:

  • 验证服务器是否正在运行: python -m src.server
  • 检查MCP配置中的URL是否与服务器端口匹配(默认值: http://localhost:8000/mcp)
  • 配置更改后重新启动MCP客户端
  • 检查服务器终端输出是否有错误消息

6.模拟行为异常

Objects fall through the ground or constraints don't work

解决方案:

  • 确保您正在逐步进行模拟: step_simulation(sim_id, steps=100)
  • 检查时间步长值(默认值0.01通常很好)
  • 验证物体质量是否为正
  • 对于接地平面,使用尺寸较大、质量=1000的长方体

7.URDF加载失败

ToolError: Failed to load URDF

解决方案:

  • 验证URDF文件路径是否正确且可访问
  • 对URDF文件使用绝对路径
  • 检查URDF中引用的网格文件是否也可访问
  • 直接使用PyBullet验证URDF语法

调试模式

要查看详细的错误消息,请检查终端中的服务器输出。服务器记录所有操作和错误。

获取帮助

如果您遇到此处未涵盖的问题:

  1. 检查服务器日志以获取详细的错误消息
  2. 验证您的MCP客户端配置
  3. 直接用Python测试服务器,以隔离MCP和PyBullet问题
  4. 查阅PyBullet文档,了解物理方面的具体问题

建筑

服务器遵循分层架构:

MCP Client (Claude Desktop)
         ↓
   MCP Protocol
         ↓
FastMCP Server (37 tools)
         ↓
Manager Classes (helpers)
         ↓
PyBullet Physics Engine

关键部件:

  • FastMCP服务器 (src/server.py):使用以下工具暴露37个MCP工具 @mcp.tool 装饰器
  • 模拟管理器:管理PyBullet物理客户端和仿真生命周期
  • 对象管理器:处理对象创建、操作和状态查询
  • 约束管理器:创建和管理对象之间的关节
  • 持久化处理程序:将模拟状态序列化/反序列化为JSON
  • 冲突查询处理程序:查询联系点和碰撞信息

每个MCP工具都会验证输入,调用相应的管理器,并直接返回Python对象(dict/list/str/int)——FastMCP会自动处理MCP协议转换。

贡献

欢迎投稿!请确保:

  • 所有测试均通过: pytest
  • 代码的格式为: black src tests
  • 代码传递linting: ruff check src tests
  • 类型提示正确: mypy src
  • 新功能包括测试(基于单元+属性)
  • 文档已更新

致谢

支持

对于问题、疑问或贡献:

  • 查看此README和故障排除部分
  • 查看PyBullet文档以了解物理特定问题