MicroPython Language Fundamentals
MicroPython is a compact implementation of the Python language designed to run directly on microcontrollers. ESP-VISION uses MicroPython v1.28.0 as its application language while retaining C/C++ and ESP-IDF components for hardware access and performance-critical vision work. This chapter introduces the language model needed to read and write ESP-VISION applications; the authoritative details remain in the MicroPython v1.28.0 language and implementation reference.
Execution Model
Upstream MicroPython aims to implement Python 3.4 syntax with selected features from later Python versions. ESP-VISION builds the ESP32 port at the EXTRA_FEATURES configuration level, with the on-device compiler, garbage collector, MPZ long integers, single-precision floating point, scheduler, VFS, and persistent bytecode loading enabled. Source code remains dynamically typed Python, but it is compiled to compact bytecode and executed by the MicroPython virtual machine. Native modules connect Python objects to ESP-VISION C/C++ components, ESP-IDF drivers, and chip hardware:

Code loaded from .py is compiled on the device and consumes RAM during compilation. Precompiled .mpy files and modules frozen into the firmware reduce runtime compilation work; immutable constants in frozen modules can remain in Flash. Python still owns application policy and object lifetimes, while native components implement operations such as frame capture, image processing, codecs, and AI inference.
Basic Syntax
The current ESP-VISION configuration uses indentation to define blocks and supports the familiar Python forms for assignment, expressions, conditions, loops, functions, classes, exceptions, context managers, comprehensions, generators, imports, and async/await. Names are dynamically bound to objects, so a declaration does not specify a C-style storage type:
from micropython import const
_MIN_PIXELS = const(80)
class Detection:
def __init__(self, label, score):
self.label = label
self.score = score
def accepted(self, threshold=0.5):
return self.score >= threshold
def select_results(results):
selected = []
for label, score in results:
item = Detection(label, score)
if item.accepted():
selected.append(item)
return selected
try:
detections = select_results((("person", 0.91), ("chair", 0.42)))
for item in detections:
print(item.label, item.score)
except (ValueError, TypeError) as error:
print("invalid result:", error)
finally:
print("processing complete")
const() is a MicroPython extension that lets the compiler substitute a constant value and can reduce bytecode and global-dictionary overhead. Type annotations may be useful to developers and editors, but MicroPython does not use them to provide C-style static typing or automatic memory layout.
Main Data Structures
The choice between mutable and immutable objects matters on a microcontroller because creating, resizing, or concatenating objects allocates heap memory:
Type |
Mutability |
ESP-VISION usage |
|---|---|---|
|
Immutable |
Represent absence and state flags without defining custom sentinel objects. |
|
Immutable |
Store counters, coordinates, thresholds, and scores. Repeated arithmetic can create new objects; avoid floating-point work in hard interrupt context. |
|
Immutable |
Store text, paths, labels, and JSON keys. Concatenation creates a new string, so avoid building large strings every frame. |
|
Immutable |
Store compact binary constants, encoded packets, and read-only model or protocol data. |
|
Mutable |
Provide reusable binary buffers for peripheral I/O and packet assembly without allocating a new object for every operation. |
|
Mutable |
Store ordered results whose size changes. |
|
Immutable |
Represent fixed records such as rectangles and detection results. Constant tuples can be more memory-efficient than repeatedly created lists. |
|
Mutable |
Represent configuration and shared scalar state. Adding keys can resize the table; create the expected structure during initialization. |
|
Mutable |
Perform membership and uniqueness checks when the additional hash-table memory is justified. |
|
Immutable |
Describe integer iteration without constructing a list of all values. |
|
View / mutable |
Access typed or sliced buffer data with fewer copies; the referenced buffer must remain alive and must not be resized while a view is active. |
Object references are shared rather than copied automatically. Assigning b = a makes both names refer to the same mutable list, dictionary, image, or buffer; use an explicit copy only when independent data is required. This is especially important for image.Image objects backed by reusable camera frame buffers.
Design Principles for Microcontrollers
MicroPython prioritizes portability, interactive development, compact firmware integration, and direct hardware access over complete CPython library coverage. Its garbage-collected heap makes dynamic application code practical, but RAM, Flash, stack space, and allocation latency remain finite. The MicroPython guide for constrained devices recommends reducing repeated object creation, preallocating buffers, moving constants and reusable modules into frozen bytecode, and monitoring the heap with gc.mem_free() and gc.mem_alloc().
For ESP-VISION applications, initialize modules, models, buffers, and stable dictionaries before entering the frame loop. Reuse bytearray and image buffers, keep per-frame temporary data bounded, and avoid retaining a camera-backed image after the next sensor.snapshot() unless it has been copied. Use Python to express orchestration and product behavior; leave deterministic real-time work, ISR handling, bulk pixel processing, codecs, and inference kernels in native components.
MicroPython and CPython
In this documentation, “Python” in a runtime comparison means CPython 3.x, the reference implementation commonly used on PCs and servers. The exact MicroPython feature set is firmware-dependent, so this table describes MicroPython v1.28.0 as configured by ESP-VISION: all maintained board manifests freeze asyncio, the ESP32 port enables _thread with a GIL, and hardware APIs remain subject to chip and board configuration.
Area |
ESP-VISION MicroPython |
CPython |
|---|---|---|
Primary environment |
Runs inside MCU firmware with direct access to peripherals and board services. |
Runs as an operating-system process on PCs, servers, and larger embedded systems. |
Language syntax |
Implements Python 3.4 syntax with selected later features; most common control flow, functions, classes, exceptions, generators, and asynchronous syntax are available. |
Tracks the current Python language specification and generally introduces new syntax first. |
Type system |
Dynamically typed; annotations do not make execution statically typed. |
Dynamically typed; annotations are consumed mainly by tools and optional libraries. |
Standard library |
Provides a resource-oriented subset selected at firmware build time, plus |
Provides the full CPython standard library for the installed version, without a standard MCU peripheral API. |
Package deployment |
Modules are copied to storage, precompiled as |
Commonly uses |
Memory model |
Uses a small garbage-collected heap shared with firmware resources; allocation failures and fragmentation must be considered explicitly. |
Uses a much larger process heap and reference counting with cyclic garbage collection. |
Concurrency |
Provides frozen |
Provides |
Performance path |
Calls native C/C++ modules and hardware accelerators for demanding operations; Python is best used for orchestration. |
Can use optimized extension modules, JIT-enabled alternative runtimes, or multiprocessing, but usually has greater CPU and memory resources. |
Compatibility details |
Some built-in behavior, exception text, introspection, module contents, and edge cases differ to reduce code size and RAM usage. |
Defines the reference behavior against which MicroPython differences are documented. |
Portability |
Pure Python code using the supported subset is often portable; hardware modules and resource assumptions are device-specific. |
Pure Python code is portable across supported operating systems when its dependencies are available. |
Do not decide portability from syntax alone. Check imported modules, memory use, filesystem paths, concurrency assumptions, and hardware access. The upstream MicroPython and CPython differences list documents known behavioral differences, while MicroPython APIs describes the inherited APIs and concurrency model available in ESP-VISION.