📱 Программирование пульта дистанционного управления
Создаем систему беспроводного управления роботом
🎮 Интерфейс • 📡 Связь • 💻 Программирование • 🔧 Отладка
7 класс • Технология • 45 минут
mw285748 • 15.06.2025
🎯 Цель урока
💡 Научимся:
- Программировать пульты дистанционного управления
- Настраивать беспроводные модули связи
- Создавать системы обработки команд
- Тестировать и оптимизировать управление
🤖 Результат: Функциональная система дистанционного управления роботом!
🏗️ Архитектура системы управления
📊 Компоненты системы
1[ОПЕРАТОР] ←→ [ПУЛЬТ] ~~~📡~~~ [РОБОТ] ←→ [ДАТЧИКИ]
2 ↑ ↑ ↑ ↑
3 Команды Интерфейс Исполнение Обратная
4 связь
Основные блоки:
- Пульт управления - формирование команд
- Канал связи - передача данных
- Робот - исполнение команд
- Обратная связь - контроль состояния
🔄 Цикл управления
Алгоритм работы системы:
1while True:
2 # 1. Получение команд от оператора
3 user_input = read_user_interface()
4
5 # 2. Формирование пакета данных
6 command_packet = encode_command(user_input)
7
8 # 3. Передача по беспроводному каналу
9 send_wireless(command_packet)
10
11 # 4. Получение и обработка на роботе
12 if packet_received():
13 execute_command(decode_packet())
14
15 # 5. Отправка обратной связи
16 telemetry = read_sensors()
17 send_feedback(telemetry)
18
19 delay(10) # Период управления
⏱️ Временные характеристики:
- Период управления: 10-100 мс
- Задержка передачи: 5-50 мс
- Время обработки: 1-10 мс
📱 Программирование пульта управления
🎮 Типы интерфейсов
Мобильное приложение (Android/iOS):
1// Пример кода для Android
2public class RobotController extends AppCompatActivity {
3 private BluetoothAdapter bluetoothAdapter;
4 private BluetoothSocket socket;
5
6 // Обработка джойстика
7 @Override
8 public boolean onTouchEvent(MotionEvent event) {
9 float x = event.getX();
10 float y = event.getY();
11
12 // Преобразование координат в команды
13 int speed = calculateSpeed(y);
14 int direction = calculateDirection(x);
15
16 // Отправка команды
17 sendCommand("MOVE", speed, direction);
18 return true;
19 }
20
21 private void sendCommand(String type, int param1, int param2) {
22 String command = type + ":" + param1 + ":" + param2 + "\n";
23 socket.getOutputStream().write(command.getBytes());
24 }
25}
🖥️ Веб-интерфейс
HTML + JavaScript:
1<!DOCTYPE html>
2<html>
3<head>
4 <title>Робот Control</title>
5</head>
6<body>
7 <div class="joystick-container">
8 <div id="joystick"></div>
9 </div>
10
11 <div class="buttons">
12 <button onclick="sendCommand('LED_ON')">💡 Свет</button>
13 <button onclick="sendCommand('HORN')">🔊 Сигнал</button>
14 <button onclick="sendCommand('STOP')">🛑 Стоп</button>
15 </div>
16
17 <script>
18 // WebSocket соединение
19 const ws = new WebSocket('ws://192.168.1.100:8080');
20
21 function sendCommand(cmd) {
22 const packet = {
23 command: cmd,
24 timestamp: Date.now(),
25 source: "web_interface"
26 };
27 ws.send(JSON.stringify(packet));
28 }
29
30 // Виртуальный джойстик
31 const joystick = new VirtualJoystick({
32 container: document.getElementById('joystick'),
33 mouseSupport: true,
34 onMove: function(event, data) {
35 const speed = Math.round(data.force * 100);
36 const angle = Math.round(data.angle.degree);
37 sendCommand(`MOVE:${speed}:${angle}`);
38 }
39 });
40 </script>
41</body>
42</html>
🎛️ Физический пульт
Arduino-пульт с джойстиками:
1// Пульт на Arduino с nRF24L01
2#include <SPI.h>
3#include <nRF24L01.h>
4#include <RF24.h>
5
6RF24 radio(9, 10); // CE, CSN пины
7const byte address[6] = "Robot1";
8
9struct ControlData {
10 int leftStickX;
11 int leftStickY;
12 int rightStickX;
13 int rightStickY;
14 bool button1;
15 bool button2;
16 bool button3;
17 unsigned long timestamp;
18};
19
20void setup() {
21 Serial.begin(9600);
22 radio.begin();
23 radio.openWritingPipe(address);
24 radio.setPALevel(RF24_PA_MIN);
25 radio.stopListening();
26}
27
28void loop() {
29 ControlData data;
30
31 // Чтение аналоговых джойстиков
32 data.leftStickX = analogRead(A0);
33 data.leftStickY = analogRead(A1);
34 data.rightStickX = analogRead(A2);
35 data.rightStickY = analogRead(A3);
36
37 // Чтение цифровых кнопок
38 data.button1 = digitalRead(2);
39 data.button2 = digitalRead(3);
40 data.button3 = digitalRead(4);
41
42 // Временная метка
43 data.timestamp = millis();
44
45 // Отправка данных
46 bool result = radio.write(&data, sizeof(data));
47
48 if (result) {
49 Serial.println("Данные отправлены успешно");
50 } else {
51 Serial.println("Ошибка передачи");
52 }
53
54 delay(50); // 20 пакетов в секунду
55}
📡 Настройка беспроводных модулей
📶 Bluetooth (HC-05/ESP32)
Настройка HC-05:
1// AT-команды для настройки HC-05
2void setupBluetooth() {
3 Serial.begin(9600);
4
5 // Вход в режим AT-команд
6 delay(1000);
7
8 // Настройка имени устройства
9 Serial.println("AT+NAME=RobotController");
10 delay(1000);
11
12 // Настройка скорости передачи
13 Serial.println("AT+UART=115200,0,0");
14 delay(1000);
15
16 // Настройка пин-кода
17 Serial.println("AT+PSWD=1234");
18 delay(1000);
19
20 // Роль - ведущий
21 Serial.println("AT+ROLE=1");
22 delay(1000);
23}
ESP32 Bluetooth Classic:
1#include "BluetoothSerial.h"
2
3BluetoothSerial SerialBT;
4
5void setup() {
6 Serial.begin(115200);
7 SerialBT.begin("ESP32_Robot"); // Имя Bluetooth устройства
8 Serial.println("Устройство готово к сопряжению");
9}
10
11void loop() {
12 if (SerialBT.available()) {
13 String command = SerialBT.readString();
14 command.trim();
15
16 Serial.println("Получена команда: " + command);
17 processCommand(command);
18
19 // Отправка подтверждения
20 SerialBT.println("OK:" + command);
21 }
22}
📶 Wi-Fi (ESP32/ESP8266)
Точка доступа (AP режим):
1#include <WiFi.h>
2#include <WebSocketsServer.h>
3
4const char* ssid = "Robot_Control";
5const char* password = "robot123";
6
7WebSocketsServer webSocket = WebSocketsServer(81);
8
9void setup() {
10 Serial.begin(115200);
11
12 // Создание точки доступа
13 WiFi.softAP(ssid, password);
14 Serial.println("AP IP адрес: " + WiFi.softAPIP().toString());
15
16 // Настройка WebSocket
17 webSocket.begin();
18 webSocket.onEvent(webSocketEvent);
19}
20
21void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
22 switch(type) {
23 case WStype_DISCONNECTED:
24 Serial.printf("Клиент [%u] отключен\n", num);
25 break;
26
27 case WStype_CONNECTED:
28 Serial.printf("Клиент [%u] подключен\n", num);
29 break;
30
31 case WStype_TEXT:
32 String command = String((char*)payload);
33 Serial.println("Получена команда: " + command);
34 processCommand(command);
35
36 // Отправка ответа
37 webSocket.sendTXT(num, "OK");
38 break;
39 }
40}
41
42void loop() {
43 webSocket.loop();
44}
📻 Радиомодули (nRF24L01)
Настройка приемника:
1#include <SPI.h>
2#include <nRF24L01.h>
3#include <RF24.h>
4
5RF24 radio(9, 10); // CE, CSN
6const byte address[6] = "Robot1";
7
8struct CommandPacket {
9 char command[10];
10 int param1;
11 int param2;
12 unsigned long timestamp;
13 byte checksum;
14};
15
16void setup() {
17 Serial.begin(9600);
18 radio.begin();
19 radio.openReadingPipe(0, address);
20 radio.setPALevel(RF24_PA_MAX); // Максимальная мощность
21 radio.setDataRate(RF24_250KBPS); // Низкая скорость = больше дальность
22 radio.startListening();
23}
24
25void loop() {
26 if (radio.available()) {
27 CommandPacket packet;
28 radio.read(&packet, sizeof(packet));
29
30 // Проверка целостности
31 if (validateChecksum(packet)) {
32 Serial.println("Команда: " + String(packet.command));
33 executeCommand(packet);
34 } else {
35 Serial.println("Ошибка целостности пакета");
36 }
37 }
38}
39
40bool validateChecksum(CommandPacket& packet) {
41 // Простая проверка контрольной суммы
42 byte calculated = 0;
43 for (int i = 0; i < sizeof(packet) - 1; i++) {
44 calculated ^= ((byte*)&packet)[i];
45 }
46 return calculated == packet.checksum;
47}
🛠️ Практическая работа
📋 Варианты заданий
🟢 Вариант 1: Bluetooth-управление
- Создать Android/iOS приложение
- Настроить HC-05 модуль
- Реализовать виртуальный джойстик
- Добавить кнопки дополнительных функций
🟡 Вариант 2: Wi-Fi веб-интерфейс
- Создать ESP32 точку доступа
- Разработать веб-страницу управления
- Использовать WebSocket для связи
- Добавить видеопоток с камеры
🔴 Вариант 3: Радиопульт
- Собрать физический пульт на Arduino
- Настроить nRF24L01 модули
- Создать эргономичный интерфейс
- Реализовать обратную связь
⏱️ План работы (90 минут)
1Этап 1: Выбор и планирование (10 мин)
2• Выбор типа системы управления
3• Распределение ролей в команде
4• Планирование архитектуры
5
6Этап 2: Настройка связи (15 мин)
7• Подключение беспроводного модуля
8• Настройка параметров связи
9• Тест базового соединения
10
11Этап 3: Программирование пульта (20 мин)
12• Создание интерфейса управления
13• Программирование отправки команд
14• Тестирование элементов управления
15
16Этап 4: Программирование робота (25 мин)
17• Код приема и обработки команд
18• Преобразование команд в действия
19• Обработка ошибок и потери связи
20
21Этап 5: Тестирование и отладка (15 мин)
22• Проверка всех функций
23• Оптимизация параметров
24• Измерение дальности и задержек
25
26Этап 6: Демонстрация (5 мин)
27• Показ работы системы
28• Объяснение реализации
💻 Примеры кода для робота
🤖 Обработка команд движения
1// Универсальная система обработки команд
2class RobotController {
3private:
4 int leftMotorPin1 = 3, leftMotorPin2 = 5;
5 int rightMotorPin1 = 6, rightMotorPin2 = 9;
6 unsigned long lastCommandTime = 0;
7 const unsigned long TIMEOUT = 3000; // 3 секунды
8
9public:
10 void processCommand(String command) {
11 lastCommandTime = millis();
12
13 if (command.startsWith("MOVE:")) {
14 // Формат: MOVE:speed:direction
15 int firstColon = command.indexOf(':');
16 int secondColon = command.indexOf(':', firstColon + 1);
17
18 int speed = command.substring(firstColon + 1, secondColon).toInt();
19 int direction = command.substring(secondColon + 1).toInt();
20
21 move(speed, direction);
22 }
23 else if (command == "STOP") {
24 stop();
25 }
26 else if (command == "LED_ON") {
27 digitalWrite(13, HIGH);
28 }
29 else if (command == "LED_OFF") {
30 digitalWrite(13, LOW);
31 }
32 else if (command.startsWith("SERVO:")) {
33 int angle = command.substring(6).toInt();
34 setServoAngle(angle);
35 }
36 }
37
38 void move(int speed, int direction) {
39 // Преобразование скорости и направления в команды моторам
40 int leftSpeed = speed;
41 int rightSpeed = speed;
42
43 // Коррекция для поворота
44 if (direction < 0) { // Поворот влево
45 leftSpeed = speed * (100 + direction) / 100;
46 } else if (direction > 0) { // Поворот вправо
47 rightSpeed = speed * (100 - direction) / 100;
48 }
49
50 setMotorSpeed(leftMotorPin1, leftMotorPin2, leftSpeed);
51 setMotorSpeed(rightMotorPin1, rightMotorPin2, rightSpeed);
52 }
53
54 void checkTimeout() {
55 if (millis() - lastCommandTime > TIMEOUT) {
56 stop(); // Аварийная остановка при потере связи
57 }
58 }
59};
📊 Система обратной связи
1// Отправка телеметрии
2void sendTelemetry() {
3 StaticJsonDocument<200> telemetry;
4
5 telemetry["battery"] = readBatteryVoltage();
6 telemetry["distance"] = readUltrasonic();
7 telemetry["temperature"] = readTemperature();
8 telemetry["position"]["x"] = robotX;
9 telemetry["position"]["y"] = robotY;
10 telemetry["timestamp"] = millis();
11
12 String output;
13 serializeJson(telemetry, output);
14
15 // Отправка через выбранный канал связи
16 if (bluetoothConnected) {
17 SerialBT.println(output);
18 }
19 if (wifiConnected) {
20 webSocket.broadcastTXT(output);
21 }
22}
23
24float readBatteryVoltage() {
25 int raw = analogRead(A7);
26 return (raw * 5.0 / 1023.0) * 2; // Делитель напряжения
27}
28
29int readUltrasonic() {
30 digitalWrite(trigPin, LOW);
31 delayMicroseconds(2);
32 digitalWrite(trigPin, HIGH);
33 delayMicroseconds(10);
34 digitalWrite(trigPin, LOW);
35
36 long duration = pulseIn(echoPin, HIGH);
37 return duration * 0.034 / 2; // Расстояние в см
38}
🔧 Оптимизация системы
⚡ Повышение надежности
Контроль целостности данных:
1struct SecurePacket {
2 char command[16];
3 int params[4];
4 unsigned long timestamp;
5 uint16_t crc16;
6};
7
8uint16_t calculateCRC16(uint8_t* data, size_t length) {
9 uint16_t crc = 0xFFFF;
10 for (size_t i = 0; i < length; i++) {
11 crc ^= data[i];
12 for (int j = 0; j < 8; j++) {
13 if (crc & 0x0001) {
14 crc = (crc >> 1) ^ 0xA001;
15 } else {
16 crc >>= 1;
17 }
18 }
19 }
20 return crc;
21}
Автоматическое переподключение:
1void maintainConnection() {
2 if (!bluetooth.connected()) {
3 Serial.println("Потеря Bluetooth соединения. Переподключение...");
4 bluetooth.reconnect();
5 }
6
7 if (WiFi.status() != WL_CONNECTED) {
8 Serial.println("Потеря Wi-Fi. Переподключение...");
9 WiFi.reconnect();
10 }
11}
📡 Оптимизация дальности
Настройки для максимальной дальности:
1// nRF24L01 настройки
2radio.setPALevel(RF24_PA_MAX); // Максимальная мощность
3radio.setDataRate(RF24_250KBPS); // Низкая скорость
4radio.setChannel(76); // Свободный канал
5radio.setRetries(15, 15); // Максимум повторов
6radio.enableAckPayload(); // Подтверждение доставки
7radio.enableDynamicPayloads(); // Динамический размер пакета
8
9// ESP32 Wi-Fi настройки
10WiFi.setTxPower(WIFI_POWER_19_5dBm); // Максимальная мощность
11wifi_config_t conf;
12esp_wifi_get_config(WIFI_IF_AP, &conf);
13conf.ap.max_connection = 1; // Один клиент
14esp_wifi_set_config(WIFI_IF_AP, &conf);
🎤 Демонстрация проектов
📊 Защита работ
План презентации (3 минуты на команду):
- Тип системы - какую технологию выбрали?
- Интерфейс - как выглядит пульт управления?
- Функции - что умеет делать робот?
- Демонстрация - показ в действии
- Особенности - уникальные решения
❓ Вопросы для обсуждения:
- Почему выбрана именно эта технология связи?
- Какая дальность действия достигнута?
- Как система ведет себя при помехах?
- Какие функции можно добавить?
🏆 Критерии оценки
📊 Оценочная матрица (20 баллов):
Критерий |
Максимум |
Описание |
Настройка связи |
5 |
Стабильность, дальность, качество |
Программирование пульта |
5 |
Интерфейс, функциональность, эргономика |
Обработка команд |
5 |
Точность, плавность, обработка ошибок |
Общий результат |
5 |
Надежность, демонстрация, творчество |
🎯 Перевод в оценки:
- 18-20: “5” (отлично)
- 14-17: “4” (хорошо)
- 10-13: “3” (удовлетворительно)
🤔 Рефлексия “3-2-1”
📝 Анализ работы
3 вещи, которые удалось реализовать:
-
2 трудности, с которыми столкнулись:
-
1 идея для усовершенствования системы:
Оценка работы группы (1-5): ___
🏠 Домашнее задание
🎯 Основное задание
Разработать схему усовершенствованного пульта:
Создать проект пульта управления с дополнительными функциями:
- Дисплей для отображения телеметрии
- Кнопки быстрого доступа к функциям
- Регулировка чувствительности управления
- Запись и воспроизведение макросов команд
📋 Структура проекта:
- Схема расположения элементов
- Список необходимых компонентов
- Описание функций каждого элемента
- Оценка стоимости реализации
🌟 Исследовательское задание
Изучить обратную связь в системах управления:
- Передача видеопотока с камеры робота
- Телеметрия датчиков в реальном времени
- Тактильная обратная связь (вибрация)
- Звуковая индикация состояния робота
🎉 Итоги урока
🏆 Что освоили
✅ Научились:
- Программировать интерфейсы дистанционного управления
- Настраивать различные типы беспроводной связи
- Создавать системы обработки команд
- Тестировать и оптимизировать управление
🧠 Поняли:
- Программирование пульта требует понимания интерфейсов
- Настройка связи влияет на качество управления
- Обработка команд должна быть надежной и быстрой
- Система управления нуждается в постоянной оптимизации
🌟 Главный принцип
“Хорошая система управления = Интуитивный интерфейс + Надежная связь + Быстрая обработка команд”
🚀 Следующий шаг: Создание автономных роботов с элементами искусственного интеллекта
💡 Теперь вы можете создать пульт для любого робота!