0
# State Management and Logging
1
2
Save and restore simulation states, log data for analysis, and manage user-defined data attachments. Essential for reproducible experiments, data collection, and simulation checkpointing.
3
4
## Capabilities
5
6
### State Management
7
8
```python { .api }
9
def saveState(physicsClientId=0):
10
"""
11
Save complete world state to memory.
12
13
Args:
14
physicsClientId (int, optional): Physics client ID
15
16
Returns:
17
int: State unique ID for later restoration
18
"""
19
20
def restoreState(stateId, fileName=None, physicsClientId=0):
21
"""
22
Restore world state from saved state ID or file.
23
24
Args:
25
stateId (int): State unique ID (if restoring from memory)
26
fileName (str, optional): File name (if restoring from file)
27
physicsClientId (int, optional): Physics client ID
28
"""
29
30
def removeState(stateId, physicsClientId=0):
31
"""
32
Remove saved state from memory.
33
34
Args:
35
stateId (int): State unique ID to remove
36
physicsClientId (int, optional): Physics client ID
37
"""
38
39
def loadBullet(bulletFileName, physicsClientId=0):
40
"""
41
Load world state from .bullet file.
42
43
Args:
44
bulletFileName (str): Path to .bullet file
45
physicsClientId (int, optional): Physics client ID
46
47
Returns:
48
list: List of loaded object IDs
49
"""
50
51
def saveBullet(bulletFileName, physicsClientId=0):
52
"""
53
Save complete world state to .bullet file.
54
55
Args:
56
bulletFileName (str): Output .bullet file path
57
physicsClientId (int, optional): Physics client ID
58
"""
59
60
def saveWorld(worldFileName, physicsClientId=0):
61
"""
62
Save world as approximate Python script.
63
64
Args:
65
worldFileName (str): Output Python file path
66
physicsClientId (int, optional): Physics client ID
67
"""
68
```
69
70
### Data Logging
71
72
```python { .api }
73
def startStateLogging(loggingType, fileName, objectUniqueIds=None, maxLogDof=None, bodyUniqueIdA=None, bodyUniqueIdB=None, linkIndexA=None, linkIndexB=None, physicsClientId=0):
74
"""
75
Start logging simulation data to file.
76
77
Args:
78
loggingType (int): Type of logging (STATE_LOGGING_VIDEO_MP4, etc.)
79
fileName (str): Output file name
80
objectUniqueIds (list, optional): Objects to log
81
maxLogDof (int, optional): Maximum degrees of freedom to log
82
83
Returns:
84
int: Logging unique ID
85
"""
86
87
def stopStateLogging(loggingUniqueId, physicsClientId=0):
88
"""
89
Stop data logging.
90
91
Args:
92
loggingUniqueId (int): Logging unique ID from startStateLogging
93
physicsClientId (int, optional): Physics client ID
94
"""
95
```
96
97
### User Data Management
98
99
```python { .api }
100
def addUserData(bodyUniqueId, key, value, linkIndex=-1, visualShapeIndex=-1, physicsClientId=0):
101
"""
102
Add or update user data entry for object.
103
104
Args:
105
bodyUniqueId (int): Object unique ID
106
key (str): Data key identifier
107
value (str): Data value
108
linkIndex (int, optional): Link index (-1 for base)
109
visualShapeIndex (int, optional): Visual shape index
110
physicsClientId (int, optional): Physics client ID
111
112
Returns:
113
int: User data unique ID
114
"""
115
116
def getUserData(userDataId, physicsClientId=0):
117
"""
118
Get user data value by ID.
119
120
Args:
121
userDataId (int): User data unique ID
122
physicsClientId (int, optional): Physics client ID
123
124
Returns:
125
str: User data value
126
"""
127
128
def getUserDataId(bodyUniqueId, key, linkIndex=-1, visualShapeIndex=-1, physicsClientId=0):
129
"""
130
Get user data ID by key.
131
132
Args:
133
bodyUniqueId (int): Object unique ID
134
key (str): Data key identifier
135
linkIndex (int, optional): Link index
136
visualShapeIndex (int, optional): Visual shape index
137
physicsClientId (int, optional): Physics client ID
138
139
Returns:
140
int: User data unique ID
141
"""
142
143
def removeUserData(userDataId, physicsClientId=0):
144
"""
145
Remove user data entry.
146
147
Args:
148
userDataId (int): User data unique ID
149
physicsClientId (int, optional): Physics client ID
150
"""
151
152
def getNumUserData(bodyUniqueId, physicsClientId=0):
153
"""
154
Get number of user data entries for object.
155
156
Args:
157
bodyUniqueId (int): Object unique ID
158
physicsClientId (int, optional): Physics client ID
159
160
Returns:
161
int: Number of user data entries
162
"""
163
164
def getUserDataInfo(bodyUniqueId, userDataIndex, physicsClientId=0):
165
"""
166
Get user data information by index.
167
168
Args:
169
bodyUniqueId (int): Object unique ID
170
userDataIndex (int): User data index (0 to getNumUserData-1)
171
physicsClientId (int, optional): Physics client ID
172
173
Returns:
174
tuple: (userDataId, key, bodyUniqueId, linkIndex, visualShapeIndex)
175
"""
176
177
def syncUserData(bodyUniqueIds=None, physicsClientId=0):
178
"""
179
Synchronize user data from server.
180
181
Args:
182
bodyUniqueIds (list, optional): Specific objects to sync
183
physicsClientId (int, optional): Physics client ID
184
"""
185
```
186
187
## Usage Examples
188
189
### State Save and Restore
190
191
```python
192
import pybullet as p
193
import time
194
195
p.connect(p.GUI)
196
p.setGravity(0, 0, -9.81)
197
198
# Set up initial scene
199
p.loadURDF("plane.urdf")
200
cube_id = p.loadURDF("cube_small.urdf", [0, 0, 1])
201
robot_id = p.loadURDF("r2d2.urdf", [1, 0, 1])
202
203
# Simulate for a while
204
for i in range(100):
205
p.stepSimulation()
206
time.sleep(1./240.)
207
208
# Save current state
209
state_id = p.saveState()
210
print(f"Saved state with ID: {state_id}")
211
212
# Continue simulation and make changes
213
p.applyExternalForce(cube_id, -1, [10, 0, 0], [0, 0, 0], p.WORLD_FRAME)
214
for i in range(100):
215
p.stepSimulation()
216
time.sleep(1./240.)
217
218
cube_pos, _ = p.getBasePositionAndOrientation(cube_id)
219
print(f"Cube position after force: {cube_pos}")
220
221
# Restore to saved state
222
p.restoreState(state_id)
223
224
# Verify restoration
225
cube_pos_restored, _ = p.getBasePositionAndOrientation(cube_id)
226
print(f"Cube position after restore: {cube_pos_restored}")
227
228
# Clean up
229
p.removeState(state_id)
230
```
231
232
### File-based State Management
233
234
```python
235
import pybullet as p
236
237
p.connect(p.GUI)
238
p.setGravity(0, 0, -9.81)
239
240
# Create scene
241
plane_id = p.loadURDF("plane.urdf")
242
cube_id = p.loadURDF("cube_small.urdf", [0, 0, 1])
243
244
# Save to file
245
p.saveBullet("my_simulation.bullet")
246
print("Saved simulation to bullet file")
247
248
# Save as Python script (approximate)
249
p.saveWorld("recreate_simulation.py")
250
print("Saved world recreation script")
251
252
# Reset and load from file
253
p.resetSimulation()
254
loaded_objects = p.loadBullet("my_simulation.bullet")
255
print(f"Loaded objects: {loaded_objects}")
256
```
257
258
### Data Logging
259
260
```python
261
import pybullet as p
262
import time
263
264
p.connect(p.GUI)
265
p.setGravity(0, 0, -9.81)
266
267
# Set up scene
268
plane_id = p.loadURDF("plane.urdf")
269
robot_id = p.loadURDF("r2d2.urdf", [0, 0, 1])
270
271
# Start video logging
272
video_log = p.startStateLogging(
273
loggingType=p.STATE_LOGGING_VIDEO_MP4,
274
fileName="simulation_video.mp4"
275
)
276
277
# Start generic robot state logging
278
robot_log = p.startStateLogging(
279
loggingType=p.STATE_LOGGING_GENERIC_ROBOT,
280
fileName="robot_states.txt",
281
objectUniqueIds=[robot_id],
282
maxLogDof=7
283
)
284
285
# Run simulation with logging
286
num_joints = p.getNumJoints(robot_id)
287
joint_indices = list(range(num_joints))
288
289
for step in range(500):
290
# Apply some control
291
if num_joints > 0:
292
target_positions = [0.1 * step * ((-1) ** i) for i in range(num_joints)]
293
p.setJointMotorControlArray(
294
robot_id, joint_indices, p.POSITION_CONTROL,
295
targetPositions=target_positions
296
)
297
298
p.stepSimulation()
299
time.sleep(1./240.)
300
301
# Stop logging
302
p.stopStateLogging(video_log)
303
p.stopStateLogging(robot_log)
304
print("Logging completed")
305
```
306
307
### User Data Management
308
309
```python
310
import pybullet as p
311
312
p.connect(p.GUI)
313
plane_id = p.loadURDF("plane.urdf")
314
robot_id = p.loadURDF("r2d2.urdf", [0, 0, 1])
315
316
# Add user data to robot
317
metadata_id = p.addUserData(robot_id, "robot_type", "R2-D2")
318
config_id = p.addUserData(robot_id, "max_speed", "2.5")
319
author_id = p.addUserData(robot_id, "created_by", "Luke Skywalker")
320
321
# Retrieve user data
322
robot_type = p.getUserData(metadata_id)
323
max_speed = p.getUserData(config_id)
324
print(f"Robot type: {robot_type}, Max speed: {max_speed}")
325
326
# Find user data by key
327
speed_id = p.getUserDataId(robot_id, "max_speed")
328
speed_value = p.getUserData(speed_id)
329
print(f"Found max_speed: {speed_value}")
330
331
# List all user data
332
num_data = p.getNumUserData(robot_id)
333
print(f"Robot has {num_data} user data entries:")
334
335
for i in range(num_data):
336
data_info = p.getUserDataInfo(robot_id, i)
337
data_id, key, body_id, link_idx, shape_idx = data_info
338
value = p.getUserData(data_id)
339
print(f" {key}: {value}")
340
341
# Remove user data
342
p.removeUserData(config_id)
343
print(f"Removed max_speed data, now has {p.getNumUserData(robot_id)} entries")
344
345
# Sync user data (useful in multi-client scenarios)
346
p.syncUserData([robot_id])
347
```
348
349
## Logging Types and Constants
350
351
```python
352
# State logging types
353
p.STATE_LOGGING_VIDEO_MP4 # MP4 video recording
354
p.STATE_LOGGING_GENERIC_ROBOT # Robot state data
355
p.STATE_LOGGING_CONTACT_POINTS # Contact point information
356
p.STATE_LOGGING_VR_CONTROLLERS # VR controller states
357
p.STATE_LOGGING_MINITAUR # Minitaur-specific logging
358
```
359
360
## Best Practices
361
362
1. **Memory Management** - Remove unused saved states to prevent memory leaks
363
2. **File Organization** - Use descriptive names for saved files and organize by experiment
364
3. **Logging Efficiency** - Only log necessary data to minimize file sizes and performance impact
365
4. **State Validation** - Verify state restoration worked correctly before continuing simulation
366
5. **User Data Structure** - Use consistent key naming conventions for user data
367
6. **Backup Strategy** - Save critical states to files for permanent storage
368
7. **Multi-client Sync** - Use sync functions when multiple clients modify the same simulation