Python и Arduino: практическая интеграция для микроконтроллеров

Раздел: Аппаратное обеспечение -> Микроконтроллеры

Основные подходы к использованию Python с Arduino

Наиболее эффективным способом взаимодействия Python с Arduino является применение протокола Firmata в связке с библиотекой pyFirmata. Этот метод позволяет управлять выводами микроконтроллера напрямую из скрипта Python, отправляя команды по последовательному порту. Arduino выступает в роли исполнительного устройства, а вся логика реализуется на стороне компьютера.

Установка и подготовка

Первым шагом является установка библиотеки pyFirmata через pip:

pip install pyfirmata

Arduino ide python (arduino ide для python)

Далее необходимо загрузить стандартный скетч Firmata в Arduino. Для этого в Arduino IDE откройте Файл → Примеры → Firmata → StandardFirmata и прошейте плату.

Пример управления светодиодом (включение и выключение)


import pyfirmata
import time

board = pyfirmata.Arduino('COM3')  # замените на ваш порт
pin = board.get_pin('d:13:o')      # цифровой пин 13 как выход

while True:
    pin.write(1)
    time.sleep(1)
    pin.write(0)
    time.sleep(1)

Результат: светодиод на плате Arduino начнёт мигать с интервалом в 1 секунду.

Типичная ошибка: не указан правильный порт. Убедитесь, что порт соответствует тому, который отображается в Arduino IDE (Сервис → Порт). В Windows это обычно COM3, в Linux – /dev/ttyACM0 или /dev/ttyUSB0.

Проблема: Firmata не прошит. Загрузите скетч StandardFirmata до запуска Python-скрипта.

Чтение аналогового датчика (потенциометр)


import pyfirmata
import time

board = pyfirmata.Arduino('COM3')
it = pyfirmata.util.Iterator(board)
it.start()

pin = board.get_pin('a:0:i')  # аналоговый пин 0 как вход

while True:
    value = pin.read()
    if value is not None:
        print(f"Напряжение: {value * 5:.2f} В")
    time.sleep(0.1)

Результат: в консоль выводятся значения напряжения от 0 до 5 В в зависимости от положения потенциометра.

Как управлять Arduino без прошивки Firmata, используя только Python?

Можно напрямую работать через последовательный порт с помощью библиотеки pyserial. При этом на Arduino загружается пользовательский скетч, который ожидает команды через Serial. Этот вариант подходит, когда нужна полная кастомизация протокола или ограниченная память платы.

Пример: включение светодиода по команде '1'

Скетч Arduino:


void setup() {
  Serial.begin(9600);
  pinMode(13, OUTPUT);
}

void loop() {
  if (Serial.available()) {
    char cmd = Serial.read();
    if (cmd == '1') digitalWrite(13, HIGH);
    else if (cmd == '0') digitalWrite(13, LOW);
  }
}

Python-скрипт:


import serial
import time

ser = serial.Serial('COM3', 9600, timeout=1)
time.sleep(2)  # ожидание инициализации Arduino

ser.write(b'1')
time.sleep(1)
ser.write(b'0')
ser.close()

Результат: светодиод загорается и гаснет через 1 секунду.

Ошибка: неправильная скорость (baudrate) – должна совпадать в скетче и в Python. Также возможна потеря первого символа из-за сброса Arduino при открытии порта – добавьте time.sleep(2) перед отправкой.

Как писать программы для Arduino на самом Python, используя MicroPython?

MicroPython – это реализация Python 3 для микроконтроллеров. Он работает на платах ESP32, ESP8266, Pyboard и некоторых других. Arduino с чипом AVR (Uno, Mega) не поддерживает MicroPython, но для ESP32 можно использовать среду Thonny или uPyCraft.

Пример мигания светодиодом на ESP32


import machine
import time

led = machine.Pin(2, machine.Pin.OUT)

while True:
    led.value(1)
    time.sleep(1)
    led.value(0)
    time.sleep(1)

Результат: встроенный светодиод ESP32 мигает. Этот код загружается напрямую во флеш-память платы.

Проблема: не все библиотеки Arduino (например, Servo, Wire) доступны в MicroPython. Для некоторых датчиков требуются альтернативные модули.

Как использовать Python для генерации скетчей Arduino на C++ и их компиляции?

Можно написать Python-скрипт, который создаёт .ino файл на основе шаблона и параметров, а затем компилирует его через Arduino CLI. Это полезно для автоматизации тестирования или генерации кода из пользовательского интерфейса.

Пример генерации скетча с заданной частотой мигания


import subprocess
import os

sketch = '''
void setup() {
  pinMode(13, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  digitalWrite(13, HIGH);
  delay({delay_time});
  digitalWrite(13, LOW);
  delay({delay_time});
}
'''

delay = 500  # мс
sketch_code = sketch.replace('{delay_time}', str(delay))

with open('blink/blink.ino', 'w') as f:
    f.write(sketch_code)

