Documentation Index
Fetch the complete documentation index at: https://mintlify.com/autorope/donkeycar/llms.txt
Use this file to discover all available pages before exploring further.
Datastore parts handle recording driving data to tubs and managing tub datasets.
Tub (v2)
The primary datastore class for recording and reading driving data.
Constructor:
Tub(base_path, inputs=[], types=[], metadata=[], max_catalog_len=1000, read_only=False)
List of input channel names (e.g., [‘cam/image_array’, ‘user/angle’])
List of data types corresponding to inputs (e.g., [‘image_array’, ‘float’])
List of metadata key:value pairs
Maximum catalog size before flushing
Open tub in read-only mode
Supported Data Types:
'float': Floating point numbers
'int': Integers
'str': Strings
'boolean': Boolean values
'image_array': NumPy image arrays (saved as JPEG)
'gray16_array': 16-bit grayscale images (saved as PNG)
'nparray': Generic NumPy arrays (saved as list)
'list' or 'vector': Lists of values
Methods:
Write a single record to the tub
delete_records
(record_indexes: list) -> None
Delete specific records by index
Delete the last N records
restore_records
(record_indexes: list) -> None
Restore previously deleted records
Close the tub and flush data
Iterate over all records in the tub
Get number of records in the tub
Usage Example:
from donkeycar.parts.tub_v2 import Tub
import numpy as np
# Create a new tub
tub = Tub(
base_path='data/tub_1',
inputs=['cam/image_array', 'user/angle', 'user/throttle'],
types=['image_array', 'float', 'float']
)
# Write a record
img = np.random.randint(0, 255, (120, 160, 3), dtype=np.uint8)
record = {
'cam/image_array': img,
'user/angle': 0.5,
'user/throttle': 0.3
}
tub.write_record(record)
# Close when done
tub.close()
TubWriter
Donkeycar part for writing records to a tub.
Constructor:
TubWriter(base_path, inputs=[], types=[], metadata=[], max_catalog_len=1000)
List of input channel names
Methods:
Donkeycar part interface. Accepts values matching inputs list and writes record. Returns current record index.
Usage Example:
from donkeycar.parts.tub_v2 import TubWriter
# Create writer
tub_writer = TubWriter(
base_path='data/tub_1',
inputs=['cam/image_array', 'user/angle', 'user/throttle', 'user/mode'],
types=['image_array', 'float', 'float', 'str']
)
# Add to vehicle
V.add(tub_writer,
inputs=['cam/image_array', 'user/angle', 'user/throttle', 'user/mode'],
outputs=['tub/num_records'],
run_condition='recording')
TubHandler
Helper class for managing multiple tubs.
Constructor:
Base path containing tubs
Methods:
Get list of tub directories
Get next available tub number
Create a new tub path with incremented number and date
new_tub_writer
(inputs, types, user_meta) -> TubWriter
Create a new TubWriter with auto-generated path
Usage Example:
from donkeycar.parts.datastore import TubHandler
handler = TubHandler(path='data')
# Create new tub with auto-naming
tub_writer = handler.new_tub_writer(
inputs=['cam/image_array', 'user/angle', 'user/throttle'],
types=['image_array', 'float', 'float'],
user_meta=['location:track1', 'driver:alice']
)
TubWiper
Part for deleting recent records during recording (delete bad data on the fly).
Constructor:
TubWiper(tub, num_records=20)
Number of records to delete when triggered
Methods:
run
(is_delete: bool) -> None
Delete records when trigger switches from False to True (debounced)
Usage Example:
from donkeycar.parts.tub_v2 import TubWriter, TubWiper
# Create tub writer
tub_writer = TubWriter('data/tub_1', inputs=['cam/image_array'], types=['image_array'])
# Create wiper
wiper = TubWiper(tub=tub_writer.tub, num_records=50)
# Add to vehicle
V.add(wiper, inputs=['delete_records'])
Legacy Tub (v1)
Older tub implementation (deprecated, use Tub v2 instead).
Constructor:
Tub(path, inputs=None, types=None, user_meta=[])
Methods: Similar to v2 but with different internal implementation.
Record Structure
Each record contains:
- User-defined fields (inputs)
- Private metadata:
_timestamp_ms: Timestamp in milliseconds
_index: Record index
_session_id: Recording session ID
Example Record
{
"cam/image_array": "123_cam-image_array_.jpg",
"user/angle": 0.15,
"user/throttle": 0.3,
"user/mode": "user",
"_timestamp_ms": 1234567890,
"_index": 123,
"_session_id": "abc123"
}
Tub Directory Structure
data/tub_1/
├── manifest.json # Tub metadata and catalog
├── images/ # Image files
│ ├── 0_cam-image_array_.jpg
│ ├── 1_cam-image_array_.jpg
│ └── ...
└── deleted.json # Deleted record indexes (optional)
Manifest File
The manifest.json contains:
- Input channel names and types
- Metadata
- Current index
- Session information
- Record catalog
Example:
{
"inputs": ["cam/image_array", "user/angle", "user/throttle"],
"types": ["image_array", "float", "float"],
"metadata": {},
"current_index": 1234,
"session_id": "abc123",
"records": [
{"_index": 0, "_timestamp_ms": 1234567890, ...},
{"_index": 1, "_timestamp_ms": 1234567891, ...}
]
}
Configuration
Typical datastore configuration in myconfig.py:
# Tub Settings
TUB_PATH = 'data'
MAX_CATALOG_LEN = 1000
# Inputs to record
INPUTS = ['cam/image_array', 'user/angle', 'user/throttle', 'user/mode']
TYPES = ['image_array', 'float', 'float', 'str']
# Auto-delete settings
NUM_RECORDS_TO_ERASE = 100
Integration Example
From templates like complete.py:
from donkeycar.parts.datastore import TubHandler
from donkeycar.parts.tub_v2 import TubWriter
# Create tub handler
tub_handler = TubHandler(path=cfg.DATA_PATH)
# Create new tub
inputs = ['cam/image_array', 'user/angle', 'user/throttle', 'user/mode']
types = ['image_array', 'float', 'float', 'str']
tub = tub_handler.new_tub_writer(inputs=inputs, types=types)
# Add to vehicle
V.add(tub,
inputs=inputs,
outputs=['tub/num_records'],
run_condition='recording')
Reading Tubs for Training
from donkeycar.parts.tub_v2 import Tub
# Open existing tub
tub = Tub('data/tub_1', read_only=True)
# Iterate over records
for record in tub:
img = record['cam/image_array']
angle = record['user/angle']
throttle = record['user/throttle']
# ... use for training
# Get tub size
num_records = len(tub)