What is Memory?
Memory is a simple dictionary-based storage system where:- Parts write outputs to named channels (keys)
- Other parts read from those same channels (inputs)
- The Vehicle orchestrates reading and writing
- All data persists for one loop iteration
The Memory Class
Defined indonkeycar/memory.py:9-61:
Memory is essentially a Python dictionary with helper methods for batch operations. The Vehicle class uses
put() and get() to manage data flow.How Data Flows
Writing to Memory
Parts return values that the Vehicle stores in Memory:Memory.put() (memory.py:35-45):
Reading from Memory
The Vehicle retrieves inputs before calling a part:Memory.get() (memory.py:49-51):
Vehicle Orchestration
Fromvehicle.py:186-215, the Vehicle manages the flow:
Channel Naming
Channels use a hierarchical naming convention:Sensor Channels
User Input Channels
Autopilot Channels
Control Channels
State Channels
Recording Channels
Data Flow Example
A complete data flow through Memory:Memory State After One Iteration
Memory values persist across iterations. If a part doesn’t run (e.g., due to run_condition), its outputs from previous iterations remain in Memory.
Multiple Outputs
Parts can return multiple values:memory.py:35-42:
No Outputs
Parts that perform actions but don’t return data:vehicle.py:212-213:
outputs is None, nothing is stored.
Accessing Memory Directly
While parts normally don’t access Memory directly, sometimes it’s useful:Use Cases
- Debugging: Inspect Memory state
- Initialization: Set initial values
- Special parts: Parts that modify Memory directly
complete.py:143:
web/buttons (a dict) and expands it into separate Memory keys.
Memory Lifecycle
1. Initialization
2. First Iteration
All inputs areNone because Memory is empty:
3. Subsequent Iterations
Memory contains values from previous parts:4. Run Conditions
If a part doesn’t run, its outputs aren’t updated:Always check for
None values in your parts, especially on the first loop iteration or when using run conditions.Common Patterns
Pattern 1: Pipeline
Data flows sequentially through parts:Pattern 2: Fan-Out
One part’s output feeds multiple parts:Pattern 3: Merge
Multiple inputs combined:Pattern 4: Conditional Branch
Memory and Threading
Threaded parts access Memory through the main loop:- Background thread updates
self.framecontinuously - Main loop calls
run_threaded()to get latest frame - Vehicle stores return value in Memory
- Other parts read from Memory
Debugging Memory
To see what’s in Memory:Best Practices
- Use descriptive channel names:
cam/image_arraynotimg - Follow naming conventions:
category/namepattern - Handle None values: Check inputs on first iteration
- Don’t access Memory directly in parts: Use inputs/outputs
- Keep Memory clean: Don’t store unnecessary data
- Document channels: Comment what each channel contains
- Avoid name collisions: Use unique, specific names
Next Steps
- Learn about the Vehicle Loop that manages Memory
- Understand Parts and how they interact with Memory
- Explore Templates to see Memory in action
- Read the Architecture overview
