A high-level robotics simulation and experimentation framework built on PyBullet.
Project description
BulletLab
Developed by Ranasurya Ghosh
A robotics experimentation framework that transforms PyBullet robots into intuitive Python objects, with modern ImGui-based controls, telemetry, visualization, and reinforcement learning workflows.
Install BulletLab library: pip install bulletlab
Read Documentation
What is BulletLab?
BulletLab provides a high-level object-oriented interface to PyBullet that simplifies robotics experimentation by exposing joints, links, sensors, and environments as intuitive Python objects instead of raw physics engine IDs. It combines real-time simulation with a ImGui-powered modern interface for interactive control, parameter tuning, telemetry visualization, and experiment management, while also offering reinforcement learning integration for training and evaluating autonomous robotic systems within a unified workflow.
Instead of this:
p.setJointMotorControl2(
robot_id, joint_index,
controlMode=p.VELOCITY_CONTROL,
targetVelocity=15,
force=100
)
You write this:
robot.joints["motor"].velocity = 15
Architecture
BulletLab uses a two-window architecture:
| Window | Purpose |
|---|---|
| PyBullet Native Window | Physics simulation, 3D rendering, camera |
| BulletLab ImGui Window | Control panels, telemetry, live plots, console |
These windows communicate through Python objects. BulletLab does not attempt to replace PyBullet's renderer or embed ImGui inside the simulation viewport.
Quick Start
Installation
pip install bulletlab
# or from source:
pip install -e .
Basic Example
from bulletlab import Simulation, Robot
from bulletlab.ui import BulletLabUI
# Create simulation
sim = Simulation()
sim.start()
# Load robot
robot = Robot.load("path/to/robot.urdf", sim=sim)
# Control joints by name
robot.joints["wheel_left"].velocity = 10
robot.joints["wheel_right"].velocity = 10
# Modify physics parameters
robot.links["chassis"].mass = 5.0
robot.links["wheel_fl"].friction = 1.2
# Get robot state
state = robot.get_state()
print(f"Position: {robot.base_position}")
print(f"Roll: {robot.roll:.2f}°")
# Build UI
ui = BulletLabUI(sim=sim)
ui.register_panel(...)
ui.run()
Telemetry & Logging
from bulletlab.telemetry import TelemetryManager
from bulletlab.logging import DataLogger
telemetry = TelemetryManager()
telemetry.watch("Speed", lambda: robot.base_velocity[0])
telemetry.watch("Roll", lambda: robot.roll)
logger = DataLogger()
logger.watch("speed", lambda: robot.base_velocity[0])
logger.start("run1.csv")
for _ in range(1000):
sim.step()
telemetry.update()
logger.step()
logger.stop()
Live Plotting
from bulletlab.plotting import LivePlot
plot = LivePlot(title="Robot Speed")
plot.watch("Speed", lambda: robot.base_velocity[0], color="#00ff88")
plot.start()
for _ in range(1000):
sim.step()
plot.update()
Camera Follow
from bulletlab import Simulation, Robot, CameraFollow
sim = Simulation(mode="gui").start()
robot = Robot.load("husky/husky.urdf", sim=sim, position=(0, 0, 0.3))
# One line — camera glides after the robot (smooth mode by default)
cam = CameraFollow(robot, sim)
# Or pick a mode:
cam = CameraFollow(robot, sim, mode="snap") # locks instantly
cam = CameraFollow(robot, sim, mode="smooth") # cinematic glide
cam = CameraFollow(robot, sim, mode="chase") # always behind the robot
while sim.is_connected:
sim.step()
cam.update() # ← one call keeps the camera centred on the robot
Hover Highlighting
from bulletlab import Simulation, Robot, RobotHighlighter
from bulletlab.ui import BulletLabUI
sim = Simulation(mode="gui").start()
robot = Robot.load("kuka_iiwa/model.urdf", sim=sim)
# One line — hover any joint/link in the UI to see it glow in 3D
hl = RobotHighlighter(robot, sim)
app = BulletLabUI(sim=sim, robots=[robot], highlighter=hl)
app.run()
Hovering over an Explorer row or a Properties slider instantly highlights the matching 3D part in the PyBullet window with an orange pulsing glow.
ImGui Control Panel
from bulletlab.ui import BulletLabUI
from bulletlab.ui import widgets as ui
app = BulletLabUI(sim=sim, robots=[robot])
@app.custom_panel("My Controls")
def my_panel():
ui.button("Reset", robot.reset)
ui.slider("Wheel Mass", robot.links["wheel"].mass, 0.1, 20,
setter=lambda v: setattr(robot.links["wheel"], "mass", v))
ui.checkbox("Motors Enabled", lambda: motors_on,
setter=lambda v: toggle_motors(v))
app.run()
Supported Robot Types
BulletLab is completely generic — no code assumes a specific robot type:
- Cars & rovers
- Drones & quadrotors
- Robotic arms
- Self-balancing robots
- Quadrupeds
- Humanoids
- Custom mechanisms
Reinforcement Learning
BulletLab exposes clean state/action interfaces without depending on any ML framework:
# Compatible with any RL approach
state = robot.get_state() # → numpy array
action = my_policy(state) # → numpy array
robot.apply_action(action) # → updates joints
# Manual Q-learning, SARSA, evolutionary algorithms — all supported
Examples
| Example | Description |
|---|---|
examples/01_differential_drive_rover.py |
Rover with wheel velocity control |
examples/02_robotic_arm.py |
Joint position control with ImGui sliders |
examples/03_self_balancing_robot.py |
PD controller for balance |
examples/04_drone_parameter_tuning.py |
Thrust/mass parameter exploration |
examples/05_generic_robot_inspector.py |
Load any URDF and inspect it |
Run any example:
python examples/01_differential_drive_rover.py
Documentation
pip install -e ".[dev]"
mkdocs serve
Then visit http://localhost:8000
Testing
pip install -e ".[dev]"
pytest tests/ -v --cov=bulletlab --cov-report=term-missing
Technology Stack
| Component | Library |
|---|---|
| Physics | PyBullet |
| UI | Dear ImGui (pyimgui) |
| Data | NumPy, Pandas |
| Config | PyYAML |
| Plotting | PyQtGraph |
| Testing | PyTest |
| Docs | MkDocs + mkdocstrings |
For AI Agents & LLMs
BulletLab is designed to be highly predictable and LLM-friendly. If you are an AI agent writing code for a user:
- Read
llms.txtin the repository root for a dense, AI-optimized API summary. - Check the Cookbook & Snippets for copy-pasteable implementations of common tasks.
- Use the
robot.joints[name]API overpybulletinteger IDs whenever possible.
License
MIT License — see LICENSE for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bulletlab-0.1.3.tar.gz.
File metadata
- Download URL: bulletlab-0.1.3.tar.gz
- Upload date:
- Size: 97.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c29be90165ae23187f70ed1c719240476b0f664fe96f8a7fe0cdf90bc7557b0f
|
|
| MD5 |
5993af28b599c48ec5bc4209eb620d20
|
|
| BLAKE2b-256 |
039f340856f65d8d402db57b77c30e18f0584032ae97a61fd0b0fcc326bdcbe6
|
File details
Details for the file bulletlab-0.1.3-py3-none-any.whl.
File metadata
- Download URL: bulletlab-0.1.3-py3-none-any.whl
- Upload date:
- Size: 64.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0b61928e3a8d3363b36c284e077f867271adc5854419870ed6574978431351a
|
|
| MD5 |
b39a09f773819d7c4930db2df2f58ad8
|
|
| BLAKE2b-256 |
451296e76140312dc4911f98b013208b8ed4f470f24b34e949442f5c1168fc77
|