Как стать автором
Поиск
Написать публикацию
Обновить

Станция обслуживания дрона: управление и архитектура взаимодействия

Уровень сложностиСредний
Время на прочтение5 мин
Количество просмотров474

Станция обслуживания дрона — это комплексный автоматизированный модуль, выполняющий функции замены аккумуляторов и обработки грузов (загрузка/выгрузка) в полностью автономном режиме. Управление ею реализовано с помощью микроконтроллера Arduino Uno, связанного с модулем ESP8266, который подключается к удалённому серверу по WebSocket и обменивается командами в формате JSON.

🔧 Архитектура управления станцией

Станция состоит из нескольких механических компонентов, управляемых шаговыми двигателями и отслеживаемых с помощью концевых датчиков. Управляющая логика разбита на два уровня:

1. Arduino Uno — логика управления станцией

Arduino отвечает за:

  • Поворотную платформу для грузов и аккумуляторов;

  • Подъём/опускание лифта;

  • Фиксацию/освобождение дрона;

  • Механизм загрузки/выгрузки груза;

  • Калибровку всех компонентов;

  • Отправку телеметрии на сервер;

  • Приём JSON-команд через UART от ESP8266 и их выполнение.

Каждый механизм снабжён шаговым двигателем, а его положение контролируется концевыми выключателями. Arduino обрабатывает команды вида:

{ "command": "move_lift", "value": 50, "operation_id": "abc123" }

...и, выполнив их, возвращает результат, например:

{ "type": "operation_result", "success": true, "message": "Lift moved", "operation_id": "abc123" }

Также отправляется телеметрия о текущем состоянии всех систем.

2. ESP8266 — шлюз между сервером и Arduino

ESP8266 подключается к Wi-Fi и устанавливает WebSocket-соединение с сервером. Его роль — посредник:

  • Принимает команды с сервера и передаёт их Arduino через UART.

  • Считывает ответы от Arduino и пересылает обратно на сервер.

  • Автоматически повторно подключается при потере связи.

  • Отвечает на PING-запросы сервера для поддержания heartbeat и передачи общего статуса работы.

3. Сервер управления

Сервер принимает WebSocket-соединения от устройств и предоставляет пользователю веб-интерфейс (временное решение для тестирования). Он:

  • Хранит список зарегистрированных устройств и пользователей.

  • Обеспечивает аутентификацию устройств.

  • Принимает и маршрутизирует команды, отправленные с веб-интерфейса.

  • Обрабатывает телеметрию и ошибки от устройств.

  • Показывает актуальное состояние системы через веб-интерфейс.

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

🔑 Принцип работы в реальном времени

  1. Пользователь отправляет команду через веб-интерфейс сервера.

  2. Сервер отправляет JSON-команду устройству esp02 (станция).

  3. ESP8266 передаёт JSON по UART на Arduino Uno.

  4. Arduino выполняет команду и возвращает JSON-результат.

  5. ESP8266 передаёт результат обратно на сервер.

  6. Сервер отображает результат пользователю.

📊 Пример телеметрии

{
  "type": "telemetry",
  "status": "работает",
  "lift_position": 50,
  "platform_position": 90,
  "is_drone_locked": true,
  "has_cargo": false,
  "is_error": false,
  "last_operation": "Drone locked",
  "switches": [true, false, false, true, false, false, true, false]
}

🧩 Преимущества архитектуры

  • 🔌 Модульность: Arduino Uno отделяет механику от сетевой логики.

  • 🌐 Удалённое управление: весь обмен данными через WebSocket.

  • 🔁 Устойчивость: повторные подключения, heartbeat, обработка ошибок.

  • 🔄 Автоматизация: полностью автоматическое выполнение команд.

Код WIFI модуля

#include <ESP8266WiFi.h>
#include <WebSocketsClient.h>
#include <ArduinoJson.h>

const char* ssid = "ASUS";
const char* password = "123456789098";

WebSocketsClient webSocket;

const char* deviceName = "esp02";
const char* devicePassword = "5678";

const int LED_PIN = LED_BUILTIN;

unsigned long previousMillis = 0;
unsigned long lastConnectionAttempt = 0;
const long connectionInterval = 10000; // 10 секунд между попытками подключения

