Electronics
⚡ МОДУЛЬ 5: “ESP32 И ЭЛЕКТРОНИКА” (8 часов)
“От железа к интеллекту: программируем мозг дрона”
🧠 ФИЛОСОФИЯ ЦИФРОВОГО УПРАВЛЕНИЯ
Переход от механики к цифре:
1🔄 ЭВОЛЮЦИЯ ПОНИМАНИЯ СИСТЕМЫ:
2
3УРОВЕНЬ "МЕХАНИК" (Модуль 4):
4- Дрон как механическая система
5- Понимание физических принципов
6- Настройка готовых компонентов
7- Диагностика "железных" проблем
8
9УРОВЕНЬ "ПРОГРАММИСТ" (Модуль 5):
10- Дрон как программируемая система
11- Контроль каждого алгоритма
12- Создание собственной логики
13- Диагностика программных ошибок
14
15УРОВЕНЬ "АРХИТЕКТОР" (Модуль 6):
16- Дрон как интеллектуальная система
17- Проектирование поведения
18- Интеграция множественных датчиков
19- Создание автономного интеллекта
ESP32: почему именно этот микроконтроллер?
1🎯 ПРЕИМУЩЕСТВА ESP32 ДЛЯ ДРОНОВ:
2
3ВЫЧИСЛИТЕЛЬНАЯ МОЩНОСТЬ:
4- Dual-core 240MHz процессор
5- 520KB RAM + 4MB Flash
6- Поддержка floating-point операций
7- Достаточно для real-time управления
8
9ВСТРОЕННАЯ СВЯЗЬ:
10- WiFi 802.11 b/g/n
11- Bluetooth Classic + BLE
12- Возможность создания mesh сетей
13- OTA (Over-The-Air) обновления
14
15БОГАТАЯ ПЕРИФЕРИЯ:
16- 18 каналов ADC (аналого-цифровое преобразование)
17- 2 канала DAC (цифро-аналоговое преобразование)
18- PWM на любом пине
19- SPI, I2C, UART интерфейсы
20- Touch sensors, Hall sensor
21
22ЭКОСИСТЕМА РАЗРАБОТКИ:
23- Arduino IDE совместимость
24- ESP-IDF для профессиональной разработки
25- PlatformIO для продвинутых проектов
26- Огромное сообщество разработчиков
27
28ЭКОНОМИЧНОСТЬ:
29- Цена $3-10 за чип
30- Низкое энергопотребление
31- Встроенный WiFi = экономия на отдельных модулях
32- Open Source экосистема
🔌 УРОК 1: ОСНОВЫ ЭЛЕКТРОНИКИ ДЛЯ ДРОНОВ (2 часа)
1.1 Электричество: от теории к практике
ПРАКТИЧЕСКИЙ КУРС “ЭЛЕКТРИЧЕСТВО БЕЗ ФОРМУЛ”:
1⚡ БАЗОВЫЕ ПОНЯТИЯ ЧЕРЕЗ АНАЛОГИИ:
2
3НАПРЯЖЕНИЕ (Voltage) = ДАВЛЕНИЕ ВОДЫ:
4Представь водопровод:
5- Высокое давление → быстрый поток
6- Низкое давление → медленный поток
7- 12V батарея = "высокое давление" для электронов
8- 3.3V логика = "низкое давление" для микросхем
9
10Практический эксперимент:
111. Измерить напряжение батареи мультиметром
122. Подключить светодиод к 12V → горит ярко
133. Подключить тот же LED к 3.3V → горит тускло
144. Вывод: напряжение определяет "силу" воздействия
15
16ТОК (Current) = КОЛИЧЕСТВО ВОДЫ:
17Аналогия с рекой:
18- Широкая река = большой ток
19- Ручеек = маленький ток
20- Мотор дрона потребляет 20A = "широкая река"
21- LED потребляет 20mA = "тонкий ручеек"
22
23Практическое измерение:
241. Подключить амперметр последовательно с нагрузкой
252. Измерить ток потребления мотора на холостом ходу
263. Дать газу → ток увеличился в разы
274. Вывод: ток зависит от нагрузки
28
29СОПРОТИВЛЕНИЕ (Resistance) = ПРЕПЯТСТВИЕ:
30Как камни в реке замедляют поток:
31- Резистор = "камень" для электронов
32- Большое сопротивление = маленький ток
33- Маленькое сопротивление = большой ток
34
35Эксперимент с резисторами:
361. LED + резистор 1кОм → тускло светится
372. LED + резистор 100Ом → ярко светится
383. LED без резистора → сгорает!
394. Вывод: резисторы ограничивают ток
ЗАКОН ОМА В ДЕЙСТВИИ:
1🔍 ПРАКТИЧЕСКОЕ ПРИМЕНЕНИЕ U = I × R:
2
3ЗАДАЧА 1: Подобрать резистор для LED
4Дано:
5- Напряжение питания: 5V
6- LED падение напряжения: 2V
7- Нужный ток через LED: 20mA
8
9Решение без формул:
101. На резисторе должно "потеряться": 5V - 2V = 3V
112. Через резистор должно пройти: 20mA
123. По таблице или калькулятору: R = 3V / 0.02A = 150 Ом
134. Выбираем ближайший стандартный: 150 Ом
14
15ЗАДАЧА 2: Рассчитать потребление мотора
16Дано:
17- Напряжение батареи: 11.1V (3S LiPo)
18- Сопротивление мотора: 0.1 Ом
19- Ток заторможенного ротора: I = U/R = 11.1/0.1 = 111A!
20
21Вывод: Никогда не блокировать вращение мотора!
22
23ЗАДАЧА 3: Выбрать сечение проводов
24- Ток потребления: 60A
25- Допустимая плотность тока: 5A/мм²
26- Нужное сечение: 60A / 5A/мм² = 12 мм²
27- Диаметр провода: ~4мм
28
29Практический выбор: провод 10 AWG (5.26 мм²) с запасом
1.2 Компоненты электронной системы дрона
АНАТОМИЯ ЭЛЕКТРОНИКИ ДРОНА:
1🔧 ОСНОВНЫЕ КОМПОНЕНТЫ:
2
31. ИСТОЧНИКИ ПИТАНИЯ:
4LiPo батарея (11.1V - 22.2V):
5- Основное питание моторов
6- Высокий ток разряда (50C+)
7- Нестабильное напряжение (зависит от заряда)
8
9BEC (Battery Eliminator Circuit):
10- Преобразование 12V → 5V для сервоприводов
11- Стабилизированное напряжение
12- Обычно встроен в ESC
13
14LDO стабилизатор (5V → 3.3V):
15- Питание микроконтроллеров
16- Низкий ток, высокая стабильность
17- Встроен в большинство плат
18
192. СИЛОВАЯ ЭЛЕКТРОНИКА:
20ESC (Electronic Speed Controller):
21- Преобразование DC → 3-phase AC для моторов
22- PWM управление скоростью
23- Встроенная защита от перегрузки
24
25Power Distribution Board (PDB):
26- Распределение питания на 4 ESC
27- Встроенные фильтры помех
28- Места для дополнительных модулей
29
303. УПРАВЛЯЮЩАЯ ЭЛЕКТРОНИКА:
31Flight Controller:
32- Основной "мозг" дрона
33- Обработка данных датчиков
34- Генерация управляющих сигналов
35
36Радиоприемник:
37- Прием команд с пульта
38- Декодирование PPM/SBUS сигналов
39- Failsafe при потере связи
40
414. ДАТЧИКИ:
42IMU (Inertial Measurement Unit):
43- Гироскопы + акселерометры
44- Определение ориентации в пространстве
45- Частота обновления 1000+ Гц
46
47Barometer:
48- Измерение атмосферного давления
49- Определение высоты
50- Стабилизация по высоте
51
52GPS:
53- Позиционирование
54- Навигация
55- Return-to-Home функция
ПРАКТИЧЕСКАЯ СХЕМОТЕХНИКА:
1📐 СХЕМЫ ПОДКЛЮЧЕНИЯ:
2
3СХЕМА ПИТАНИЯ:
LiPo 3S (11.1V)
│
├── PDB ──┬── ESC1 ── Motor1
│ ├── ESC2 ── Motor2
│ ├── ESC3 ── Motor3
│ └── ESC4 ── Motor4
│
├── BEC (5V) ──┬── Servo1
│ ├── Servo2
│ └── Receiver Power
│
└── LDO (3.3V) ──┬── Flight Controller
├── GPS Module
└── Sensors
1
2СХЕМА УПРАВЛЕНИЯ:
Transmitter ~~~ Receiver ──── Flight Controller ────┬── ESC1
│ ├── ESC2
│ ├── ESC3
┌─────────────┼──────────────└── ESC4
│ │
┌── IMU ┌── GPS
├── Baro ├── Compass
├── Sonar └── Optical Flow
└── Cameras
1
2ЗАЗЕМЛЕНИЕ И ЭКРАНИРОВАНИЕ:
3- Общий "земляной" провод для всех компонентов
4- Экранирование силовых проводов от сигнальных
5- Развязка аналоговой и цифровой "земли"
6- Ферритовые кольца на длинных проводах
💻 УРОК 2: ПРОГРАММИРОВАНИЕ ESP32 (3 часа)
2.1 Настройка среды разработки
STEP-BY-STEP SETUP:
1🛠️ УСТАНОВКА ARDUINO IDE + ESP32:
2
3ШАГ 1: Установка Arduino IDE
41. Скачать с official site: arduino.cc
52. Установить стандартным способом
63. Запустить и проверить работу
7
8ШАГ 2: Добавление ESP32 Support
91. File → Preferences
102. В "Additional Boards Manager URLs" добавить:
11 https://dl.espressif.com/dl/package_esp32_index.json
123. Tools → Board → Boards Manager
134. Найти "esp32" и установить
14
15ШАГ 3: Выбор платы
161. Tools → Board → ESP32 Arduino
172. Выбрать "ESP32 Dev Module"
183. Настроить параметры:
19 - Flash Mode: QIO
20 - Flash Size: 4MB
21 - Upload Speed: 921600
22
23ШАГ 4: Тест подключения
24```cpp
25void setup() {
26 Serial.begin(115200);
27 Serial.println("ESP32 Test Start!");
28}
29
30void loop() {
31 Serial.println("Hello from ESP32!");
32 delay(1000);
33}
Загрузить код и проверить вывод в Serial Monitor
1
2**АЛЬТЕРНАТИВНЫЕ СРЕДЫ РАЗРАБОТКИ:**
🚀 ПРОДВИНУТЫЕ ИНСТРУМЕНТЫ:
PLATFORMIO (рекомендуется для серьезной разработки): Преимущества:
- Встроенный менеджер библиотек
- Поддержка множества плат
- Интеграция с VS Code
- Профессиональный debugger
Установка:
- Установить VS Code
- Установить расширение PlatformIO
- Создать новый проект для ESP32
- Автоматическая установка toolchain
ESP-IDF (для профессиональной разработки):
- Native ESP32 framework от Espressif
- Полный доступ к всем возможностям
- Real-time операционная система (FreeRTOS)
- Профессиональные инструменты отладки
MICROPYTHON (для быстрого прототипирования):
- Интерпретируемый Python на ESP32
- Интерактивная разработка через REPL
- Быстрое тестирование идей
- Ограниченная производительность
1
2### **2.2 Основы программирования ESP32**
3
4**СТРУКТУРА ПРОГРАММЫ:**
5```cpp
6// =====================================
7// БАЗОВАЯ СТРУКТУРА ESP32 ПРОГРАММЫ
8// =====================================
9
10// 1. ПОДКЛЮЧЕНИЕ БИБЛИОТЕК
11#include <WiFi.h> // WiFi функции
12#include <Wire.h> // I2C протокол
13#include <SPI.h> // SPI протокол
14
15// 2. ОПРЕДЕЛЕНИЕ КОНСТАНТ
16#define LED_PIN 2 // Встроенный LED
17#define MOTOR_PIN 18 // PWM для мотора
18#define SENSOR_PIN 34 // Аналоговый вход
19
20// 3. ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ
21int sensorValue = 0;
22float motorSpeed = 0.0;
23bool systemArmed = false;
24
25// 4. ФУНКЦИЯ ИНИЦИАЛИЗАЦИИ (выполняется один раз)
26void setup() {
27 // Инициализация Serial для отладки
28 Serial.begin(115200);
29 Serial.println("=== ESP32 DRONE CONTROLLER ===");
30
31 // Настройка пинов
32 pinMode(LED_PIN, OUTPUT);
33 pinMode(MOTOR_PIN, OUTPUT);
34 pinMode(SENSOR_PIN, INPUT);
35
36 // Инициализация PWM для моторов
37 ledcSetup(0, 50, 16); // Канал 0, 50Hz, 16-bit разрешение
38 ledcAttachPin(MOTOR_PIN, 0);
39
40 // Инициализация других систем
41 initWiFi();
42 initSensors();
43
44 Serial.println("Setup complete!");
45}
46
47// 5. ГЛАВНЫЙ ЦИКЛ (выполняется бесконечно)
48void loop() {
49 // Чтение датчиков
50 readSensors();
51
52 // Обработка команд
53 processCommands();
54
55 // Управление моторами
56 controlMotors();
57
58 // Отправка телеметрии
59 sendTelemetry();
60
61 // Небольшая задержка для стабильности
62 delay(20); // 50Hz основной цикл
63}
64
65// =====================================
66// ПОЛЬЗОВАТЕЛЬСКИЕ ФУНКЦИИ
67// =====================================
68
69void initWiFi() {
70 WiFi.begin("YourWiFi", "YourPassword");
71 while (WiFi.status() != WL_CONNECTED) {
72 delay(1000);
73 Serial.println("Connecting to WiFi...");
74 }
75 Serial.println("WiFi Connected!");
76}
77
78void initSensors() {
79 Wire.begin(); // Инициализация I2C
80 // Здесь инициализация IMU, барометра и т.д.
81}
82
83void readSensors() {
84 sensorValue = analogRead(SENSOR_PIN);
85 // Чтение других датчиков
86}
87
88void processCommands() {
89 // Обработка команд с пульта или WiFi
90}
91
92void controlMotors() {
93 if (systemArmed) {
94 // Преобразование команд в PWM сигналы
95 int pwmValue = map(motorSpeed, 0, 100, 1000, 2000);
96 ledcWrite(0, pwmValue);
97 } else {
98 ledcWrite(0, 1000); // Моторы остановлены
99 }
100}
101
102void sendTelemetry() {
103 // Отправка данных через WiFi или Serial
104 Serial.print("Sensor: ");
105 Serial.print(sensorValue);
106 Serial.print(" Motor: ");
107 Serial.println(motorSpeed);
108}
РАБОТА С ПОРТАМИ ВВОДА-ВЫВОДА:
1// =====================================
2// GPIO (GENERAL PURPOSE INPUT/OUTPUT)
3// =====================================
4
5// ЦИФРОВЫЕ ВЫХОДЫ (для LED, реле, и т.д.)
6void setupDigitalOutputs() {
7 pinMode(LED_PIN, OUTPUT);
8
9 digitalWrite(LED_PIN, HIGH); // Включить LED
10 delay(1000);
11 digitalWrite(LED_PIN, LOW); // Выключить LED
12}
13
14// ЦИФРОВЫЕ ВХОДЫ (для кнопок, концевиков)
15void setupDigitalInputs() {
16 pinMode(BUTTON_PIN, INPUT_PULLUP); // Встроенный pull-up резистор
17
18 if (digitalRead(BUTTON_PIN) == LOW) {
19 Serial.println("Button pressed!");
20 }
21}
22
23// АНАЛОГОВЫЕ ВХОДЫ (для датчиков, потенциометров)
24void setupAnalogInputs() {
25 // ESP32 имеет 12-bit ADC (0-4095)
26 int rawValue = analogRead(SENSOR_PIN);
27
28 // Преобразование в напряжение (0-3.3V)
29 float voltage = rawValue * (3.3 / 4095.0);
30
31 // Преобразование в физическую величину
32 float temperature = (voltage - 0.5) * 100; // Для TMP36
33
34 Serial.print("Raw: "); Serial.print(rawValue);
35 Serial.print(" Voltage: "); Serial.print(voltage);
36 Serial.print(" Temp: "); Serial.println(temperature);
37}
38
39// PWM ВЫХОДЫ (для моторов, сервоприводов)
40void setupPWMOutputs() {
41 // Настройка PWM канала
42 ledcSetup(0, 50, 16); // Канал 0, 50Hz, 16-bit
43 ledcAttachPin(MOTOR_PIN, 0); // Привязать пин к каналу
44
45 // Генерация PWM сигнала
46 // Для ESC: 1000-2000 микросекунд (1ms-2ms)
47 // При 50Hz и 16-bit: 1ms = 3277, 2ms = 6554
48
49 ledcWrite(0, 3277); // Минимальный газ
50 delay(1000);
51 ledcWrite(0, 4915); // Средний газ (1.5ms)
52 delay(1000);
53 ledcWrite(0, 6554); // Максимальный газ
54}
2.3 Протоколы связи
I2C ДЛЯ ДАТЧИКОВ:
1// =====================================
2// I2C ПРОТОКОЛ (для IMU, барометра, компаса)
3// =====================================
4
5#include <Wire.h>
6
7// Пример работы с MPU6050 (гироскоп + акселерометр)
8#define MPU6050_ADDR 0x68
9
10void setupIMU() {
11 Wire.begin();
12 Wire.beginTransmission(MPU6050_ADDR);
13 Wire.write(0x6B); // PWR_MGMT_1 register
14 Wire.write(0); // Включить датчик
15 Wire.endTransmission(true);
16
17 Serial.println("MPU6050 initialized");
18}
19
20struct IMUData {
21 float gyroX, gyroY, gyroZ;
22 float accelX, accelY, accelZ;
23};
24
25IMUData readIMU() {
26 IMUData data;
27
28 // Запрос данных
29 Wire.beginTransmission(MPU6050_ADDR);
30 Wire.write(0x3B); // Начальный регистр данных
31 Wire.endTransmission(false);
32 Wire.requestFrom(MPU6050_ADDR, 14, true);
33
34 // Чтение сырых данных (16-bit значения)
35 int16_t rawAccelX = Wire.read() << 8 | Wire.read();
36 int16_t rawAccelY = Wire.read() << 8 | Wire.read();
37 int16_t rawAccelZ = Wire.read() << 8 | Wire.read();
38 int16_t rawTemp = Wire.read() << 8 | Wire.read(); // Температура
39 int16_t rawGyroX = Wire.read() << 8 | Wire.read();
40 int16_t rawGyroY = Wire.read() << 8 | Wire.read();
41 int16_t rawGyroZ = Wire.read() << 8 | Wire.read();
42
43 // Преобразование в физические единицы
44 data.accelX = rawAccelX / 16384.0; // ±2g range
45 data.accelY = rawAccelY / 16384.0;
46 data.accelZ = rawAccelZ / 16384.0;
47
48 data.gyroX = rawGyroX / 131.0; // ±250°/s range
49 data.gyroY = rawGyroY / 131.0;
50 data.gyroZ = rawGyroZ / 131.0;
51
52 return data;
53}
SPI ДЛЯ ВЫСОКОСКОРОСТНЫХ ДАТЧИКОВ:
1// =====================================
2// SPI ПРОТОКОЛ (для быстрых IMU, SD карт)
3// =====================================
4
5#include <SPI.h>
6
7#define CS_PIN 5 // Chip Select
8#define SCLK_PIN 18 // Serial Clock
9#define MISO_PIN 19 // Master In Slave Out
10#define MOSI_PIN 23 // Master Out Slave In
11
12void setupSPI() {
13 SPI.begin(SCLK_PIN, MISO_PIN, MOSI_PIN, CS_PIN);
14 pinMode(CS_PIN, OUTPUT);
15 digitalWrite(CS_PIN, HIGH); // Неактивное состояние
16
17 Serial.println("SPI initialized");
18}
19
20// Пример чтения регистра через SPI
21uint8_t readSPIRegister(uint8_t address) {
22 digitalWrite(CS_PIN, LOW); // Активировать устройство
23
24 SPI.transfer(address | 0x80); // Команда чтения (bit 7 = 1)
25 uint8_t data = SPI.transfer(0x00); // Читаем данные
26
27 digitalWrite(CS_PIN, HIGH); // Деактивировать
28
29 return data;
30}
31
32// Пример записи в регистр через SPI
33void writeSPIRegister(uint8_t address, uint8_t data) {
34 digitalWrite(CS_PIN, LOW);
35
36 SPI.transfer(address & 0x7F); // Команда записи (bit 7 = 0)
37 SPI.transfer(data);
38
39 digitalWrite(CS_PIN, HIGH);
40}
UART ДЛЯ GPS И ТЕЛЕМЕТРИИ:
1// =====================================
2// UART ПРОТОКОЛ (для GPS, радио модулей)
3// =====================================
4
5// ESP32 имеет 3 UART порта
6HardwareSerial SerialGPS(1); // UART1 для GPS
7HardwareSerial SerialRadio(2); // UART2 для радио
8
9void setupUART() {
10 // GPS обычно работает на 9600 baud
11 SerialGPS.begin(9600, SERIAL_8N1, 16, 17); // RX=16, TX=17
12
13 // Радио модуль на высокой скорости
14 SerialRadio.begin(115200, SERIAL_8N1, 14, 15); // RX=14, TX=15
15
16 Serial.println("UART initialized");
17}
18
19// Простой парсер NMEA для GPS
20void parseGPS() {
21 if (SerialGPS.available()) {
22 String nmeaString = SerialGPS.readStringUntil('\n');
23
24 if (nmeaString.startsWith("$GPGGA")) {
25 // Парсинг координат из GPGGA строки
26 // $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
27
28 int comma1 = nmeaString.indexOf(',', 7); // После времени
29 int comma2 = nmeaString.indexOf(',', comma1 + 1);
30 int comma3 = nmeaString.indexOf(',', comma2 + 1);
31 int comma4 = nmeaString.indexOf(',', comma3 + 1);
32 int comma5 = nmeaString.indexOf(',', comma4 + 1);
33
34 String latStr = nmeaString.substring(comma1 + 1, comma2);
35 String latDir = nmeaString.substring(comma2 + 1, comma3);
36 String lonStr = nmeaString.substring(comma3 + 1, comma4);
37 String lonDir = nmeaString.substring(comma4 + 1, comma5);
38
39 if (latStr.length() > 0 && lonStr.length() > 0) {
40 float latitude = parseCoordinate(latStr, latDir);
41 float longitude = parseCoordinate(lonStr, lonDir);
42
43 Serial.print("GPS: ");
44 Serial.print(latitude, 6);
45 Serial.print(", ");
46 Serial.println(longitude, 6);
47 }
48 }
49 }
50}
51
52float parseCoordinate(String coord, String direction) {
53 // Конвертация DDMM.MMMM в десятичные градусы
54 float degrees = coord.substring(0, 2).toFloat();
55 float minutes = coord.substring(2).toFloat();
56
57 float decimal = degrees + minutes / 60.0;
58
59 if (direction == "S" || direction == "W") {
60 decimal = -decimal;
61 }
62
63 return decimal;
64}
🎛️ УРОК 3: СОЗДАНИЕ СОБСТВЕННОГО АВТОПИЛОТА (3 часа)
3.1 Архитектура системы управления
КОНЦЕПТУАЛЬНАЯ СХЕМА:
1🏗️ СТРУКТУРА АВТОПИЛОТА:
2
3INPUT LAYER (Входные данные):
4├── Radio Receiver (команды пилота)
5├── IMU (ориентация в пространстве)
6├── GPS (позиция)
7├── Barometer (высота)
8├── Optical Flow (скорость относительно земли)
9└── Rangefinder (точная высота)
10
11PROCESSING LAYER (Обработка):
12├── Sensor Fusion (объединение данных датчиков)
13├── State Estimation (оценка состояния дрона)
14├── Control Algorithms (алгоритмы управления)
15├── Mission Planning (планирование полета)
16└── Safety Monitoring (контроль безопасности)
17
18OUTPUT LAYER (Выходные сигналы):
19├── Motor 1 PWM
20├── Motor 2 PWM
21├── Motor 3 PWM
22├── Motor 4 PWM
23├── Servo Outputs (для камеры, сброса груза)
24└── Status LEDs
25
26COMMUNICATION LAYER (Связь):
27├── Telemetry Radio (данные на землю)
28├── WiFi (настройка и отладка)
29└── Bluetooth (мобильные приложения)
БАЗОВАЯ РЕАЛИЗАЦИЯ:
1// =====================================
2// ПРОСТОЙ АВТОПИЛОТ НА ESP32
3// =====================================
4
5#include <Wire.h>
6#include <WiFi.h>
7
8// ===== СТРУКТУРЫ ДАННЫХ =====
9struct Vector3 {
10 float x, y, z;
11};
12
13struct Attitude {
14 float roll, pitch, yaw; // Углы в градусах
15};
16
17struct Position {
18 float latitude, longitude, altitude;
19};
20
21struct ControlInputs {
22 float throttle; // 0.0 - 1.0
23 float roll; // -1.0 - 1.0
24 float pitch; // -1.0 - 1.0
25 float yaw; // -1.0 - 1.0
26};
27
28struct MotorOutputs {
29 float motor1, motor2, motor3, motor4; // 0.0 - 1.0
30};
31
32// ===== ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ =====
33Vector3 gyro, accel, mag;
34Attitude attitude;
35Position position;
36ControlInputs controls;
37MotorOutputs motors;
38
39// Настройки PID регуляторов
40float rollKp = 1.0, rollKi = 0.1, rollKd = 0.05;
41float pitchKp = 1.0, pitchKi = 0.1, pitchKd = 0.05;
42float yawKp = 1.0, yawKi = 0.1, yawKd = 0.05;
43
44// Переменные для PID
45float rollError, rollErrorPrev, rollErrorSum;
46float pitchError, pitchErrorPrev, pitchErrorSum;
47float yawError, yawErrorPrev, yawErrorSum;
48
49unsigned long lastTime = 0;
50
51// ===== ОСНОВНОЙ КОД =====
52void setup() {
53 Serial.begin(115200);
54 Serial.println("=== ESP32 AUTOPILOT v1.0 ===");
55
56 initHardware();
57 initSensors();
58 initMotors();
59
60 Serial.println("Autopilot ready!");
61}
62
63void loop() {
64 unsigned long currentTime = millis();
65 float dt = (currentTime - lastTime) / 1000.0; // Время в секундах
66 lastTime = currentTime;
67
68 // 1. Чтение датчиков
69 readSensors();
70
71 // 2. Оценка состояния
72 updateAttitude(dt);
73
74 // 3. Чтение команд пилота
75 readControlInputs();
76
77 // 4. Алгоритмы управления
78 calculatePIDControl(dt);
79
80 // 5. Управление моторами
81 updateMotors();
82
83 // 6. Отправка телеметрии
84 sendTelemetry();
85
86 delay(20); // 50Hz основной цикл
87}
3.2 Алгоритмы стабилизации
PID КОНТРОЛЛЕР:
1// =====================================
2// PID РЕГУЛЯТОР ДЛЯ СТАБИЛИЗАЦИИ
3// =====================================
4
5void calculatePIDControl(float dt) {
6 // Желаемые углы на основе команд пилота
7 float desiredRoll = controls.roll * 30.0; // Максимум ±30°
8 float desiredPitch = controls.pitch * 30.0;
9 float desiredYawRate = controls.yaw * 180.0; // Максимум ±180°/с
10
11 // === ROLL PID ===
12 rollError = desiredRoll - attitude.roll;
13 rollErrorSum += rollError * dt;
14 rollErrorSum = constrain(rollErrorSum, -10, 10); // Anti-windup
15
16 float rollDerivative = (rollError - rollErrorPrev) / dt;
17 rollErrorPrev = rollError;
18
19 float rollOutput = rollKp * rollError +
20 rollKi * rollErrorSum +
21 rollKd * rollDerivative;
22
23 // === PITCH PID ===
24 pitchError = desiredPitch - attitude.pitch;
25 pitchErrorSum += pitchError * dt;
26 pitchErrorSum = constrain(pitchErrorSum, -10, 10);
27
28 float pitchDerivative = (pitchError - pitchErrorPrev) / dt;
29 pitchErrorPrev = pitchError;
30
31 float pitchOutput = pitchKp * pitchError +
32 pitchKi * pitchErrorSum +
33 pitchKd * pitchDerivative;
34
35 // === YAW PID (на угловой скорости) ===
36 yawError = desiredYawRate - gyro.z;
37 yawErrorSum += yawError * dt;
38 yawErrorSum = constrain(yawErrorSum, -10, 10);
39
40 float yawDerivative = (yawError - yawErrorPrev) / dt;
41 yawErrorPrev = yawError;
42
43 float yawOutput = yawKp * yawError +
44 yawKi * yawErrorSum +
45 yawKd * yawDerivative;
46
47 // === МИКШИРОВАНИЕ НА МОТОРЫ ===
48 // Квадрокоптер X конфигурация:
49 // Motor1 (передний правый): +pitch, -roll, -yaw
50 // Motor2 (задний правый): -pitch, -roll, +yaw
51 // Motor3 (задний левый): -pitch, +roll, -yaw
52 // Motor4 (передний левый): +pitch, +roll, +yaw
53
54 float throttle = controls.throttle;
55
56 motors.motor1 = throttle + pitchOutput - rollOutput - yawOutput;
57 motors.motor2 = throttle - pitchOutput - rollOutput + yawOutput;
58 motors.motor3 = throttle - pitchOutput + rollOutput - yawOutput;
59 motors.motor4 = throttle + pitchOutput + rollOutput + yawOutput;
60
61 // Ограничение выходов 0.0-1.0
62 motors.motor1 = constrain(motors.motor1, 0.0, 1.0);
63 motors.motor2 = constrain(motors.motor2, 0.0, 1.0);
64 motors.motor3 = constrain(motors.motor3, 0.0, 1.0);
65 motors.motor4 = constrain(motors.motor4, 0.0, 1.0);
66}
67
68// Функция ограничения значений
69float constrain(float value, float min_val, float max_val) {
70 if (value < min_val) return min_val;
71 if (value > max_val) return max_val;
72 return value;
73}
ОЦЕНКА ОРИЕНТАЦИИ:
1// =====================================
2// КОМПЛЕМЕНТАРНЫЙ ФИЛЬТР
3// =====================================
4
5void updateAttitude(float dt) {
6 // Интегрирование гироскопа (быстро, но дрейфует)
7 attitude.roll += gyro.x * dt;
8 attitude.pitch += gyro.y * dt;
9 attitude.yaw += gyro.z * dt;
10
11 // Расчет углов из акселерометра (медленно, но точно)
12 float accelRoll = atan2(accel.y, accel.z) * 180.0 / PI;
13 float accelPitch = atan2(-accel.x, sqrt(accel.y*accel.y + accel.z*accel.z)) * 180.0 / PI;
14
15 // Комплементарный фильтр (объединяем показания)
16 float alpha = 0.98; // Коэффициент доверия гироскопу
17
18 attitude.roll = alpha * attitude.roll + (1.0 - alpha) * accelRoll;
19 attitude.pitch = alpha * attitude.pitch + (1.0 - alpha) * accelPitch;
20
21 // Yaw можно корректировать по магнитометру
22 if (mag.x != 0 || mag.y != 0) {
23 float magYaw = atan2(mag.y, mag.x) * 180.0 / PI;
24 attitude.yaw = alpha * attitude.yaw + (1.0 - alpha) * magYaw;
25 }
26
27 // Ограничение углов в диапазоне ±180°
28 if (attitude.roll > 180) attitude.roll -= 360;
29 if (attitude.roll < -180) attitude.roll += 360;
30 if (attitude.pitch > 180) attitude.pitch -= 360;
31 if (attitude.pitch < -180) attitude.pitch += 360;
32 if (attitude.yaw > 180) attitude.yaw -= 360;
33 if (attitude.yaw < -180) attitude.yaw += 360;
34}
3.3 Режимы полета
РЕАЛИЗАЦИЯ РЕЖИМОВ:
1// =====================================
2// РЕЖИМЫ ПОЛЕТА
3// =====================================
4
5enum FlightMode {
6 MANUAL, // Ручное управление
7 STABILIZE, // Стабилизация углов
8 ALT_HOLD, // Удержание высоты
9 LOITER, // Зависание в точке
10 AUTO, // Автоматический полет
11 RTL // Возврат домой
12};
13
14FlightMode currentMode = STABILIZE;
15Position homePosition;
16bool isArmed = false;
17
18void processFlightMode() {
19 switch (currentMode) {
20 case MANUAL:
21 // Прямое управление моторами
22 manualMode();
23 break;
24
25 case STABILIZE:
26 // Стабилизация углов (уже реализована выше)
27 stabilizeMode();
28 break;
29
30 case ALT_HOLD:
31 // Стабилизация + удержание высоты
32 altHoldMode();
33 break;
34
35 case LOITER:
36 // Стабилизация + удержание позиции
37 loiterMode();
38 break;
39
40 case AUTO:
41 // Автоматический полет по waypoints
42 autoMode();
43 break;
44
45 case RTL:
46 // Возврат домой
47 returnToLaunchMode();
48 break;
49 }
50}
51
52void manualMode() {
53 // Прямое преобразование команд в PWM
54 motors.motor1 = controls.throttle;
55 motors.motor2 = controls.throttle;
56 motors.motor3 = controls.throttle;
57 motors.motor4 = controls.throttle;
58
59 // Добавляем управление по осям
60 motors.motor1 += controls.pitch - controls.roll - controls.yaw;
61 motors.motor2 += -controls.pitch - controls.roll + controls.yaw;
62 motors.motor3 += -controls.pitch + controls.roll - controls.yaw;
63 motors.motor4 += controls.pitch + controls.roll + controls.yaw;
64
65 // Ограничиваем
66 motors.motor1 = constrain(motors.motor1, 0.0, 1.0);
67 motors.motor2 = constrain(motors.motor2, 0.0, 1.0);
68 motors.motor3 = constrain(motors.motor3, 0.0, 1.0);
69 motors.motor4 = constrain(motors.motor4, 0.0, 1.0);
70}
71
72void stabilizeMode() {
73 // Уже реализована в calculatePIDControl()
74 calculatePIDControl(0.02); // 50Hz
75}
76
77void altHoldMode() {
78 // Сначала стабилизация углов
79 stabilizeMode();
80
81 // Затем контроль высоты
82 static float targetAltitude = position.altitude;
83 static bool altitudeSet = false;
84
85 // Установка целевой высоты при первом входе в режим
86 if (!altitudeSet) {
87 targetAltitude = position.altitude;
88 altitudeSet = true;
89 }
90
91 // Изменение целевой высоты стиком газа
92 if (abs(controls.throttle - 0.5) > 0.1) {
93 targetAltitude += (controls.throttle - 0.5) * 2.0; // 2 м/с максимум
94 altitudeSet = false;
95 }
96
97 // PID регулятор высоты
98 static float altError, altErrorPrev, altErrorSum;
99 float altKp = 0.5, altKi = 0.1, altKd = 0.2;
100
101 altError = targetAltitude - position.altitude;
102 altErrorSum += altError * 0.02;
103 altErrorSum = constrain(altErrorSum, -5, 5);
104
105 float altDerivative = (altError - altErrorPrev) / 0.02;
106 altErrorPrev = altError;
107
108 float altOutput = altKp * altError + altKi * altErrorSum + altKd * altDerivative;
109
110 // Модификация throttle для всех моторов
111 motors.motor1 += altOutput;
112 motors.motor2 += altOutput;
113 motors.motor3 += altOutput;
114 motors.motor4 += altOutput;
115
116 // Ограничение
117 motors.motor1 = constrain(motors.motor1, 0.0, 1.0);
118 motors.motor2 = constrain(motors.motor2, 0.0, 1.0);
119 motors.motor3 = constrain(motors.motor3, 0.0, 1.0);
120 motors.motor4 = constrain(motors.motor4, 0.0, 1.0);
121}
122
123void returnToLaunchMode() {
124 // Простая реализация RTL
125
126 // 1. Подняться на безопасную высоту
127 float safeAltitude = homePosition.altitude + 20.0; // +20 метров
128 if (position.altitude < safeAltitude) {
129 // Подъем
130 controls.throttle = 0.7;
131 stabilizeMode();
132 return;
133 }
134
135 // 2. Лететь к точке старта
136 float distanceToHome = sqrt(
137 pow(position.latitude - homePosition.latitude, 2) +
138 pow(position.longitude - homePosition.longitude, 2)
139 );
140
141 if (distanceToHome > 0.00001) { // ~1 метр точности GPS
142 // Вычисляем направление к дому
143 float bearingToHome = atan2(
144 homePosition.longitude - position.longitude,
145 homePosition.latitude - position.latitude
146 );
147
148 // Устанавливаем команды для полета домой
149 controls.pitch = cos(bearingToHome) * 0.3; // 30% максимального наклона
150 controls.roll = sin(bearingToHome) * 0.3;
151 controls.yaw = 0;
152 controls.throttle = 0.5; // Постоянная высота
153
154 stabilizeMode();
155 } else {
156 // 3. Посадка над домом
157 controls.throttle = 0.3; // Медленное снижение
158 controls.pitch = 0;
159 controls.roll = 0;
160 controls.yaw = 0;
161
162 stabilizeMode();
163
164 // Disarm при касании земли
165 if (position.altitude <= homePosition.altitude + 0.5) {
166 isArmed = false;
167 }
168 }
169}
🔧 ПРАКТИЧЕСКАЯ АТТЕСТАЦИЯ МОДУЛЯ
Комплексный экзамен “ESP32 разработчик”:
ТЕОРЕТИЧЕСКАЯ ЧАСТЬ (30% оценки):
1Блоки вопросов:
2
31. ОСНОВЫ ЭЛЕКТРОНИКИ (25% теории)
4 - Закон Ома и его применение
5 - Выбор компонентов по характеристикам
6 - Принципы построения схем питания
7 - Диагностика электронных проблем
8
92. ПРОГРАММИРОВАНИЕ ESP32 (40% теории)
10 - Структура программы и основные функции
11 - Работа с GPIO, PWM, ADC
12 - Протоколы связи I2C, SPI, UART
13 - Обработка прерываний и многозадачность
14
153. АЛГОРИТМЫ УПРАВЛЕНИЯ (35% теории)
16 - Принципы PID регулирования
17 - Sensor fusion и фильтрация
18 - Режимы полета и их реализация
19 - Системы безопасности
20
21Формат: Письменный тест + практическое программирование
22Время: 90 минут + 30 минут практика
23Проходной балл: 75%
ПРАКТИЧЕСКАЯ ЧАСТЬ (70% оценки):
Задание 1: “Система сбора данных” (35% практики)
1// ЗАДАЧА: Создать систему сбора и передачи данных датчиков
2
3/* ТРЕБОВАНИЯ:
41. Подключить IMU датчик по I2C
52. Подключить GPS по UART
63. Настроить WiFi для передачи данных
74. Создать web-интерфейс для просмотра данных в реальном времени
85. Логирование данных на SD карту
9
10КРИТЕРИИ ОЦЕНКИ:
11- Корректность подключения датчиков (25%)
12- Качество программного кода (30%)
13- Функциональность web-интерфейса (25%)
14- Стабильность работы системы (20%)
15*/
16
17#include <WiFi.h>
18#include <WebServer.h>
19#include <Wire.h>
20#include <SPI.h>
21#include <SD.h>
22
23// Ваш код здесь...
Задание 2: “Мини-автопилот” (35% практики)
1// ЗАДАЧА: Реализовать базовый автопилот для стабилизации
2
3/* ТРЕБОВАНИЯ:
41. Чтение данных IMU с частотой 100Hz
52. Реализация PID регулятора для стабилизации roll/pitch
63. Генерация PWM сигналов для 4 моторов
74. Режимы: Manual, Stabilize, Disarmed
85. Безопасность: автоматическое отключение при потере сигнала
9
10ТЕСТИРОВАНИЕ:
11- Симуляция на стенде с сервоприводами
12- Проверка отклика на внешние возмущения
13- Анализ качества стабилизации
14
15КРИТЕРИИ ОЦЕНКИ:
16- Точность чтения датчиков (20%)
17- Корректность PID алгоритма (35%)
18- Качество генерации PWM (20%)
19- Реализация систем безопасности (25%)
20*/
21
22// Ваша реализация автопилота...
Уровни сертификации:
⚡ EMBEDDED SYSTEMS ENGINEER (85-100 баллов):
- Сертификат “Инженер встроенных систем дронов”
- Право на разработку коммерческих автопилотов
- Создание собственных решений с нуля
- Консультирование по техническим вопросам
💻 DRONE PROGRAMMER (75-84 балла):
- Сертификат “Программист дронов”
- Модификация существующих автопилотов
- Интеграция новых датчиков и функций
- Техническая поддержка систем
🔧 ELECTRONICS TECHNICIAN (65-74 балла):
- Сертификат “Техник по электронике дронов”
- Сборка и настройка электронных систем
- Диагностика и ремонт
- Базовое программирование
📋 ДОПОЛНИТЕЛЬНЫЕ МАТЕРИАЛЫ К МОДУЛЮ 5
Расширенные примеры кода:
1. Продвинутая работа с датчиками:
1// Калибровка магнитометра
2// Автоматическое определение типа GPS
3// Фильтр Калмана для sensor fusion
4// Обнаружение отказов датчиков
2. Оптимизация производительности:
1// Использование DMA для высокоскоростного чтения
2// Многозадачность с FreeRTOS
3// Оптимизация вычислений с плавающей точкой
4// Профилирование производительности
3. Беспроводная связь:
1// MAVLink протокол телеметрии
2// Mesh-сети между дронами
3// Прямая связь с GCS
4// OTA обновления прошивки
4. Системы безопасности:
1// Watchdog таймеры
2// Резервирование критических систем
3// Детекция аномального поведения
4// Emergency recovery процедуры
Философское завершение модуля: “Поздравляю! Теперь вы владеете цифровой душой дрона. Вы можете не только собрать механическую конструкцию, но и вдохнуть в неё жизнь через программный код. ESP32 стал вашим инструментом для создания интеллектуальных летающих систем, способных принимать решения, адаптироваться к условиям и выполнять сложные задачи автономно.”
🎯 Результат модуля: Студент освоил программирование микроконтроллеров для дронов, может создавать собственные автопилоты, интегрировать различные датчики и реализовывать алгоритмы управления полетом.