Загрузка данных
ARDUINO IDE CODE:
// --- НАСТРОЙКА ПИНОВ ПО ВАШЕМУ ФОТО ---
const int IN1 = 8;
const int IN2 = 9;
const int IN3 = 10;
const int IN4 = 11;
const int trigPin = 12; // Датчик: Trig
const int echoPin = 13; // Датчик: Echo
// --- ПЕРЕМЕННЫЕ СОСТОЯНИЯ ---
int stepDelay = 3; // Пауза между шагами в мс (чем меньше, тем быстрее крутится)
char mode = 'M'; // Режим: 'M' - ручной, 'A' - автомат
int stepCounter = 0; // Счетчик фаз шагового мотора
// Матрица полношагового режима для ULN2003 (4 шага)
const int steps[4][4] = {
{1, 0, 0, 1},
{1, 1, 0, 0},
{0, 1, 1, 0},
{0, 1, 1, 1}
};
void setup() {
Serial.begin(9600); // Связь с Python
// Конфигурируем выходы на драйвер ULN2003
pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}
// Функция для совершения одного шага в заданном направлении (1 - вправо, -1 - влево)
void moveStep(int dir) {
stepCounter += dir;
if (stepCounter > 3) stepCounter = 0;
if (stepCounter < 0) stepCounter = 3;
digitalWrite(IN1, steps[stepCounter][0]);
digitalWrite(IN2, steps[stepCounter][1]);
digitalWrite(IN3, steps[stepCounter][2]);
digitalWrite(IN4, steps[stepCounter][3]);
delay(stepDelay);
}
// Функция полной остановки мотора (чтобы не грелся)
void stopMotor() {
digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
}
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
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') {
if (cmd == 'U') stepDelay = max(1, stepDelay - 1); // Вверх -> Крутить быстрее (меньше пауза)
if (cmd == 'D') stepDelay = min(10, stepDelay + 1); // Вниз -> Крутить медленнее (больше пауза)
// Шаговый мотор вращается, пока идет поток команд нажатия
if (cmd == 'L') { for(int i=0; i<50; i++) moveStep(-1); stopMotor(); } // Влево -> Вращение против часовой
if (cmd == 'R') { for(int i=0; i<50; i++) moveStep(1); stopMotor(); } // Вправо -> Вращение по часовой
}
}
// 3. ЛОГИКА АВТОМАТИЧЕСКОГО РЕЖИМА
if (mode == 'A') {
if (dist < 30) {
// Препятствие близко: экстренно реверсируем мотор (разворот назад)
stepDelay = 2;
for(int i=0; i<100; i++) moveStep(-1);
stopMotor();
} else {
// Путь свободен: медленно движемся вперед
stepDelay = 5;
moveStep(1);
}
}
delay(10);
}
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()