int ledState = LOW;
int connectionState = 0; // 0 - нет подключения, 1 - WiFi подключен, 2 - WebSocket подключен

void updateLed() {
  unsigned long currentMillis = millis();
  unsigned long interval;
  
  switch(connectionState) {
    case 0: // Нет подключения - быстрое мигание (500ms)
      interval = 500;
      break;
    case 1: // WiFi подключен - медленное мигание (1000ms)
      interval = 1000;
      break;
    case 2: // WebSocket подключен - постоянно включен
      digitalWrite(LED_PIN, LOW);
      return;
  }
  
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    ledState = (ledState == LOW) ? HIGH : LOW;
    digitalWrite(LED_PIN, ledState);
  }
}

void sendToArduino(const String& message) {
  Serial.println(message); // Просто перенаправляем сообщение на Arduino
}

void webSocketEvent(WStype_t type, uint8_t* payload, size_t length) {
  switch (type) {
    case WStype_CONNECTED:
      //Serial.println("[WS] Connected");
      connectionState = 2;  // WebSocket подключен
      updateLed();

      // Отправляем информацию об устройстве при подключении
      {
        StaticJsonDocument<256> doc;
        doc["type"] = "auth";
        doc["name"] = deviceName;
        doc["password"] = devicePassword;
        String json;
        serializeJson(doc, json);
        webSocket.sendTXT(json);
      }
      break;

    case WStype_DISCONNECTED:
      //Serial.println("[WS] Disconnected");
      connectionState = (WiFi.status() == WL_CONNECTED) ? 1 : 0;
      break;

    case WStype_TEXT:
      //Serial.printf("[WS] Received: %s\n", payload);

      // Обработка PING
      if (String((char*)payload) == "PING") {
        StaticJsonDocument<128> doc;
        doc["type"] = "telemetry";
        doc["status"] = "работает";
        String json;
        serializeJson(doc, json);
        webSocket.sendTXT(json);
      }
      // Обработка команды reboot
      else if (String((char*)payload) == "reboot") {
        //Serial.println("Rebooting...");
        ESP.restart();
      }
      // Все остальные сообщения просто перенаправляем на Arduino
      else {
        //Serial.printf("Сообщения отправлено на arduino\n");
        sendToArduino(String((char*)payload));
      }
      break;
  }
}

void checkUART() {
  if (Serial.available() > 0) {
    String received = Serial.readStringUntil('\n');
    received.trim();
    
    if (received.length() > 0) {
     // Serial.printf("Received from Arduino: %s\n", received.c_str());
      
      // Просто перенаправляем полученные данные на сервер
      if (webSocket.isConnected()) {
        webSocket.sendTXT(received);
      }
    }
  }
}

void setup() {
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);
  
  Serial.begin(115200); // Инициализация UART для связи с другим Arduino
  WiFi.begin(ssid, password);
  
  // Начальное состояние - нет подключения
  connectionState = 0;
}

void loop() {
  unsigned long currentMillis = millis();
  
  // Обновляем состояние подключения WiFi
  if (WiFi.status() != WL_CONNECTED) {
    connectionState = 0;
    if (currentMillis - lastConnectionAttempt >= connectionInterval) {
      //Serial.println("Connecting to WiFi...");
      WiFi.begin(ssid, password);
      lastConnectionAttempt = currentMillis;
    }
  } 
  else if (connectionState == 0) {
    connectionState = 1;
    //Serial.println("\nWiFi connected");
    //Serial.print("IP address: ");
    //Serial.println(WiFi.localIP());
  }
  
  updateLed();
  webSocket.loop();
  
  // Если WiFi подключен, но WebSocket еще нет - пытаемся подключиться
  if (WiFi.status() == WL_CONNECTED && !webSocket.isConnected() && 
      currentMillis - lastConnectionAttempt >= connectionInterval) {
    connectionState = 1;
    //Serial.println("Connecting to WebSocket server...");
    webSocket.begin("178.66.182.97", 8765, "/");
    webSocket.onEvent(webSocketEvent);
    webSocket.setReconnectInterval(5000);
    lastConnectionAttempt = currentMillis;
  }
  
  // Проверяем входящие сообщения от Arduino
  checkUART();
  
  delay(10); // Небольшая задержка для стабильности
}
Теги:
Хабы:
+2
Комментарии0

Публикации

Ближайшие события