Design Philosophy
The Donkeycar architecture follows several key principles:Modularity First
Every capability in Donkeycar is implemented as a self-contained part. Parts can be:- Hardware interfaces (cameras, motors, sensors)
- Processing components (image transforms, neural networks)
- Control logic (PID controllers, state machines)
- Data handlers (logging, recording)
Data Flow Architecture
Donkeycar uses a shared memory model where parts communicate through named channels:- Loose coupling: Parts don’t need to know about each other
- Easy debugging: You can inspect any value in the pipeline
- Simple composition: Connect parts by matching input/output names
Synchronous Loop with Threading
The vehicle runs a synchronous drive loop that executes all parts sequentially at a fixed rate (typically 20 Hz). This provides:- Predictable execution order
- Consistent timing
- Easy reasoning about system behavior
Core Components
Vehicle Class
TheVehicle class (in donkeycar/vehicle.py:61) is the heart of the framework:
- The Memory instance (shared data store)
- A list of parts with their input/output mappings
- Threading for background parts
- Performance profiling
Memory System
TheMemory class (in donkeycar/memory.py:9) provides a simple key-value store:
'cam/image_array', 'user/angle', 'pilot/throttle', etc.
Parts
Parts are Python classes or functions that implement either:run(*inputs)- for synchronous executionrun_threaded(*inputs)- for threaded executionupdate()- for background threadsshutdown()- for cleanup (optional)
Templates
Templates are pre-configured vehicle applications for common use cases:- complete.py - Full-featured autonomous car with ML autopilot
- basic.py - Minimal car with camera and manual control
- path_follow.py - Path following with odometry/GPS
- cv_control.py - Computer vision-based control
- simulator.py - For Donkey Gym simulation
System Architecture Diagram
Execution Flow
-
Initialization
- Create Vehicle instance
- Add parts with
V.add(part, inputs=[...], outputs=[...]) - Parts are registered in order
-
Startup (
V.start(rate_hz=20))- Start background threads for threaded parts
- Enter main drive loop
-
Drive Loop (each iteration)
- For each part:
- Check run condition (if specified)
- Get inputs from Memory
- Call
run()orrun_threaded() - Put outputs into Memory
- Sleep to maintain target rate_hz
- For each part:
-
Shutdown
- Call
shutdown()on all parts - Report performance profiling data
- Call
The framework automatically handles the data flow between parts. You just need to match input names with output names, and the Vehicle orchestrates everything.
Threading Model
Synchronous Parts (default)
- Part’s
run()method is called in the main loop - Blocks until execution completes
- Use for fast operations (< 50ms)
Threaded Parts
- Part’s
update()method runs in a background thread - Main loop calls
run_threaded()to get latest output - Use for slow I/O (cameras, network, sensors)
Threaded parts continuously update in the background while the main loop just reads their latest output via
run_threaded(). This prevents slow operations from blocking the entire vehicle loop.Run Conditions
Parts can have conditional execution:- User vs autopilot mode switching
- Conditional data recording
- Feature toggling
- Button-triggered actions
Performance Profiling
Donkeycar includes built-in profiling (seevehicle.py:20):
- Execution time for each part (max, min, avg)
- Percentile statistics (50%, 90%, 99%, 99.9%)
- Identification of performance bottlenecks
Configuration-Driven
Donkeycar uses a configuration file (myconfig.py) to control behavior:
- Switch hardware without code changes
- Tune parameters
- Enable/disable features
- Share configurations
Extensibility
The architecture makes it easy to extend Donkeycar:Adding New Parts
Creating Templates
Templates are just Python scripts that compose parts:Swapping Implementations
Because parts are loosely coupled, you can swap implementations:Best Practices
- Keep parts small and focused - Each part should do one thing well
- Use meaningful channel names - Follow the convention
category/name(e.g.,cam/image_array,pilot/angle) - Make threaded parts for I/O - Cameras, network, sensors should be threaded
- Profile your loop - Use verbose mode to identify bottlenecks
- Handle shutdown gracefully - Implement
shutdown()to clean up resources
Next Steps
- Learn about the Vehicle Loop and how the drive cycle works
- Understand Parts and how to create custom components
- Explore Templates for different vehicle configurations
- Study the Memory system and data flow
