MicroPython: Python для микроконтроллеров ESP32 и RP2040
Python, который живёт на чипе за пару долларов: интерпретатор в сотни килобайт, модуль machine для пинов и стандартная библиотека, ужатая до сути. Разбираем отличия от CPython и стиль кода под маленькую память.
Редакция Питоники
Вся таблица реализаций из урока 16 жила на компьютерах — больших или виртуальных. MicroPython спускает Python на землю, почти в буквальном смысле: интерпретатор, который помещается в сотни килобайт и живёт прямо на микроконтроллере — чипе за пару долларов. Урок про то, что остаётся от языка на чипе, чем MicroPython отличается от CPython и как выглядит код для железа.
Что такое MicroPython
MicroPython написал Дэмиен Джордж: проект собрался на Kickstarter в 2013 году и вырос в целое семейство портов. Сегодня официальный MicroPython работает на ESP32 и ESP8266, на RP2040 — чипе Raspberry Pi Pico, на платах micro:bit и линейке STM32. Интерпретатор компилируется под конкретный чип, зашивается в его флеш-память вместо прошивки, и после включения плата уже умеет исполнять Python: подача питания — и через секунды работает ваша программа.
Ключевое отличие от всего, что было в разделе раньше, — масштаб. CPython ставит на диск десятки мегабайт и живёт в гигабайтах оперативной памяти; MicroPython занимает сотни килобайт флеша и управляется килобайтами RAM. Из этого масштаба вырастает всё остальное: урезанная библиотека, свои модули для железа и особая экономия в коде.
| Свойство | CPython | MicroPython |
|---|---|---|
| Размер интерпретатора | Десятки мегабайт | Сотни килобайт |
| Память данных | Гигабайты RAM | Килобайты RAM |
| Стандартная библиотека | Полная | Подмножество: json, math, sys и ещё десятки |
| Работа с железом | Через внешние библиотеки | Модуль machine: пины, ШИМ, ADC, I2C |
| Пакеты | pip и PyPI | mip и заморозка в прошивку |
| Обновление | Установка новой версии | Перепрошивка устройства |
Как код понимает, где он живёт
Модуль machine есть только на устройстве с прошивкой MicroPython. Отсюда переносимый способ определить среду: попытка импорта в try — на чипе она сработает, на обычном Python честно упадёт в except. Тот же приём, что с отсутствующими библиотеками в уроке про FileNotFoundError и импорты исключений:
try:
import machine
print('machine доступен: мы на микроконтроллере')
except ImportError:
print('machine недоступен: обычный Python')
machine недоступен: обычный Python
В песочнице и на десктопе ответ один: machine недоступен — и это правильный ответ среды о себе. На настоящей ESP32 первая ветка открылась бы, и дальше код работал бы с железом:
from machine import Pin
led = Pin(25, Pin.OUT)
led.value(1)
Pin(25, Pin.OUT) объявляет пин двадцать пять выходом, а value(1) подаёт на него единицу — включённое состояние. Вся работа с железом в MicroPython построена на этом модуле: пины, ШИМ для управления яркостью и моторами, ADC для чтения аналоговых датчиков, шины I2C и SPI для внешних микросхем.
Что урезано: стандартная библиотека
Из стандартной библиотеки CPython на чипе живёт выбранное: json и math, sys и gc, time, struct и немного itertools. Тяжёлых модулей нет — никаких tkinter, multiprocessing или threading в полном виде. Есть и модули, которых в CPython не существует: у MicroPython свой sys без некоторых функций настольного Python. Проверка hasattr из урока 16 работает как зонд:
import sys
print('есть implementation?', hasattr(sys, 'implementation'))
print('есть getsizeof?', hasattr(sys, 'getsizeof'))
print('есть maxsize?', hasattr(sys, 'maxsize'))
есть implementation? True есть getsizeof? True есть maxsize? True
В песочнице все три ответа True: у CPython в sys есть и implementation, и getsizeof, и maxsize. На настоящем MicroPython третья строка тоже дала бы True, а вот getsizeof — измерение размера объекта в байтах — там не существует: код, который опирается на точные размеры, на чипе упадёт с AttributeError. Отсюда правило переносимости: возможности проверяются hasattr-ом, а не предполагаются.
Стиль кода под маленькую память
На чипе каждый килобайт на счету, и стиль кода меняется: кортежи вместо объектов с классами, bytes вместо str, генераторы вместо списков. Показания датчиков — пример данных, которые на настольном Python стали бы списком словарей, а на чипе живут компактным кортежем пар:
readings = [('temp', 21.5), ('hum', 48.0), ('press', 1013.0)]
for name, value in readings:
print(name, '=', value)
temp = 21.5 hum = 48.0 press = 1013.0
Заметьте: сам код — обычный Python. Распаковка пар в цикле, кортежи, печать — всё это работает и на CPython, и на MicroPython одинаково. Компактный стиль не является особым языком: это те же конструкции, применённые с экономией. Крупные словари с сотнями ключей на чипе не влезут — и правильный код заранее знает размер своих данных.
Второй приём экономии — bytes вместо строк там, где данные не текст. У bytes меньше накладных расходов, а перебирается он как последовательность чисел:
header = b'META'
print('bytes перебирается как числа:', [b for b in header])
bytes перебирается как числа: [77, 69, 84, 65]
Четыре символа заголовка превратились в четыре кода: 77 — M, 69 — E, 84 — T, 65 — A. Для протоколов обмена с железом — команд, заголовков пакетов, сигнатур — bytes и есть правильный тип, и на настольном Python этот же код работает без правок.
Мигаем светодиодом логически
Каноническая первая программа на микроконтроллере — мигание светодиодом. На чипе в цикле стоит вызов machine, но каркас мигания — чистая логика переключения состояния. Вынесем логику отдельно и выполним её прямо здесь:
led_on = False
for tick in range(6):
led_on = not led_on
print('тик', tick, '- светодиод', 'горит' if led_on else 'погашен')
тик 0 - светодиод горит тик 1 - светодиод погашен тик 2 - светодиод горит тик 3 - светодиод погашен тик 4 - светодиод горит тик 5 - светодиод погашен
Шесть тиков — шесть честных переключений. Логика на MicroPython — обычный Python: каркас циклов и словарей переносится на десктоп без правок. Чтобы превратить этот код в настоящее мигание, достаточно внутрь цикла добавить вызов led.value(1 if led_on else 0) и паузу sleep — структура программы не изменится ни на строку.
Как поставить MicroPython
- скачать прошивку под свою плату с официального сайта micropython.org;
- залить прошивку: для ESP32 — утилитой esptool, для RP2040 — файлом UF2, который просто переносится на диск платы;
- открыть REPL: через Thonny или командой mpremote — питон-консоль прямо в чипе;
- положить main.py в файловую систему устройства — он запускается при подаче питания.
mpremote cp main.py :main.py
mpremote repl
MicroPython доказывает: между языком и микроконтроллером — считанные сотни килобайт. Циклы, словари и функции живут на чипе, урезана только библиотека, а железо пришло своим модулем machine. Следующий урок — четыре платформенные реализации: Jython на JVM, IronPython на .NET, RustPython на Rust и Brython в браузере.
Сначала предскажи ответ в голове — это главный навык программиста.
try:
import machine
print('на чипе')
except ImportError:
print('на обычном Python')
led_on = False
led_on = not led_on
led_on = not led_on
print('светодиод', 'горит' if led_on else 'погашен')
header = b'OK'
print([b for b in header])
1. Что такое MicroPython?
2. Как обычный код узнаёт, что он работает не на чипе?
3. Чем модуль machine занимается в MicroPython?
4. Как на MicroPython ставятся библиотеки?
5. Почему для показаний датчиков на чипе берут кортежи, а не классы?
6. Что происходит с MemoryError на микроконтроллере?
7. Какая плата из перечисленных официально поддерживается MicroPython?
Смоделируйте мигание светодиода: 4 переключения, начиная с выключенного. Печатайте строку вида тик N - вкл или тик N - выкл, где N начинается с 1.
Чем MicroPython отличается от обычного Python?
Язык одинаковый, но интерпретатор ужат до сотен килобайт и живёт на микроконтроллере: стандартная библиотека — подмножество, работа с железом через модуль machine, pip и C-расширения отсутствуют, большие данные не влезают в RAM.
Урок 16: реализации PythonКакие платы поддерживают MicroPython?
Официальные порты: ESP32 и ESP8266, Raspberry Pi Pico на RP2040, micro:bit, платы STM32. Для RP2040 прошивка ставится файлом UF2 — его достаточно скопировать на появившийся диск платы.
Как написать мигание светодиодом на MicroPython?
Через machine: from machine import Pin — led = Pin(25, Pin.OUT), затем в цикле led.value(1 if led_on else 0) и пауза sleep. Логика переключения — обычный Python: её структуру можно отладить на настольном Python без железа.
Можно ли ставить pip-пакеты на MicroPython?
Обычный pip и PyPI не работают. Библиотеки ставятся через mip — он тянет только чистый Python, — а самые нужные модули вмораживаются в прошивку при её сборке. Код с C-расширениями не запустится вовсе.
Сколько памяти у MicroPython-устройства?
Порядка сотен килобайт RAM и мегабайты флеша: например, у Raspberry Pi Pico 264 килобайта RAM. Поэтому компактный стиль — кортежи, bytes, генераторы — не прихоть, а условие работы: большой список поднимает MemoryError.
Понравился урок? Сошлитесь на него
«Логика на MicroPython — обычный Python: каркас циклов и словарей переносится на десктоп без правок.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Компиляция · Урок 16
Реализации Python: CPython и альтернативные среды
Python — это язык, а CPython — его главная реализация. Разбираем, кто ещё исполняет Python-код, как узнать свою среду через sys.implementation и что гарантировано любому коду на любой реализации.
Компиляция · Урок 17
PyPy: JIT-компилятор Python и когда он выигрывает
Тот же язык, другой движок: PyPy компилирует горячие участки прямо во время работы. Разбираем разогрев, ускорение в разы, совместимость с C-расширениями и случаи, когда CPython остаётся правильным выбором.
Компиляция · Урок 19
Jython, IronPython, RustPython и Brython: Python на чужих платформах
Четыре реализации для четырёх сред: Python на JVM, на .NET, на Rust и прямо в браузере. Зачем их переписывали, что они умеют сегодня и чем Brython отличается от Pyodide из песочницы.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.