使用说明
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包管理器
- 虚拟环境(推荐)
安装依赖项
- 创建并激活虚拟环境:
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
- 安装FastMCP和PyBullet:
pip install fastmcp pybullet
- 对于开发(包括测试工具):
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语法
调试模式
要查看详细的错误消息,请检查终端中的服务器输出。服务器记录所有操作和错误。
获取帮助
如果您遇到此处未涵盖的问题:
- 检查服务器日志以获取详细的错误消息
- 验证您的MCP客户端配置
- 直接用Python测试服务器,以隔离MCP和PyBullet问题
- 查阅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文档以了解物理特定问题
