Загрузка данных


PYTHON CODE:

import os, sys, serial
import tkinter as tk

# --- АВТОПОЧИНКА ОШИБКИ ОКНА (TclError) ---
tcl_dir = r"C:\Users\User\AppData\Local\Programs\Python\Python313\tcl"
os.environ['TCL_LIBRARY'] = os.path.join(tcl_dir, "tcl8.6")
os.environ['TK_LIBRARY'] = os.path.join(tcl_dir, "tk8.6")

# --- ПОДКЛЮЧЕНИЕ ---
port = 'COM3'  # Замените на актуальный порт вашей платы Arduino
try: ser = serial.Serial(port, 9600, timeout=0.01)
except Exception: ser = None

def send(cmd):
    if ser: ser.write(cmd.encode())
    else: print(f"[Демо] Отправлено: {cmd}")

def update_dist():
    if ser:
        while ser.in_waiting:
            try:
                line = ser.readline().decode().strip()
                if line.startswith("DIST:"):
                    # Исправлено: берем только числовую часть после двоеточия
                    dist_value = line.split(":")[1]
                    dist_label.config(text=f"{dist_value} см")
            except Exception: pass
    root.after(50, update_dist)

root = tk.Tk()
root.title("Управление дроном"); root.geometry("340x440")

# --- ЗАГРУЗКА ВАШИХ КАРТИНОК ИЗ ПАПКИ ---
def load_img(name):
    return tk.PhotoImage(file=name) if os.path.exists(name) else None

img_L = load_img("BCleft.png")      # Разворот влево
img_R = load_img("BCright.png")     # Разворот вправо
img_D = load_img("BCbottom.png")    # Снижение (Вниз)
img_U = load_img("BCvertical.png")  # Взлет (Вверх)

# --- ИНТЕРФЕЙС GUI ---
tk.Label(root, text="Расстояние:").pack(pady=(10,0))
dist_label = tk.Label(root, text="0 см", font=("Arial", 20)); dist_label.pack()

mode_frame = tk.Frame(root); mode_frame.pack(pady=10)
tk.Button(mode_frame, text="Ручной", command=lambda: [send('M'), status.config(text="Ручной", fg="blue")], width=10).pack(side="left", padx=5)
tk.Button(mode_frame, text="Автомат", command=lambda: [send('A'), status.config(text="Автомат", fg="green")], width=10).pack(side="left", padx=5)
status = tk.Label(root, text="Ручной", fg="blue"); status.pack()

# --- КРЕСТОВИНА ДЖОЙСТИКА (4 НАПРАВЛЕНИЯ) ---
btn_frame = tk.Frame(root); btn_frame.pack(pady=20)

def create_btn(row, col, txt, cmd, img):
    btn = tk.Button(btn_frame, command=lambda: send(cmd))
    if img: btn.config(image=img)
    else: btn.config(text=txt, width=8, height=2)
    btn.grid(row=row, column=col, padx=5, pady=5)

# Распределение кнопок строго по вашему техническому заданию
create_btn(0, 1, "Набор высоты",  'U', img_U)  # Верхняя кнопка (Вверх)
create_btn(1, 0, "Разворот Лев", 'L', img_L)  # Левая кнопка (Влево)
create_btn(1, 2, "Разворот Пр",  'R', img_R)  # Правая кнопка (Вправо)
create_btn(2, 1, "Снижение",     'D', img_D)  # Нижняя кнопка (Вниз)

root.after(100, update_dist)
root.mainloop()

ARDUINO IDE CODE:

#include <Servo.h>

// --- НАСТРОЙКА ПИНОВ И ПЕРИФЕРИИ ---
Servo servoYaw;          // Сервопривод для разворота влево/вправо

const int motorPin = 5;  // Пин главного мотора (набор/уменьшение высоты)
const int trigPin = 12;  // Датчик: пин отправки сигнала Trig
const int echoPin = 13;  // Датчик: пин приема сигнала Echo

// --- ПЕРЕМЕННЫЕ СОСТОЯНИЯ ---
int motorSpeed = 150;    // Стартовая скорость мотора (высота)
int yaw = 90;            // Стартовый угол разворота (прямо)
char mode = 'M';         // Стартовый режим: 'M' - ручной, 'A' - автомат

void setup() {
  Serial.begin(9600);    // Открываем связь с Python
  
  servoYaw.attach(9);     // Сервопривод разворота на Pin 9
  pinMode(motorPin, OUTPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  
  // Устанавливаем начальное состояние взлета
  servoYaw.write(yaw);
  analogWrite(motorPin, motorSpeed);
}

void loop() {
  // 1. Измерение расстояния ультразвуковым датчиком
  digitalWrite(trigPin, LOW);  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH); delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  long duration = pulseIn(echoPin, HIGH);
  int dist = constrain(duration * 0.034 / 2, 0, 150);
  
  // Отправка телеметрии в Python-приложение (строго в формате DIST:число)
  Serial.print("DIST:");
  Serial.println(dist);

  // 2. Обработка команд от Python приложения
  if (Serial.available() > 0) {
    char cmd = Serial.read();
    
    // Переключение режимов
    if (cmd == 'M') mode = 'M';
    if (cmd == 'A') mode = 'A';
    
    // ЛОГИКА РУЧНОГО УПРАВЛЕНИЯ
    if (mode == 'M') {
      switch (cmd) {
        case 'U': motorSpeed = min(255, motorSpeed + 20); break; // Вверх -> Набор высоты (газ +)
        case 'D': motorSpeed = max(0,   motorSpeed - 20); break; // Вниз -> Снижение высоты (газ -)
        case 'L': yaw        = max(0,   yaw - 15);        break; // Влево -> Разворот влево
        case 'R': yaw        = min(180, yaw + 15);        break; // Вправо -> Разворот вправо
      }
      // Мгновенно применяем команды ручного управления
      servoYaw.write(yaw);
      analogWrite(motorPin, motorSpeed);
    }
  }

  // 3. ЛОГИКА АВТОМАТИЧЕСКОГО РЕЖИМА
  if (mode == 'A') {
    if (dist < 30) {
      // Препятствие ближе 30 см: экстренно набираем высоту и разворачиваемся
      analogWrite(motorPin, 220); 
      servoYaw.write(135);        
    } else {
      // Путь свободен: летим на стабильной высоте и прямо
      analogWrite(motorPin, 150); 
      servoYaw.write(90);         
    }
  }

  delay(50); // Частота работы цикла (20 раз в секунду)
}