The documentation is unusually honest about where it bites: hinge joints cannot be made through the runtime constraint interface, so a generator writes a URDF instead — and it warns that the generated file must land inside the server's working directory or loading it will be refused. Ray casting and rendered camera images make this usable for perception work, not just for dropping boxes.
A server over the PyBullet physics engine. Several independent simulations can be alive at once; you add shapes or load a robot from a URDF, step time forward, and query state, contacts and rendered images.
- Simulations created with the gravity you choose, listed, stepped forward and torn down, with a configurable timestep (create_simulation, list_simulations, step_simulation, set_timestep, destroy_simulation)
- Primitive shapes and URDF models placed in the world, repositioned, and queried for position, orientation and velocity (add_box, add_sphere, add_cylinder, add_capsule, load_urdf, set_object_pose, get_object_state)
- Forces, torques and velocities applied, and physics properties like mass, friction, restitution and damping changed at runtime and read back (apply_force, apply_torque, set_object_velocity, change_dynamics, get_dynamics_info)
- Robot control: how many joints a model has, each joint's limits and axis, its live position and velocity, motor control by position, velocity or torque, and inverse kinematics for an end effector (get_num_joints, get_joint_info, get_joint_state, set_joint_motor_control, calculate_inverse_kinematics)
- Ray casting, singly or in batches, for obstacle detection and lidar-style sensing (ray_test, ray_test_batch)
- Rendered colour, depth and segmentation images from a virtual camera you position yourself (compute_view_matrix, compute_view_matrix_from_yaw_pitch, compute_projection_matrix, get_camera_image)
- Joints between objects, and a generator that writes a URDF for a hinge joint the runtime constraint interface cannot create (create_constraint, remove_constraint, generate_revolute_joint)
- Contact points across the whole world or between one pair, with positions, normals and forces (get_all_collisions, get_collisions_for_pair)
- The world saved to a file and restored later, constraints included (save_simulation, load_simulation)
- Debug rendering of contacts and frames, and camera control, when the graphical mode is on (enable_debug_visualization, set_camera)
Python with PyBullet and FastMCP installed, in a virtual environment. It runs headless by default; the graphical mode needs a display, and only one graphical simulation can be alive at a time. Vectors must be given complete — gravity, positions, forces and orientations all take their full set of components — and mass must be positive, so a static ground plane is made heavy rather than massless.
