P2
Отлично! Создаю эталонную STEM-презентацию по практическому программированию систем следования по линии с глубоким техническим анализом:Отлично! Создаю эталонную STEM-презентацию для практической работы по программированию датчиков линии с глубоким математическим анализом алгоритмов управления.
1title: "STEM-презентация: Программирование работы датчика линии"
2tag: "line-following-programming"
3description: |
4 ## 🛤️ Создание STEM-презентации "Практическая работа: Программирование работы датчика линии"
5
6 ### 📋 Исходные данные
7 **Учитель:** Ахметов Рустам
8 **Школа:** ГБОУ Школа № 1362
9 **Класс:** 6 (физмат-профиль)
10 **Модуль:** Сенсорные системы роботов
11 **Тип урока:** Практическая работа (90 минут)
12 **Дата:** 2025-06-13
13
14 ### 🎯 Цель презентации
15 Создать комплексную методическую презентацию для практической работы по программированию датчиков линии с акцентом на алгоритмическую разработку, математические модели управления и оптимизацию параметров системы.
16
17 ### 🔬 STEM-интеграция урока
18 - **S (Science):** Физика сенсоров, оптика, калибровка измерительных систем
19 - **T (Technology):** Датчики линии, микроконтроллеры, системы автоматического управления
20 - **E (Engineering):** Алгоритмы управления, PID-регуляторы, оптимизация систем
21 - **M (Mathematics):** Теория управления, дифференциальные уравнения, алгоритмы
22
23 ### 📊 Структура урока по карте
24 1. **Организационный момент** (3 мин)
25 2. **Постановка задачи** (5 мин)
26 3. **Подготовка оборудования** (10 мин)
27 4. **Калибровка датчиков** (10 мин)
28 5. **Изучение алгоритмов следования** (8 мин)
29 6. **Программирование базового алгоритма** (15 мин)
30 7. **Тестирование работы робота** (10 мин)
31 8. **Усовершенствование алгоритма** (15 мин)
32 9. **Финальное тестирование** (10 мин)
33 10. **Рефлексия и итоги** (4 мин)
34
35 ### 🧠 Ключевые технические аспекты
36 - Методы калибровки и определения пороговых значений
37 - Алгоритмы управления: от простых до PID-регуляторов
38 - Математическое моделирование поведения робота
39 - Оптимизация параметров для различных условий
40 - Обработка особых случаев (перекрестки, разрывы линии)
41
42 ### 🛠️ Практические задачи
43 - Установка и калибровка датчиков линии
44 - Программирование алгоритмов следования различной сложности
45 - Настройка параметров управления
46 - Тестирование в различных условиях освещения
47 - Оптимизация производительности системы
48
49 ### 🔧 Математический аппарат
50 - Теория автоматического управления
51 - PID-регуляторы и настройка коэффициентов
52 - Алгоритмы цифровой фильтрации сигналов
53 - Методы оптимизации параметров системы
1---
2title: "🛤️ Программирование работы датчика линии"
3subtitle: "От алгоритмов управления до математической оптимизации поведения"
4author: "Ахметов Рустам"
5date: "2025-06-13"
6class: "6 класс"
7subject: "Технология • Сенсорные системы роботов"
8duration: "90 минут"
9layout: "list"
10outputs:
11 - "reveal"
12theme: "control-algorithms"
13transition: "slide"
14backgroundTransition: "fade"
15controls: true
16progress: true
17history: true
18center: true
19touch: true
20loop: false
21rtl: false
22navigationMode: "default"
23---
24
25# 🛤️ Программирование работы датчика линии
26## От алгоритмов управления до математической оптимизации поведения
27
28**🧮 Алгоритмы • 📊 Теория управления • 💻 Программирование • 🎯 Оптимизация**
29*6 класс • Технология • 90 минут*
30
31👨🏫 **Учитель:** Ахметов Рустам
32🏫 **Школа:** ГБОУ № 1362
33📅 **Дата:** 2025-06-13
34🎯 **Цель:** Создать интеллектуальную систему навигации по линии!
35
36---
37
38## 🎯 План алгоритмической разработки
39
40**💻 Наша программистская миссия:**
411. **⚠️ Подготовка системы** - безопасность и инициализация (3 мин)
422. **🎯 Техническое задание** - формулировка алгоритмической задачи (5 мин)
433. **🔧 Установка оборудования** - интеграция датчиков в систему (10 мин)
444. **📐 Калибровка сенсоров** - настройка пороговых значений (10 мин)
455. **🧮 Математические модели** - теория алгоритмов управления (8 мин)
466. **💻 Базовое программирование** - реализация простых алгоритмов (15 мин)
477. **🧪 Тестирование и отладка** - верификация работы системы (10 мин)
488. **⚡ Продвинутые алгоритмы** - PID-регуляторы и оптимизация (15 мин)
499. **🏁 Итоговые испытания** - тестирование в различных условиях (10 мин)
5010. **🤔 Анализ результатов** - оценка эффективности алгоритмов (4 мин)
51
52**🎯 К концу практикума мы сможем:**
53- 📐 Калибровать сенсорные системы для точных измерений
54- 🧮 Программировать математические алгоритмы управления
55- ⚡ Оптимизировать параметры для максимальной эффективности
56- 🎛️ Создавать адаптивные системы автоматического управления
57
58---
59
60
⚠️ Подготовка инженерной лаборатории
Инициализация систем и безопасность
🛡️ Протокол безопасности
⚡ Электробезопасность при работе с датчиками:
- Проверка правильности подключения перед подачей питания
- Соблюдение полярности при подключении датчиков
- Использование токоограничивающих резисторов
- Избегание короткого замыкания сигнальных линий
💻 Безопасность программирования:
- Создание резервных копий перед каждым изменением кода
- Поэтапное тестирование новых функций
- Использование отладочных выводов для мониторинга
- Документирование всех изменений в коде
🤖 Безопасность тестирования роботов:
- Ограниченная скорость при первых запусках
- Контролируемая зона тестирования
- Готовность к экстренной остановке
- Защита датчиков от механических повреждений
🧰 Программные инструменты и среды
💻 Среды разработки по платформам:
Arduino IDE:
1// Настройка среды для работы с датчиками линии
2#define LEFT_SENSOR A0
3#define RIGHT_SENSOR A1
4#define LEFT_MOTOR 5
5#define RIGHT_MOTOR 6
6
7void setup() {
8 Serial.begin(9600);
9 pinMode(LEFT_MOTOR, OUTPUT);
10 pinMode(RIGHT_MOTOR, OUTPUT);
11
12 Serial.println("=== СИСТЕМА СЛЕДОВАНИЯ ПО ЛИНИИ ===");
13 Serial.println("Инициализация датчиков...");
14}
15
16// Функция диагностики системы
17void systemDiagnostics() {
18 Serial.println("Проверка подключения датчиков:");
19 Serial.print("Левый датчик: ");
20 Serial.println(analogRead(LEFT_SENSOR));
21 Serial.print("Правый датчик: ");
22 Serial.println(analogRead(RIGHT_SENSOR));
23}
LEGO MINDSTORMS EV3:
1Настройка среды EV3-G:
2- Подключение датчиков цвета в режиме отражения
3- Настройка портов моторов для левого и правого колеса
4- Конфигурация параметров связи для отладки
5- Установка начальной мощности моторов
Python для Raspberry Pi:
1import RPi.GPIO as GPIO
2import time
3
4# Инициализация GPIO для датчиков линии
5LEFT_SENSOR = 18
6RIGHT_SENSOR = 19
7LEFT_MOTOR_PWM = 20
8RIGHT_MOTOR_PWM = 21
9
10def initialize_system():
11 GPIO.setmode(GPIO.BCM)
12 GPIO.setup(LEFT_SENSOR, GPIO.IN)
13 GPIO.setup(RIGHT_SENSOR, GPIO.IN)
14 GPIO.setup(LEFT_MOTOR_PWM, GPIO.OUT)
15 GPIO.setup(RIGHT_MOTOR_PWM, GPIO.OUT)
16
17 print("=== СИСТЕМА НАВИГАЦИИ ГОТОВА ===")
18 print("Начинаем калибровку...")
19
20def system_check():
21 left_value = GPIO.input(LEFT_SENSOR)
22 right_value = GPIO.input(RIGHT_SENSOR)
23 print(f"Датчики: L={left_value}, R={right_value}")
📊 Подготовка тестового полигона
🛤️ Конфигурация трассы для тестирования:
1Схема тестового полигона:
2
3┌─────────────────────────────────────────────────┐
4│ │
5│ 🏁 СТАРТ │
6│ ║ │
7│ ║ ← Прямой участок (50 см) │
8│ ║ │
9│ ╚══╗ │
10│ ║ ← Плавный поворот (R=30 см) │
11│ ║ │
12│ ╔══╝ │
13│ ║ │
14│ ║ ← Прямой участок (30 см) │
15│ ║ │
16│ ╚══╗ │
17│ ║ ← Острый поворот (R=15 см) │
18│ ╔══╝ │
19│ ║ │
20│ ║ ← Финишный участок (20 см) │
21│ 🏁 ФИНИШ │
22└─────────────────────────────────────────────────┘
23
24Технические параметры:
25- Ширина линии: 20 мм
26- Материал: черная изолента на белом фоне
27- Контрастность: > 70%
28- Общая длина трассы: 150 см
📋 Контрольные точки для тестирования:
Участок
Тип испытания
Критерий успеха
Время прохождения
Участок 1
Прямолинейное движение
Отклонение < 5 мм
< 5 сек
Участок 2
Плавный поворот
Без потери линии
< 3 сек
Участок 3
Острый поворот
Восстановление < 1 сек
< 4 сек
Полная трасса
Комплексное испытание
Без остановок
< 15 сек
61
62---
63
64
🎯 Техническое задание
Формулировка алгоритмической задачи
🎯 Постановка задачи управления
📋 Техническое задание:
Основная цель: Разработать адаптивную систему автоматического управления роботом для точного следования по контрастной линии с оптимизацией скорости и плавности движения.
Технические требования:
- Максимальное отклонение от центра линии: ±3 мм
- Время восстановления после возмущения: < 0.5 сек
- Скорость движения: 0.2-0.8 м/с (переменная)
- Плавность управления: без резких рывков
- Адаптация к изменению освещения: автоматическая
🎮 Функциональные требования:
Базовый уровень (обязательный):
11. Калибровка датчиков:
2 - Определение пороговых значений для черного/белого
3 - Сохранение калибровочных данных
4 - Возможность рекалибровки
5
62. Следование по прямой линии:
7 - Стабильное движение по центру
8 - Коррекция при отклонениях
9 - Индикация состояния датчиков
10
113. Прохождение поворотов:
12 - Плавные повороты без потери линии
13 - Адаптация скорости в поворотах
14 - Восстановление после временной потери
Продвинутый уровень (дополнительный):
14. Оптимизация производительности:
2 - PID-регулятор для плавного управления
3 - Переменная скорость в зависимости от кривизны
4 - Предсказание траектории
5
65. Обработка особых случаев:
7 - Перекрестки и разветвления
8 - Прерывистые линии
9 - Изменение ширины линии
🔬 Анализ системы управления
📊 Математическая модель робота:
Робот как объект управления можно представить упрощенной моделью:
\[\frac{d\theta}{dt} = \frac{v_r - v_l}{L}\]
\[\frac{dx}{dt} = \frac{v_r + v_l}{2} \cos(\theta)\]
\[\frac{dy}{dt} = \frac{v_r + v_l}{2} \sin(\theta)\]
где:
- θ - угол поворота робота
- v_r, v_l - скорости правого и левого колеса
- L - расстояние между колесами
- x, y - координаты робота
🎛️ Переменные состояния системы:
1Входные переменные:
2- sensor_left: значение левого датчика [0-1023]
3- sensor_right: значение правого датчика [0-1023]
4- sensor_center: значение центрального датчика [0-1023] (опционально)
5
6Промежуточные переменные:
7- line_position: позиция линии относительно робота [-1.0...+1.0]
8- line_detected: флаг обнаружения линии [true/false]
9- error: ошибка позиционирования [-1.0...+1.0]
10
11Выходные переменные:
12- motor_left_speed: скорость левого мотора [0-255]
13- motor_right_speed: скорость правого мотора [0-255]
14- status_led: индикация состояния системы
🎯 Критерии качества управления
📈 Показатели эффективности системы:
Точность следования:
\[\text{RMSE} = \sqrt{\frac{1}{n}\sum_{i=1}^{n}(e_i)^2}\]
где e_i - отклонение от центра линии в i-й момент времени
Плавность управления:
\[\text{Smoothness} = \frac{1}{n-1}\sum_{i=1}^{n-1}|u_{i+1} - u_i|\]
где u_i - управляющее воздействие в i-й момент
Скорость прохождения:
\[\text{Speed} = \frac{L_{total}}{T_{total}}\]
где L_total - общая длина трассы, T_total - время прохождения
📊 Целевые значения показателей:
Показатель
Единица
Базовый уровень
Продвинутый уровень
RMSE отклонения
мм
< 5
< 2
Плавность
Δu/dt
< 50
< 20
Скорость
см/с
> 15
> 25
Время восстановления
мс
< 1000
< 300
🔄 Алгоритм оценки качества:
1class PerformanceAnalyzer {
2private:
3 float position_errors[1000];
4 float control_signals[1000];
5 int sample_count = 0;
6
7public:
8 void addSample(float error, float control) {
9 if(sample_count < 1000) {
10 position_errors[sample_count] = error;
11 control_signals[sample_count] = control;
12 sample_count++;
13 }
14 }
15
16 float calculateRMSE() {
17 float sum_squares = 0;
18 for(int i = 0; i < sample_count; i++) {
19 sum_squares += position_errors[i] * position_errors[i];
20 }
21 return sqrt(sum_squares / sample_count);
22 }
23
24 float calculateSmoothness() {
25 float sum_changes = 0;
26 for(int i = 1; i < sample_count; i++) {
27 sum_changes += abs(control_signals[i] - control_signals[i-1]);
28 }
29 return sum_changes / (sample_count - 1);
30 }
31
32 void printReport() {
33 Serial.println("=== ОТЧЕТ О ПРОИЗВОДИТЕЛЬНОСТИ ===");
34 Serial.print("RMSE ошибки: ");
35 Serial.println(calculateRMSE());
36 Serial.print("Плавность: ");
37 Serial.println(calculateSmoothness());
38 Serial.print("Количество образцов: ");
39 Serial.println(sample_count);
40 }
41};
65
66---
67
68
🔧 Установка и интеграция оборудования
Системная интеграция датчиков
📐 Оптимальное размещение датчиков
🔍 Конфигурации датчиков для различных задач:
Двухсенсорная система (базовая):
1Схема размещения:
2 [L] [R]
3 │ │
4 ├───────┤ ← 15-20 мм
5 ═══●═══════●═══ ← Линия (20 мм)
6 │ │
7 ПЛАТФОРМА
8
9Логика работы:
10L=0, R=0 → Линия потеряна или между датчиками
11L=1, R=0 → Линия слева, поворот направо
12L=0, R=1 → Линия справа, поворот налево
13L=1, R=1 → Широкая линия или перекресток
14
15Преимущества:
16✓ Простота программирования
17✓ Низкая стоимость
18✓ Быстрая реакция
19
20Ограничения:
21✗ Низкое разрешение
22✗ Рывки в движении
23✗ Сложность точной калибровки
Трехсенсорная система (рекомендуемая):
1Схема размещения:
2 [L] [C] [R]
3 │ │ │
4 ├─────┼─────┤ ← 10 мм каждый
5 ═══●═════●═════●═══ ← Линия
6 │ │ │
7 ПЛАТФОРМА
8
9Состояния и реакции:
10001 → Поворот налево (сильный)
11010 → Движение прямо
12100 → Поворот направо (сильный)
13011 → Поворот налево (слабый)
14110 → Поворот направо (слабый)
15111 → Перекресток или широкая линия
16000 → Поиск линии
17
18Преимущества:
19✓ Плавное управление
20✓ Хорошая точность
21✓ Простая калибровка
Пятисенсорная система (профессиональная):
1Схема размещения:
2[L2][L1][C][R1][R2]
3 │ │ │ │ │
4 ├───┼───┼───┼───┤ ← 6 мм между соседними
5═●═══●═══●═══●═══●═ ← Линия
6 │ │ │ │ │
7 ПЛАТФОРМА
8
9Расчет позиции линии:
10position = (L2×(-2) + L1×(-1) + C×0 + R1×1 + R2×2) / total_active
11
12Преимущества:
13✓ Максимальная точность
14✓ Плавное движение
15✓ Возможность интерполяции
16✓ Хорошее восстановление
⚡ Электрическое подключение
🔌 Схемы подключения для Arduino:
1Подключение трех аналоговых датчиков TCRT5000:
2
3Arduino Uno Датчик линии (Left) Датчик линии (Center) Датчик линии (Right)
4┌─────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
5│ 5V ├────┤ VCC │ │ VCC │ │ VCC │
6│ GND ├────┤ GND │ │ GND │ │ GND │
7│ A0 ├────┤ Analog Out │ │ │ │ │
8│ A1 ├────┼─────────────────┘ │ Analog Out │ │ │
9│ A2 ├────┼──────────────────────┤ │ │ Analog Out │
10│ │ └─────────────────────────────────────────┘ └─────────────────┘
11│ Pin 5 ├──── Left Motor (PWM)
12│ Pin 6 ├──── Right Motor (PWM)
13│ Pin 7 ├──── Left Motor Direction
14│ Pin 8 ├──── Right Motor Direction
15│ Pin 13 ├──── Status LED
16└─────────────┘
📊 Проверка подключения:
1void verifyConnections() {
2 Serial.println("=== ПРОВЕРКА ПОДКЛЮЧЕНИЯ ДАТЧИКОВ ===");
3
4 // Проверка питания
5 for(int i = 0; i < 3; i++) {
6 int value = analogRead(A0 + i);
7 Serial.print("Датчик ");
8 Serial.print(i);
9 Serial.print(": ");
10 Serial.print(value);
11
12 if(value < 50) {
13 Serial.println(" ❌ Возможно не подключен");
14 } else if(value > 950) {
15 Serial.println(" ⚠️ Возможно нет нагрузки");
16 } else {
17 Serial.println(" ✅ Подключение OK");
18 }
19 }
20
21 // Проверка моторов
22 digitalWrite(LEFT_MOTOR_DIR, HIGH);
23 analogWrite(LEFT_MOTOR_PWM, 100);
24 delay(500);
25 analogWrite(LEFT_MOTOR_PWM, 0);
26
27 digitalWrite(RIGHT_MOTOR_DIR, HIGH);
28 analogWrite(RIGHT_MOTOR_PWM, 100);
29 delay(500);
30 analogWrite(RIGHT_MOTOR_PWM, 0);
31
32 Serial.println("Проверка моторов завершена");
33}
🛠️ Механическое крепление
🔧 Требования к установке датчиков:
1Критические параметры установки:
2
31. Высота над поверхностью:
4 - Оптимальная: 3-5 мм
5 - Минимальная: 2 мм
6 - Максимальная: 8 мм
7
82. Угол наклона:
9 - Рекомендуемый: 0° (перпендикулярно)
10 - Допустимый: ±5°
11 - Критический: ±15°
12
133. Расстояние от центра робота:
14 - Минимальное: 30 мм (для маневренности)
15 - Оптимальное: 50-70 мм
16 - Максимальное: 100 мм (для больших роботов)
17
184. Защита от вибраций:
19 - Жесткое крепление к раме
20 - Амортизация при необходимости
21 - Защита проводов от перегибов
📐 Проверочный тест установки:
1void testSensorPlacement() {
2 Serial.println("=== ТЕСТ КАЧЕСТВА УСТАНОВКИ ===");
3
4 // Тест стабильности показаний
5 float readings[3][20];
6
7 for(int sample = 0; sample < 20; sample++) {
8 for(int sensor = 0; sensor < 3; sensor++) {
9 readings[sensor][sample] = analogRead(A0 + sensor);
10 }
11 delay(50);
12 }
13
14 // Анализ стабильности
15 for(int sensor = 0; sensor < 3; sensor++) {
16 float mean = 0, stddev = 0;
17
18 // Среднее значение
19 for(int i = 0; i < 20; i++) {
20 mean += readings[sensor][i];
21 }
22 mean /= 20;
23
24 // Стандартное отклонение
25 for(int i = 0; i < 20; i++) {
26 stddev += pow(readings[sensor][i] - mean, 2);
27 }
28 stddev = sqrt(stddev / 19);
29
30 Serial.print("Датчик ");
31 Serial.print(sensor);
32 Serial.print(": среднее=");
33 Serial.print(mean);
34 Serial.print(", σ=");
35 Serial.print(stddev);
36
37 if(stddev < 5) {
38 Serial.println(" ✅ Стабильно");
39 } else if(stddev < 15) {
40 Serial.println(" ⚠️ Умеренные колебания");
41 } else {
42 Serial.println(" ❌ Нестабильно - проверить крепление");
43 }
44 }
45}
69
70---
71
72## 📐 Калибровка сенсорной системы
73
74### 🎛️ Методология точной калибровки
75
76**🔬 Теоретические основы калибровки:**
77
78Калибровка датчиков линии - критически важный процесс, определяющий точность работы всей системы. Цель калибровки - установить соответствие между физическими характеристиками поверхности и цифровыми значениями датчиков.
79
80**📊 Математическая модель калибровки:**
81
82
\[V_{norm} = \frac{V_{raw} - V_{min}}{V_{max} - V_{min}}\]
83
84где:
85- V_norm - нормализованное значение [0...1]
86- V_raw - сырое значение АЦП
87- V_min - минимальное значение (черная поверхность)
88- V_max - максимальное значение (белая поверхность)
89
90**🎯 Определение порогового значения:**
91
92
\[V_{threshold} = V_{min} + k \times (V_{max} - V_{min})\]
93
94где k - коэффициент порога (обычно 0.4-0.6 для максимальной помехоустойчивости)
95
96---
97
98### 📋 Пошаговая процедура калибровки
99
100**🔧 Автоматическая калибровка:**
101
102```cpp
103class SensorCalibration {
104private:
105 int sensor_pins[3] = {A0, A1, A2};
106 int min_values[3] = {1023, 1023, 1023};
107 int max_values[3] = {0, 0, 0};
108 int threshold_values[3];
109 bool calibrated = false;
110
111public:
112 void performCalibration() {
113 Serial.println("=== АВТОМАТИЧЕСКАЯ КАЛИБРОВКА ===");
114 Serial.println("Поместите робота на белую поверхность");
115 Serial.println("Нажмите кнопку для начала...");
116
117 waitForButtonPress();
118
119 // Калибровка на белой поверхности
120 Serial.println("Калибровка белого... (5 сек)");
121 calibrateWhiteSurface();
122
123 Serial.println("Поместите робота на черную линию");
124 Serial.println("Нажмите кнопку для продолжения...");
125
126 waitForButtonPress();
127
128 // Калибровка на черной поверхности
129 Serial.println("Калибровка черного... (5 сек)");
130 calibrateBlackSurface();
131
132 // Расчет пороговых значений
133 calculateThresholds();
134
135 // Сохранение результатов
136 saveCalibrationData();
137
138 calibrated = true;
139 Serial.println("✅ Калибровка завершена успешно!");
140 printCalibrationResults();
141 }
142
143private:
144 void calibrateWhiteSurface() {
145 unsigned long start_time = millis();
146 int sample_count = 0;
147
148 while(millis() - start_time < 5000) {
149 for(int i = 0; i < 3; i++) {
150 int value = analogRead(sensor_pins[i]);
151 if(value > max_values[i]) {
152 max_values[i] = value;
153 }
154 }
155 sample_count++;
156 delay(10);
157 }
158
159 Serial.print("Образцов обработано: ");
160 Serial.println(sample_count);
161 }
162
163 void calibrateBlackSurface() {
164 unsigned long start_time = millis();
165 int sample_count = 0;
166
167 while(millis() - start_time < 5000) {
168 for(int i = 0; i < 3; i++) {
169 int value = analogRead(sensor_pins[i]);
170 if(value < min_values[i]) {
171 min_values[i] = value;
172 }
173 }
174 sample_count++;
175 delay(10);
176 }
177
178 Serial.print("Образцов обработано: ");
179 Serial.println(sample_count);
180 }
181
182 void calculateThresholds() {
183 for(int i = 0; i < 3; i++) {
184 // Адаптивный порог с учетом контрастности
185 int range = max_values[i] - min_values[i];
186 float threshold_factor = 0.5; // Базовое значение
187
188 // Адаптация в зависимости от контрастности
189 if(range > 500) {
190 threshold_factor = 0.4; // Высокая контрастность
191 } else if(range < 200) {
192 threshold_factor = 0.6; // Низкая контрастность
193 }
194
195 threshold_values[i] = min_values[i] + threshold_factor * range;
196 }
197 }
198
199public:
200 float getNormalizedValue(int sensor_index) {
201 if(!calibrated || sensor_index < 0 || sensor_index > 2) {
202 return 0.5; // Безопасное значение
203 }
204
205 int raw = analogRead(sensor_pins[sensor_index]);
206
207 // Ограничение значений в калибровочном диапазоне
208 raw = constrain(raw, min_values[sensor_index], max_values[sensor_index]);
209
210 // Нормализация
211 float normalized = (float)(raw - min_values[sensor_index]) /
212 (max_values[sensor_index] - min_values[sensor_index]);
213
214 return normalized;
215 }
216
217 bool isOnLine(int sensor_index) {
218 if(!calibrated) return false;
219
220 int raw = analogRead(sensor_pins[sensor_index]);
221 return raw < threshold_values[sensor_index];
222 }
223
224 void printCalibrationResults() {
225 Serial.println("\n=== РЕЗУЛЬТАТЫ КАЛИБРОВКИ ===");
226 for(int i = 0; i < 3; i++) {
227 Serial.print("Датчик ");
228 Serial.print(i);
229 Serial.print(": MIN=");
230 Serial.print(min_values[i]);
231 Serial.print(", MAX=");
232 Serial.print(max_values[i]);
233 Serial.print(", ПОРОГ=");
234 Serial.print(threshold_values[i]);
235 Serial.print(", КОНТРАСТ=");
236 Serial.print(max_values[i] - min_values[i]);
237 Serial.println();
238 }
239
240 // Оценка качества калибровки
241 analyzeCalibrationQuality();
242 }
243
244private:
245 void analyzeCalibrationQuality() {
246 Serial.println("\n=== АНАЛИЗ КАЧЕСТВА КАЛИБРОВКИ ===");
247
248 for(int i = 0; i < 3; i++) {
249 int contrast = max_values[i] - min_values[i];
250
251 Serial.print("Датчик ");
252 Serial.print(i);
253 Serial.print(": ");
254
255 if(contrast > 400) {
256 Serial.println("✅ Отличная контрастность");
257 } else if(contrast > 200) {
258 Serial.println("✅ Хорошая контрастность");
259 } else if(contrast > 100) {
260 Serial.println("⚠️ Удовлетворительная контрастность");
261 } else {
262 Serial.println("❌ Плохая контрастность - проверить установку");
263 }
264 }
265 }
266};
📊 Адаптивная калибровка
🤖 Самообучающаяся система:
1class AdaptiveCalibration {
2private:
3 float adaptation_rate = 0.01; // Скорость адаптации
4 float confidence_threshold = 0.8;
5
6 struct CalibrationStats {
7 float running_min;
8 float running_max;
9 int sample_count;
10 float confidence;
11 } stats[3];
12
13public:
14 void initializeAdaptive() {
15 for(int i = 0; i < 3; i++) {
16 stats[i].running_min = 1023;
17 stats[i].running_max = 0;
18 stats[i].sample_count = 0;
19 stats[i].confidence = 0;
20 }
21 }
22
23 void updateAdaptiveCalibration() {
24 for(int i = 0; i < 3; i++) {
25 float current_value = analogRead(A0 + i);
26
27 // Медленная адаптация к экстремальным значениям
28 if(current_value < stats[i].running_min) {
29 stats[i].running_min = current_value * (1 - adaptation_rate) +
30 stats[i].running_min * adaptation_rate;
31 }
32
33 if(current_value > stats[i].running_max) {
34 stats[i].running_max = current_value * (1 - adaptation_rate) +
35 stats[i].running_max * adaptation_rate;
36 }
37
38 stats[i].sample_count++;
39
40 // Обновление уверенности в калибровке
41 float range = stats[i].running_max - stats[i].running_min;
42 stats[i].confidence = min(1.0, range / 500.0);
43 }
44 }
45
46 bool isCalibrationReliable() {
47 for(int i = 0; i < 3; i++) {
48 if(stats[i].confidence < confidence_threshold) {
49 return false;
50 }
51 }
52 return true;
53 }
54
55 void printAdaptiveStatus() {
56 static unsigned long last_print = 0;
57 if(millis() - last_print > 2000) {
58 Serial.println("=== АДАПТИВНАЯ КАЛИБРОВКА ===");
59 for(int i = 0; i < 3; i++) {
60 Serial.print("S");
61 Serial.print(i);
62 Serial.print(": MIN=");
63 Serial.print(stats[i].running_min, 1);
64 Serial.print(", MAX=");
65 Serial.print(stats[i].running_max, 1);
66 Serial.print(", CONF=");
67 Serial.print(stats[i].confidence * 100, 0);
68 Serial.println("%");
69 }
70 last_print = millis();
71 }
72 }
73};
🧮 Математические модели управления
📈 Теория автоматического управления
🎯 Классификация алгоритмов управления:
1. Релейный алгоритм (Bang-Bang Control): \[u(t) = \begin{cases} U_{max} & \text{если } e(t) > 0 \\ -U_{max} & \text{если } e(t) < 0 \end{cases}\]
2. Пропорциональный регулятор (P-Controller): \[u(t) = K_p \cdot e(t)\]
3. Пропорционально-дифференциальный (PD-Controller): \[u(t) = K_p \cdot e(t) + K_d \cdot \frac{de(t)}{dt}\]
4. PID-регулятор: \[u(t) = K_p \cdot e(t) + K_i \int_0^t e(\tau)d\tau + K_d \cdot \frac{de(t)}{dt}\]
где:
- e(t) - ошибка управления (отклонение от желаемой траектории)
- u(t) - управляющее воздействие
- K_p, K_i, K_d - коэффициенты регулятора
🎛️ Реализация алгоритмов управления
🔧 Простой релейный алгоритм:
1class BangBangController {
2private:
3 SensorCalibration* calibration;
4 int base_speed = 150;
5 int turn_speed = 200;
6
7public:
8 BangBangController(SensorCalibration* cal) : calibration(cal) {}
9
10 void update() {
11 bool left_on_line = calibration->isOnLine(0);
12 bool center_on_line = calibration->isOnLine(1);
13 bool right_on_line = calibration->isOnLine(2);
14
15 // Простая логика управления
16 if(center_on_line) {
17 // Линия по центру - движение прямо
18 setMotorSpeeds(base_speed, base_speed);
19 setStatusLED(GREEN);
20 }
21 else if(left_on_line) {
22 // Линия слева - поворот направо
23 setMotorSpeeds(base_speed + turn_speed, base_speed - turn_speed);
24 setStatusLED(YELLOW);
25 }
26 else if(right_on_line) {
27 // Линия справа - поворот налево
28 setMotorSpeeds(base_speed - turn_speed, base_speed + turn_speed);
29 setStatusLED(YELLOW);
30 }
31 else {
32 // Линия потеряна - поиск
33 executeSearchPattern();
34 setStatusLED(RED);
35 }
36 }
37
38private:
39 void executeSearchPattern() {
40 static unsigned long search_start = 0;
41 static int search_direction = 1;
42
43 if(search_start == 0) {
44 search_start = millis();
45 }
46
47 // Зигзагообразный поиск
48 if(millis() - search_start < 500) {
49 setMotorSpeeds(100 * search_direction, -100 * search_direction);
50 } else {
51 search_direction *= -1;
52 search_start = millis();
53 }
54 }
55};
⚖️ Пропорциональный регулятор:
1class ProportionalController {
2private:
3 SensorCalibration* calibration;
4 float kp = 2.0; // Пропорциональный коэффициент
5 int base_speed = 150; // Базовая скорость
6 int max_correction = 100; // Максимальная коррекция
7
8public:
9 ProportionalController(SensorCalibration* cal) : calibration(cal) {}
10
11 void update() {
12 float line_position = calculateLinePosition();
13
14 if(line_position != -999) { // Линия обнаружена
15 float error = 0.0 - line_position; // Цель - центр (0)
16 float correction = kp * error;
17
18 // Ограничение коррекции
19 correction = constrain(correction, -max_correction, max_correction);
20
21 // Применение коррекции к моторам
22 int left_speed = base_speed - correction;
23 int right_speed = base_speed + correction;
24
25 // Ограничение скоростей моторов
26 left_speed = constrain(left_speed, 0, 255);
27 right_speed = constrain(right_speed, 0, 255);
28
29 setMotorSpeeds(left_speed, right_speed);
30
31 // Отладочная информация
32 Serial.print("Pos: ");
33 Serial.print(line_position, 2);
34 Serial.print(", Err: ");
35 Serial.print(error, 2);
36 Serial.print(", Corr: ");
37 Serial.print(correction, 1);
38 Serial.print(", Motors: ");
39 Serial.print(left_speed);
40 Serial.print(",");
41 Serial.println(right_speed);
42 } else {
43 // Линия потеряна
44 executeSearchPattern();
45 }
46 }
47
48private:
49 float calculateLinePosition() {
50 float left_norm = calibration->getNormalizedValue(0);
51 float center_norm = calibration->getNormalizedValue(1);
52 float right_norm = calibration->getNormalizedValue(2);
53
54 // Инверсия для работы с черной линией (0 = белый, 1 = черный)
55 left_norm = 1.0 - left_norm;
56 center_norm = 1.0 - center_norm;
57 right_norm = 1.0 - right_norm;
58
59 float total_activation = left_norm + center_norm + right_norm;
60
61 if(total_activation < 0.1) {
62 return -999; // Линия не обнаружена
63 }
64
65 // Взвешенное среднее: -1 (крайне слева) до +1 (крайне справа)
66 float weighted_sum = left_norm * (-1.0) + center_norm * 0.0 + right_norm * (+1.0);
67 float position = weighted_sum / total_activation;
68
69 return position;
70 }
71
72 void setKp(float new_kp) {
73 kp = constrain(new_kp, 0.1, 10.0);
74 Serial.print("Новый Kp: ");
75 Serial.println(kp);
76 }
77};
🎛️ PD-регулятор (продвинутый):
1class PDController {
2private:
3 SensorCalibration* calibration;
4
5 // Параметры регулятора
6 float kp = 2.5; // Пропорциональный коэффициент
7 float kd = 0.8; // Дифференциальный коэффициент
8
9 // Переменные состояния
10 float previous_error = 0;
11 unsigned long previous_time = 0;
12
13 // Параметры управления
14 int base_speed = 180;
15 int max_correction = 120;
16
17 // Фильтр для производной
18 float derivative_filter = 0.1;
19 float filtered_derivative = 0;
20
21public:
22 PDController(SensorCalibration* cal) : calibration(cal) {
23 previous_time = millis();
24 }
25
26 void update() {
27 unsigned long current_time = millis();
28 float dt = (current_time - previous_time) / 1000.0; // Время в секундах
29
30 if(dt > 0.001) { // Минимальный интервал времени
31 float line_position = calculateLinePosition();
32
33 if(line_position != -999) {
34 float error = 0.0 - line_position;
35
36 // Пропорциональная составляющая
37 float proportional = kp * error;
38
39 // Дифференциальная составляющая с фильтрацией
40 float raw_derivative = (error - previous_error) / dt;
41 filtered_derivative = derivative_filter * raw_derivative +
42 (1 - derivative_filter) * filtered_derivative;
43 float differential = kd * filtered_derivative;
44
45 // Общее управляющее воздействие
46 float control_signal = proportional + differential;
47
48 // Ограничение сигнала управления
49 control_signal = constrain(control_signal, -max_correction, max_correction);
50
51 // Применение к моторам
52 int left_speed = base_speed - control_signal;
53 int right_speed = base_speed + control_signal;
54
55 left_speed = constrain(left_speed, 0, 255);
56 right_speed = constrain(right_speed, 0, 255);
57
58 setMotorSpeeds(left_speed, right_speed);
59
60 // Обновление переменных состояния
61 previous_error = error;
62 previous_time = current_time;
63
64 // Отладочная информация
65 printControllerStatus(line_position, error, proportional,
66 differential, control_signal);
67 } else {
68 executeAdvancedSearchPattern();
69 }
70 }
71 }
72
73private:
74 void printControllerStatus(float position, float error,
75 float prop, float diff, float control) {
76 static unsigned long last_print = 0;
77 if(millis() - last_print > 100) { // Каждые 100 мс
78 Serial.print("Pos:");
79 Serial.print(position, 2);
80 Serial.print(" E:");
81 Serial.print(error, 2);
82 Serial.print(" P:");
83 Serial.print(prop, 1);
84 Serial.print(" D:");
85 Serial.print(diff, 1);
86 Serial.print(" U:");
87 Serial.println(control, 1);
88 last_print = millis();
89 }
90 }
91
92 void tuneParameters(float new_kp, float new_kd) {
93 kp = constrain(new_kp, 0.1, 10.0);
94 kd = constrain(new_kd, 0.0, 5.0);
95
96 Serial.print("Новые параметры - Kp:");
97 Serial.print(kp);
98 Serial.print(", Kd:");
99 Serial.println(kd);
100
101 // Сброс фильтра при изменении параметров
102 filtered_derivative = 0;
103 previous_error = 0;
104 }
105
106 void executeAdvancedSearchPattern() {
107 static unsigned long search_start = 0;
108 static float search_amplitude = 50;
109 static float search_frequency = 2.0; // Гц
110
111 if(search_start == 0) {
112 search_start = millis();
113 }
114
115 float time_elapsed = (millis() - search_start) / 1000.0;
116 float search_signal = search_amplitude * sin(2 * PI * search_frequency * time_elapsed);
117
118 int left_speed = base_speed/2 - search_signal;
119 int right_speed = base_speed/2 + search_signal;
120
121 left_speed = constrain(left_speed, 0, 255);
122 right_speed = constrain(right_speed, 0, 255);
123
124 setMotorSpeeds(left_speed, right_speed);
125 }
126};
💻 Программирование базовых алгоритмов
🚀 Архитектура программной системы
🏗️ Модульная структура программы:
1// ================== ГЛАВНЫЙ ФАЙЛ ПРОГРАММЫ ==================
2#include "SensorCalibration.h"
3#include "LineFollowingController.h"
4#include "PerformanceAnalyzer.h"
5#include "UserInterface.h"
6
7// Глобальные объекты системы
8SensorCalibration calibration;
9PDController controller(&calibration);
10PerformanceAnalyzer analyzer;
11UserInterface ui;
12
13// Конфигурация системы
14struct SystemConfig {
15 bool auto_calibration_enabled = true;
16 bool performance_logging = true;
17 bool debug_output = false;
18 int target_loop_frequency = 50; // Гц
19} config;
20
21void setup() {
22 Serial.begin(115200);
23
24 // Инициализация аппаратуры
25 initializeHardware();
26
27 // Приветствие пользователя
28 ui.displayWelcomeMessage();
29
30 // Проверка системы
31 if(!performSystemSelfCheck()) {
32 Serial.println("❌ Ошибка инициализации системы!");
33 while(1) { delay(1000); }
34 }
35
36 // Калибровка датчиков
37 if(config.auto_calibration_enabled) {
38 calibration.performCalibration();
39 } else {
40 calibration.loadFromEEPROM();
41 }
42
43 // Готовность к работе
44 ui.displayReadyMessage();
45 delay(1000);
46
47 Serial.println("🚀 СИСТЕМА СЛЕДОВАНИЯ ПО ЛИНИИ ЗАПУЩЕНА");
48}
49
50void loop() {
51 unsigned long loop_start = micros();
52
53 // Основной цикл управления
54 controller.update();
55
56 // Сбор данных о производительности
57 if(config.performance_logging) {
58 analyzer.collectSample();
59 }
60
61 // Обработка пользовательского интерфейса
62 ui.processInput();
63
64 // Адаптивная калибровка
65 if(config.auto_calibration_enabled) {
66 calibration.updateAdaptive();
67 }
68
69 // Контроль частоты цикла
70 maintainLoopFrequency(loop_start);
71}
72
73// ================== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ==================
74void initializeHardware() {
75 // Инициализация пинов моторов
76 pinMode(LEFT_MOTOR_PWM, OUTPUT);
77 pinMode(RIGHT_MOTOR_PWM, OUTPUT);
78 pinMode(LEFT_MOTOR_DIR, OUTPUT);
79 pinMode(RIGHT_MOTOR_DIR, OUTPUT);
80
81 // Инициализация индикации
82 pinMode(STATUS_LED, OUTPUT);
83 pinMode(BUTTON_PIN, INPUT_PULLUP);
84
85 // Установка начального состояния
86 digitalWrite(LEFT_MOTOR_DIR, HIGH);
87 digitalWrite(RIGHT_MOTOR_DIR, HIGH);
88 analogWrite(LEFT_MOTOR_PWM, 0);
89 analogWrite(RIGHT_MOTOR_PWM, 0);
90}
91
92bool performSystemSelfCheck() {
93 Serial.println("=== САМОДИАГНОСТИКА СИСТЕМЫ ===");
94
95 // Проверка датчиков
96 bool sensors_ok = true;
97 for(int i = 0; i < 3; i++) {
98 int value = analogRead(A0 + i);
99 if(value < 10 || value > 1020) {
100 Serial.print("❌ Датчик ");
101 Serial.print(i);
102 Serial.println(" не отвечает");
103 sensors_ok = false;
104 }
105 }
106
107 // Проверка моторов
108 bool motors_ok = testMotors();
109
110 // Проверка памяти
111 bool memory_ok = (getFreeMemory() > 500);
112
113 Serial.print("Датчики: ");
114 Serial.println(sensors_ok ? "✅" : "❌");
115 Serial.print("Моторы: ");
116 Serial.println(motors_ok ? "✅" : "❌");
117 Serial.print("Память: ");
118 Serial.print(getFreeMemory());
119 Serial.println(" байт");
120
121 return sensors_ok && motors_ok && memory_ok;
122}
123
124void maintainLoopFrequency(unsigned long loop_start) {
125 unsigned long target_period = 1000000 / config.target_loop_frequency; // мкс
126 unsigned long loop_duration = micros() - loop_start;
127
128 if(loop_duration < target_period) {
129 delayMicroseconds(target_period - loop_duration);
130 } else if(config.debug_output) {
131 Serial.print("⚠️ Превышение времени цикла: ");
132 Serial.print(loop_duration);
133 Serial.println(" мкс");
134 }
135}
🎛️ Пользовательский интерфейс
📟 Интерактивное управление системой:
1class UserInterface {
2private:
3 enum UIState {
4 MAIN_MENU,
5 CALIBRATION_MENU,
6 PARAMETER_TUNING,
7 PERFORMANCE_VIEW,
8 RUNNING
9 } current_state = MAIN_MENU;
10
11 unsigned long last_status_update = 0;
12
13public:
14 void displayWelcomeMessage() {
15 Serial.println("╔═══════════════════════════════════════╗");
16 Serial.println("║ СИСТЕМА СЛЕДОВАНИЯ ПО ЛИНИИ ║");
17 Serial.println("║ Версия 2.0 STEM ║");
18 Serial.println("║ ГБОУ Школа № 1362 - 6 класс ║");
19 Serial.println("╚═══════════════════════════════════════╝");
20 Serial.println();
21 }
22
23 void displayMainMenu() {
24 Serial.println("=== ГЛАВНОЕ МЕНЮ ===");
25 Serial.println("1. Запустить следование по линии");
26 Serial.println("2. Калибровка датчиков");
27 Serial.println("3. Настройка параметров");
28 Serial.println("4. Просмотр производительности");
29 Serial.println("5. Диагностика системы");
30 Serial.println("0. Экстренная остановка");
31 Serial.println();
32 Serial.print("Выберите опцию: ");
33 }
34
35 void processInput() {
36 if(Serial.available()) {
37 char input = Serial.read();
38 handleMenuInput(input);
39 }
40
41 // Обновление статуса во время работы
42 if(current_state == RUNNING && millis() - last_status_update > 1000) {
43 displayRunningStatus();
44 last_status_update = millis();
45 }
46 }
47
48private:
49 void handleMenuInput(char input) {
50 switch(current_state) {
51 case MAIN_MENU:
52 handleMainMenuInput(input);
53 break;
54 case CALIBRATION_MENU:
55 handleCalibrationMenuInput(input);
56 break;
57 case PARAMETER_TUNING:
58 handleParameterTuningInput(input);
59 break;
60 case PERFORMANCE_VIEW:
61 handlePerformanceViewInput(input);
62 break;
63 case RUNNING:
64 handleRunningInput(input);
65 break;
66 }
67 }
68
69 void handleMainMenuInput(char input) {
70 switch(input) {
71 case '1':
72 Serial.println("🚀 Запуск системы следования...");
73 current_state = RUNNING;
74 break;
75 case '2':
76 Serial.println("📐 Меню калибровки:");
77 displayCalibrationMenu();
78 current_state = CALIBRATION_MENU;
79 break;
80 case '3':
81 Serial.println("⚙️ Настройка параметров:");
82 displayParameterMenu();
83 current_state = PARAMETER_TUNING;
84 break;
85 case '4':
86 Serial.println("📊 Анализ производительности:");
87 analyzer.displayDetailedReport();
88 current_state = PERFORMANCE_VIEW;
89 break;
90 case '5':
91 Serial.println("🔧 Диагностика системы:");
92 performSystemSelfCheck();
93 displayMainMenu();
94 break;
95 case '0':
96 emergencyStop();
97 break;
98 default:
99 Serial.println("❌ Неверный ввод. Попробуйте снова.");
100 displayMainMenu();
101 }
102 }
103
104 void displayRunningStatus() {
105 Serial.println("┌─────────────────────────────────┐");
106 Serial
107
108
109# Пересобрать урок и уменьшить код
110// Достаточно для образовательных целей (урок 90 мин)
111#define LEFT_SENSOR A0
112#define CENTER_SENSOR A1
113#define RIGHT_SENSOR A2
114
115int threshold = 500; // Простое фиксированное значение для начала
116
117void setup() {
118 Serial.begin(9600);
119 Serial.println("🤖 Робот-следопыт запущен!");
120
121 // Быстрая автокалибровка (30 сек)
122 Serial.println("Калибровка... поставьте на линию");
123 delay(3000);
124 autoCalibrate();
125
126 Serial.println("✅ Готов! Показания датчиков:");
127}
128
129void loop() {
130 // Основной алгоритм
131 followLine();
132
133 // Простая отладка
134 debugPrint();
135 delay(100);
136}
137
138void debugPrint() {
139 Serial.print("Датчики: ");
140 Serial.print(analogRead(LEFT_SENSOR) > threshold ? "●" : "○");
141 Serial.print(" ");
142 Serial.print(analogRead(CENTER_SENSOR) > threshold ? "●" : "○");
143 Serial.print(" ");
144 Serial.print(analogRead(RIGHT_SENSOR) > threshold ? "●" : "○");
145 Serial.print(" | Движение: ");
146 Serial.println(getMovementDescription());
147}