PyBullet is an open-source Python module for robot simulation built on the Bullet Physics SDK, a C++ engine for rigid-body and soft-body dynamics, collision detection and contact resolution. In robotics simulation, it lets engineers and researchers load robot models, step a physics world, read sensors and send motor commands from a few lines of Python, without a heavy graphical environment.
The module became popular in reinforcement learning and robot learning research because it is free, installs as a single package, runs headless on servers and executes many simulation steps per second. It sits between lightweight research tools and full robotics platforms: it is more physically complete than a toy environment, yet far simpler than a simulator with an integrated middleware stack and photorealistic rendering.
How PyBullet runs a physics world
PyBullet works as a client-server architecture: the Python script is a client that sends commands to a physics server holding the world state. The server can run in the same process (DIRECT mode, no window), with an OpenGL viewer (GUI mode), or in a separate process reached over shared memory, UDP or TCP. Every function call, such as loading a model or applying a torque, is a message to that server.
Each call to stepSimulation advances the world by a fixed time step, by default 1/240 of a second. In one step the engine detects collisions, builds contact constraints, solves them together with joint constraints and motor targets, and integrates velocities and positions. The solver is an iterative sequential impulse method, so accuracy depends on the number of solver iterations and the step size rather than on an exact analytical solution.
The following table lists the connection modes and when each one is appropriate.
| Mode | What it does | Typical use |
|---|---|---|
| DIRECT | Runs physics in-process without a window | Training runs, batch tests, cloud servers |
| GUI | Opens an OpenGL viewer with debug controls | Debugging, demonstrations, tuning |
| SHARED_MEMORY | Connects to a separate physics server process | Virtual reality, external visualizers |
| UDP or TCP | Connects to a server over the network | Remote or distributed experiments |
Robot models, sensors and control in PyBullet
Robots enter the world through robot description files. PyBullet loads URDF files most often, and it also reads SDF and MJCF files, the latter being the MuJoCo format. A loaded model becomes a multibody with links and joints, and every joint can be queried for position, velocity and reaction forces, or driven by a motor command.
Control is set per joint through setJointMotorControl2 with three main modes. Position control drives a joint toward a target angle using a proportional-derivative law with configurable gains, velocity control holds a target speed, and torque control applies a raw force after the default velocity motors are disabled. Choosing the wrong mode is a common source of robots that jitter, sag or refuse to move.
The next table summarizes the main capabilities a robotics user typically relies on.
| Capability | Main functions | Purpose |
|---|---|---|
| Model loading | loadURDF, loadSDF, loadMJCF | Build the robot and its environment |
| Joint control | setJointMotorControl2 | Drive joints by position, velocity or torque |
| State queries | getJointState, getLinkState | Read joint angles, link poses and forces |
| Kinematics | calculateInverseKinematics | Compute joint angles for a target pose |
| Dynamics | calculateInverseDynamics, calculateJacobian | Model-based control and analysis |
| Sensing | getCameraImage, rayTestBatch | Synthetic RGB, depth, segmentation and lidar-like rays |
The built-in camera renderer returns RGB, depth and segmentation images, either through a software renderer on headless machines or through OpenGL when a display is available. Batched ray casts imitate lidar or proximity sensors, and contact points report normal forces, which can approximate tactile sensing.
PyBullet compared with other robot simulators
PyBullet is best understood as a physics library with a Python interface, not as a full robotics platform. Neighboring tools in robotics simulation differ in physics accuracy, rendering quality, middleware integration and hardware requirements, so the choice depends on the task.
| Simulator | Strength | Typical limitation |
|---|---|---|
| PyBullet | Free, lightweight, quick to script in Python | Basic rendering, no longer actively extended |
| MuJoCo | Accurate, fast contact dynamics for control research | Less suited to large sensor-rich scenes |
| Gazebo | Deep ROS integration and sensor plugins | Heavier setup and slower iteration |
| Isaac Sim | Photorealistic rendering and GPU physics | Requires a capable NVIDIA GPU |
| Webots | Complete robot library and editor | Less common in learning research |
A practical rule follows from this comparison. PyBullet suits fast prototyping and moderate-scale learning experiments on ordinary hardware, while MuJoCo is often preferred for precise contact control, and GPU-based simulators win for massive parallel training with thousands of environments.
Typical uses in research and engineering
The most widespread use is training control policies with reinforcement learning. Many open-source environment collections for legged locomotion, manipulation and drones are built on PyBullet, and their Gym-style interfaces let researchers swap algorithms without rewriting the simulation.
Engineers also use it for motion planning checks, collision testing of grasp poses, inverse kinematics experiments and teaching. Because the engine supports domain randomization easily, by changing masses, friction coefficients, latencies or visual textures at each episode, it is a common tool for sim-to-real transfer studies.
- Locomotion research: quadrupeds and humanoids learning to walk on varied terrain.
- Manipulation: grasping, pushing and pick-and-place with robot arms.
- Education: university courses on kinematics, dynamics and control.
- Regression testing: automated checks that a controller still works after code changes.
Limitations and common mistakes
PyBullet inherits the approximations of an iterative rigid-body solver: contacts can be slightly soft, stacked objects may drift, and stiff mechanisms can become unstable at large time steps. Its rendering is functional rather than photorealistic, which limits training of vision models that must later work on real camera images.
Most problems that users report come from setup rather than from the engine itself. The table below lists frequent symptoms with their usual causes and remedies.
| Symptom | Likely cause | Remedy |
|---|---|---|
| Robot falls through the floor | Missing or wrong collision geometry | Check collision shapes in the URDF |
| Joints ignore torque commands | Default velocity motors still active | Disable motors with zero force first |
| Simulation explodes or jitters | Time step too large or stiff gains | Use smaller steps or lower gains |
| Policy fails on the real robot | Unmodeled latency, friction or noise | Add domain randomization and delays |
| Results differ between runs | Uncontrolled random seeds or timing | Fix seeds and use DIRECT mode |
A further consideration is maintenance status. Development of new features has slowed considerably, and many groups have moved toward newer engines. PyBullet remains usable and widely cited, but a long-term project should weigh this against simulators with more active development.
A non-technical view
PyBullet is a virtual playground for robots that runs inside a computer. Instead of building a real robot arm and risking damage every time a program has a bug, a developer places a digital copy of the arm in a simulated room where gravity, collisions and friction behave roughly like in reality.
The developer writes short instructions in Python, such as move this joint or pick up that cube, and watches what happens. Mistakes cost nothing, experiments can run faster than real time, and thousands of attempts can be repeated overnight. The catch is that the virtual world is a simplification, so results must still be confirmed on real hardware.
A concrete example
A university lab wants a small quadruped robot to walk on uneven ground. Training the gait directly on hardware would wear out motors and take weeks, so the team loads the robot URDF into PyBullet in DIRECT mode and runs a reinforcement learning algorithm across 32 parallel processes on a server.
At every episode the script randomizes ground friction between 0.5 and 1.1, adds up to 20 milliseconds of control latency and varies the body mass by about 10 percent. After roughly a day of training, the policy walks steadily in simulation. Deployed on the physical robot, it walks on the first trial with slightly shorter steps, and a few hours of fine-tuning close the remaining gap. The randomization, not the simulator alone, made the transfer from simulation to reality succeed.