# Компиляция через Arduino CLI
subprocess.run(['arduino-cli', 'compile', '--fqbn', 'arduino:avr:uno', 'blink'])

Результат: создаётся и компилируется скетч с длительностью мигания 500 мс.

Ошибка: отсутствие Arduino CLI в PATH или неправильно указан FQBN. Установите Arduino CLI и настройте пути.

Расширенные примеры взаимодействия Python с Arduino

Пример 1: Управление сервоприводом через pyFirmata

При использовании библиотеки pyFirmata сервопривод подключается к цифровому пину с поддержкой ШИМ. Следующий код устанавливает угол поворота от 0 до 180 градусов.

Пример

import pyfirmata
import time

board = pyfirmata.Arduino('COM3')
servo = board.get_pin('d:9:s')  # сервопином на 9 пине

for angle in range(0, 181, 10):
    servo.write(angle)
    print(f"Угол: {angle}°")
    time.sleep(0.5)
Угол: 0°
Угол: 10°
...
Угол: 180°

Сервопривод плавно поворачивается на каждый заданный угол.

Пример 2: Чтение данных с датчика расстояния HC-SR04 и вывод в реальном времени

На Arduino загружается скетч, который измеряет расстояние и отправляет его по Serial. Python считывает данные и выводит в консоль.

Скетч Arduino:

Пример

#define TRIG_PIN 9
#define ECHO_PIN 10

void setup() {
  Serial.begin(9600);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
}

void loop() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  long duration = pulseIn(ECHO_PIN, HIGH);
  int distance = duration * 0.034 / 2;
  Serial.println(distance);
  delay(100);
}

Python-скрипт:

Пример

import serial
import time

ser = serial.Serial('COM3', 9600, timeout=1)
time.sleep(2)

while True:
    line = ser.readline().decode().strip()
    if line:
        try:
            dist = int(line)
            print(f"Расстояние: {dist} см")
        except:
            pass
Расстояние: 45 см
Расстояние: 44 см
Расстояние: 45 см

Пример 3: Управление шаговым двигателем 28BYJ-48 через pyserial и собственный протокол

На Arduino реализуется конечный автомат для управления шаговым двигателем. Python отправляет команды: 'F' – вперёд, 'B' – назад, 'S' – стоп.

Скетч Arduino (фрагмент):

Пример

#include 

const int stepsPerRev = 2048;
Stepper myStepper(stepsPerRev, 8, 9, 10, 11);

void setup() {
  Serial.begin(9600);
  myStepper.setSpeed(10);
}

void loop() {
  if (Serial.available()) {
    char cmd = Serial.read();
    if (cmd == 'F') myStepper.step(200);
    else if (cmd == 'B') myStepper.step(-200);
    else if (cmd == 'S') { /* остановка */ }
  }
}

Python-скрипт:

Пример

import serial
import time

ser = serial.Serial('COM3', 9600, timeout=1)
time.sleep(2)

while True:
    command = input("Введите команду (F/B/S): ").upper()
    if command in ['F', 'B', 'S']:
        ser.write(command.encode())
        time.sleep(0.5)

При вводе 'F' двигатель делает 200 шагов вперёд, 'B' – назад.

Пример 4: Построение графика данных с акселерометра MPU6050 (Python + Matplotlib)

Arduino читает MPU6050 через I2C и передаёт значения x, y, z по Serial. Python принимает и строит график в реальном времени с помощью matplotlib.

Скетч Arduino (упрощённо):

Пример

#include 
#include 

MPU6050 mpu;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  mpu.initialize();
}

void loop() {
  int16_t ax, ay, az;
  mpu.getMotion6(&ax, &ay, &az, &gyroX, &gyroY, &gyroZ);
  Serial.print(ax); Serial.print(",");
  Serial.print(ay); Serial.print(",");
  Serial.println(az);
  delay(10);
}

Python-скрипт:

Пример

import serial
import matplotlib.pyplot as plt
from collections import deque
import numpy as np

ser = serial.Serial('COM3', 115200, timeout=1)
plt.ion()
fig, ax = plt.subplots()
x_data = deque(maxlen=100)
y_data = deque(maxlen=100)
z_data = deque(maxlen=100)
line_x, = ax.plot(x_data, label='X')
line_y, = ax.plot(y_data, label='Y')
line_z, = ax.plot(z_data, label='Z')
ax.legend()

while True:
    try:
        line = ser.readline().decode().strip()
        if line:
            vals = list(map(int, line.split(',')))
            x_data.append(vals[0])
            y_data.append(vals[1])
            z_data.append(vals[2])
            line_x.set_ydata(x_data)
            line_y.set_ydata(y_data)
            line_z.set_ydata(z_data)
            ax.relim()
            ax.autoscale_view()
            plt.pause(0.01)
    except:
        pass

Результат: интерактивный график трёх осей акселерометра, обновляющийся при каждом измерении.

Arduino IDE для Python - comments

En
Arduino ide python (python)