PyBullet: the friendly option
Zero-install, URDF-native, fastest path from 'I want to simulate a robot' to 'I'm running my first script.' The teaching tool, the prototyping tool, and the lightweight RL sim that punches above its weight.
PyBullet is the simplest way to start simulating robots in 2026. pip install pybullet, write 30 lines of Python, watch a robot move. The development of PyBullet itself has slowed, but the ecosystem (PyBullet Gym, RoboGym, PyBullet ML) is still active. For teaching, prototyping, and any project where the fastest path matters more than peak fidelity, PyBullet is the right pick.
Why PyBullet wins on speed-of-onboarding
- Pure pip install:
pip install pybullet. No CUDA, no Docker, no Linux-only. Runs on any laptop. - Pure Python API: no C++ plugins to compile, no XML config files to edit. Everything is function calls.
- URDF native:
p.loadURDF('robot.urdf')just works. The same URDF used elsewhere drops in. - Reasonable physics: Bullet's contact physics is decent — not as accurate as MuJoCo for stiff contacts, but solid for rolling wheels, articulated arms, and most robotics.
- GUI included:
p.connect(p.GUI)opens a 3D viewport with mouse-orbit controls.
The 30-line working sim
import pybullet as p
import pybullet_data
# Connect — GUI mode for visualization, DIRECT for headless
client = p.connect(p.GUI)
p.setAdditionalSearchPath(pybullet_data.getDataPath())
# World setup
p.setGravity(0, 0, -9.81)
plane = p.loadURDF("plane.urdf")
# Load a robot
robot = p.loadURDF("kuka_iiwa/model.urdf", [0, 0, 0])
n_joints = p.getNumJoints(robot)
# Run physics
for step in range(2400): # 10 seconds at 240 Hz
# Apply some torque to joint 0
p.setJointMotorControl2(
bodyUniqueId=robot,
jointIndex=0,
controlMode=p.VELOCITY_CONTROL,
targetVelocity=1.0,
force=20,
)
p.stepSimulation()
p.disconnect()
That's a complete simulation. Run it; the KUKA iiwa rotates its first joint for 10 seconds. The full Bullet API has hundreds of functions but you'll use ten of them most days.
Sensors and observations
PyBullet's sensor API is direct: query joint state, query contacts, render cameras programmatically.
# Joint state
state = p.getJointState(robot, 0)
position, velocity, _, applied_torque = state
# All joint states at once
positions = [p.getJointState(robot, i)[0] for i in range(n_joints)]
# Camera render
view_matrix = p.computeViewMatrix(
cameraEyePosition=[1, 0, 0.5],
cameraTargetPosition=[0, 0, 0.3],
cameraUpVector=[0, 0, 1],
)
proj_matrix = p.computeProjectionMatrixFOV(60, 1.0, 0.1, 10.0)
_, _, rgb, depth, _ = p.getCameraImage(640, 480, view_matrix, proj_matrix)
# Contact points on a link
contacts = p.getContactPoints(robot, plane, linkIndexA=6)
No plugins to write. The same Python script can simulate, visualize, log, and analyze.
Where PyBullet shines
- Quick prototypes: test an idea in 50 lines before committing to MuJoCo or Gazebo.
- Teaching: the visible API is great for showing students what's happening physically.
- Single-arm, single-robot RL: gym-pybullet-drones, panda-gym are PyBullet-based and serve as quality benchmarks.
- Manipulation research: easy to set up, fast for small scenes.
Where it falls short
- Stiff contacts: contact physics can drift or jitter with very stiff materials. MuJoCo handles these better.
- Massive parallel RL: PyBullet runs one simulation per process; can't easily batch on GPU. MuJoCo MJX or Isaac Lab beat it for thousand-env training.
- Photorealistic rendering: PyBullet's renderer is functional but not pretty. Use Isaac for camera-perception training.
- Active development: PyBullet's core has slowed. New features mostly come from community wrappers.
The Bullet engine vs PyBullet wrapper
Bullet is the underlying physics engine — written in C++, also used in Blender, Cocos2d, many games. PyBullet is the Python wrapper. Bullet's contact-solver tradeoffs (sequential impulse, fast but less accurate than MuJoCo's smooth-contact formulation) determine how it behaves on stiff contacts.
For most robotics, the limitation is rarely the engine; it's the wrapper's lack of GPU batching.
Connecting to ROS
PyBullet doesn't natively bridge ROS. Options:
- roboticstoolbox-python (Peter Corke's): Python interface that wraps PyBullet + ROS messaging.
- Custom bridge: ~50 lines of Python publishing PyBullet state to ROS topics. Most projects roll their own.
- Direct simulator-in-the-loop: Python script reads ROS commands, calls PyBullet, publishes state. Works fine.
For ROS-heavy work, prefer Gazebo. For Python-heavy research, PyBullet wins.
The standard wrappers
| Library | Use |
|---|---|
| PyBullet Gym | RL benchmarks (cartpole, ant, walker) |
| panda-gym | Manipulation tasks on Franka Panda |
| gym-pybullet-drones | Drone RL |
| RoboGym (OpenAI) | Robotic manipulation benchmarks (deprecated; gymnasium-robotics inherits) |
The 2026 production reality
For new projects in 2026:
- Education + first robotics simulation → PyBullet.
- Quick prototyping of any robotics idea → PyBullet.
- Single-task RL on commodity hardware → PyBullet (or MuJoCo if speed matters).
- Production work targeting ROS → switch to Gazebo or MuJoCo.
- Industrial-scale RL → switch to MuJoCo MJX or Isaac Lab.
The path is: start in PyBullet, graduate to a more specialized simulator when limits show up. The 30-line PyBullet starting point teaches you what to look for.
Common gotchas
- Default time-step is 1/240 s: too slow for fast control loops.
p.setTimeStep(1.0/1000.0)for kHz-rate sim. - URDF inertias: PyBullet uses what's in your URDF; bad inertias produce wobbly robots. Same as Gazebo.
- GUI mode is slow: for headless training, use
p.connect(p.DIRECT)— much faster. - Multiple connections: each
p.connectopens a new physics client. Easy to leak.
Exercise
Use PyBullet to load any URDF. Apply gravity. Apply joint torques. Read joint state. In 50 lines, you'll have a working simulator. Now wrap it as a Gymnasium environment with reset / step / observation. You've just built the substrate for any RL experiment. Then port to MuJoCo and observe the speed difference (5–10× for batched envs).
Next
NVIDIA Isaac Sim and Isaac Lab — the photorealistic, GPU-batched simulator that's eating MuJoCo's lunch in industrial-scale RL.
Comments
Sign in to post a comment.