From 6ffc2e606bb364514ab09ec41f42381c57a466d3 Mon Sep 17 00:00:00 2001 From: drho1y Date: Mon, 6 Jul 2026 18:25:06 +0700 Subject: [PATCH] adding backend script + test program for microcontroller --- arduino_code/Test/.vscode/extensions.json | 10 ++ arduino_code/Test/include/README | 37 +++++++ arduino_code/Test/lib/README | 46 ++++++++ arduino_code/Test/platformio.ini | 19 ++++ arduino_code/Test/src/main.cpp | 129 ++++++++++++++++++++++ arduino_code/Test/test/README | 11 ++ backend_control/create_venv.sh | 6 + backend_control/main.py | 80 ++++++++++++++ kicad/ozon/ozon.kicad_pcb | 2 + kicad/ozon/ozon.kicad_pro | 1 + kicad/ozon/ozon.kicad_sch | 14 +++ {schemes => specification}/mindmap.md | 0 {schemes => specification}/mvp_1.drawio | 0 {schemes => specification}/mvp_1.jpg | Bin {schemes => specification}/mvp_1.md | 0 specification/specification.md | 97 ++++++++++++++++ 16 files changed, 452 insertions(+) create mode 100644 arduino_code/Test/.vscode/extensions.json create mode 100644 arduino_code/Test/include/README create mode 100644 arduino_code/Test/lib/README create mode 100644 arduino_code/Test/platformio.ini create mode 100644 arduino_code/Test/src/main.cpp create mode 100644 arduino_code/Test/test/README create mode 100644 backend_control/create_venv.sh create mode 100644 backend_control/main.py create mode 100644 kicad/ozon/ozon.kicad_pcb create mode 100644 kicad/ozon/ozon.kicad_pro create mode 100644 kicad/ozon/ozon.kicad_sch rename {schemes => specification}/mindmap.md (100%) rename {schemes => specification}/mvp_1.drawio (100%) rename {schemes => specification}/mvp_1.jpg (100%) rename {schemes => specification}/mvp_1.md (100%) create mode 100644 specification/specification.md diff --git a/arduino_code/Test/.vscode/extensions.json b/arduino_code/Test/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/arduino_code/Test/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/arduino_code/Test/include/README b/arduino_code/Test/include/README new file mode 100644 index 0000000..49819c0 --- /dev/null +++ b/arduino_code/Test/include/README @@ -0,0 +1,37 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the convention is to give header files names that end with `.h'. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/arduino_code/Test/lib/README b/arduino_code/Test/lib/README new file mode 100644 index 0000000..9379397 --- /dev/null +++ b/arduino_code/Test/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into the executable file. + +The source code of each library should be placed in a separate directory +("lib/your_library_name/[Code]"). + +For example, see the structure of the following example libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +Example contents of `src/main.c` using Foo and Bar: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +The PlatformIO Library Dependency Finder will find automatically dependent +libraries by scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/arduino_code/Test/platformio.ini b/arduino_code/Test/platformio.ini new file mode 100644 index 0000000..e232c82 --- /dev/null +++ b/arduino_code/Test/platformio.ini @@ -0,0 +1,19 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:upesy_wroom] +platform = espressif32 +board = upesy_wroom +framework = arduino +monitor_speed = 115200 +upload_speed = 921600 +upload_port = /dev/ttyUSB0 +lib_deps = + knolleary/PubSubClient@^2.8 diff --git a/arduino_code/Test/src/main.cpp b/arduino_code/Test/src/main.cpp new file mode 100644 index 0000000..f286429 --- /dev/null +++ b/arduino_code/Test/src/main.cpp @@ -0,0 +1,129 @@ +// arduino_code/Test/src/main.cpp +#include +#include +#include + +// WiFi credentials +const char* ssid = "Home"; +const char* password = "88888888qwE"; + +// MQTT Server details +const char* mqtt_server = "192.168.31.225"; +const char* mqtt_user = "test"; +const char* mqtt_password = "1234"; + +WiFiClient espClient; +PubSubClient client(espClient); + +// Пины для управления TMC2209 +const int DIR_PIN = 18; // Направление +const int STEP_PIN = 19; // Шаг +const int EN_PIN = 21; // Включение (опционально) + +// Переменные для управления +bool motor_running = false; +int step_delay = 1000; // Задержка между шагами (в микросекундах) +int steps_per_second = 1000; // Количество шагов в секунду + +void setup_wifi() { + delay(10); + // Подключение к WiFi + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + } +} + +void startMotor() { + motor_running = true; + Serial.println("Motor started"); +} + +void stopMotor() { + motor_running = false; + Serial.println("Motor stopped"); +} + +void updateStepDelay() { + // Рассчитываем задержку между шагами + step_delay = 1000000 / steps_per_second; +} + +void setSpeed(int speed) { + // Установка скорости в шагах в секунду + if (speed > 0) { + steps_per_second = speed; + updateStepDelay(); + Serial.print("Speed set to: "); + Serial.print(speed); + Serial.println(" steps/sec"); + } +} + +void callback(char* topic, byte* payload, unsigned int length) { + // Обработка команд через MQTT + String message; + for (int i = 0; i < length; i++) { + message += (char)payload[i]; + } + + if (message == "start") { + startMotor(); + } else if (message == "stop") { + stopMotor(); + } else if (message.startsWith("speed:")) { + int speed = message.substring(6).toInt(); + setSpeed(speed); + } else if (message.startsWith("turnoff")) { + digitalWrite(EN_PIN, HIGH); + } else if (message.startsWith("turnon")) { + digitalWrite(EN_PIN, LOW); + } +} + +void reconnect() { + // Повторное подключение к MQTT + while (!client.connected()) { + if (client.connect("ESP32Client", mqtt_user, mqtt_password)) { + client.subscribe("motor/control"); + } else { + delay(5000); + } + } +} + +void setup() { + Serial.begin(115200); + setup_wifi(); + client.setServer(mqtt_server, 1883); + client.setCallback(callback); + + // Настройка пинов + pinMode(DIR_PIN, OUTPUT); + pinMode(STEP_PIN, OUTPUT); + pinMode(EN_PIN, OUTPUT); + + // Включаем двигатель + digitalWrite(EN_PIN, LOW); + + // Начальное направление (вперед) + digitalWrite(DIR_PIN, HIGH); +} + +void loop() { + if (!client.connected()) { + reconnect(); + } + client.loop(); + // Обновляем задержку для правильной скорости + updateStepDelay(); + // Управление двигателем + if (motor_running) { + // Выполняем шаг + digitalWrite(STEP_PIN, HIGH); + delayMicroseconds(step_delay); + digitalWrite(STEP_PIN, LOW); + delayMicroseconds(step_delay); + } +} + diff --git a/arduino_code/Test/test/README b/arduino_code/Test/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/arduino_code/Test/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html diff --git a/backend_control/create_venv.sh b/backend_control/create_venv.sh new file mode 100644 index 0000000..15221ef --- /dev/null +++ b/backend_control/create_venv.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +python -m venv testing + +source testing/bin/activate +pip install paho-mqtt \ No newline at end of file diff --git a/backend_control/main.py b/backend_control/main.py new file mode 100644 index 0000000..deceb63 --- /dev/null +++ b/backend_control/main.py @@ -0,0 +1,80 @@ +# mqtt_motor_control.py +import paho.mqtt.client as mqtt +import time + +# Настройки MQTT +MQTT_BROKER = "192.168.31.225" # Адрес MQTT брокера +MQTT_PORT = 1883 # Порт MQTT +MQTT_USER = "test" # Имя пользователя +MQTT_PASSWORD = "1234" # Пароль +MQTT_TOPIC = "motor/control" # Топик для управления двигателем + +def on_connect(client, userdata, flags, rc): + if rc == 0: + print("Connected to MQTT broker") + else: + print(f"Failed to connect, return code {rc}") + +def send_command(command): + """Отправка команды в MQTT топик""" + client.publish(MQTT_TOPIC, command) + print(f"Sent command: {command}") + +def main(): + # Создание клиента MQTT + global client + client = mqtt.Client() + + # Установка учетных данных + client.username_pw_set(MQTT_USER, MQTT_PASSWORD) + + # Установка функции обратного вызова при подключении + client.on_connect = on_connect + + # Подключение к брокеру + try: + client.connect(MQTT_BROKER, MQTT_PORT, 60) + client.loop_start() # Запуск цикла обработки в отдельном потоке + + print("MQTT Motor Controller") + print("Commands:") + print(" start - запустить двигатель") + print(" stop - остановить двигатель") + print(" turnon - включить управление двигателем") + print(" turnoff - выключить управление двигателем") + print(" speed - установить скорость (например: speed 2000)") + print(" exit - выход") + + while True: + command = input("\nEnter command: ").strip() + + if command == "exit": + break + elif command == "start": + send_command("start") + elif command == "stop": + send_command("stop") + elif command == "turnon": + send_command("turnon") + elif command == "turnoff": + send_command("turnoff") + elif command.startswith("speed "): + try: + speed = int(command.split()[1]) + send_command(f"speed:{speed}") + except ValueError: + print("Invalid speed value. Please enter a number.") + else: + print("Unknown command. Use 'start', 'stop', 'speed ', or 'exit'") + + except KeyboardInterrupt: + print("\nShutting down...") + except Exception as e: + print(f"Error: {e}") + finally: + client.loop_stop() + client.disconnect() + print("Disconnected") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/kicad/ozon/ozon.kicad_pcb b/kicad/ozon/ozon.kicad_pcb new file mode 100644 index 0000000..ccd82d6 --- /dev/null +++ b/kicad/ozon/ozon.kicad_pcb @@ -0,0 +1,2 @@ +(kicad_pcb (version 20260206) (generator "pcbnew") (generator_version "10.0") +) \ No newline at end of file diff --git a/kicad/ozon/ozon.kicad_pro b/kicad/ozon/ozon.kicad_pro new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/kicad/ozon/ozon.kicad_pro @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/kicad/ozon/ozon.kicad_sch b/kicad/ozon/ozon.kicad_sch new file mode 100644 index 0000000..281c21e --- /dev/null +++ b/kicad/ozon/ozon.kicad_sch @@ -0,0 +1,14 @@ +(kicad_sch + (version 20260306) + (generator "eeschema") + (generator_version "10.0") + (uuid 8eb30ef0-8ef0-4108-b9d0-4c3ae489af42) + (paper "A4") + (lib_symbols) + (sheet_instances + (path "/" + (page "1") + ) + ) + (embedded_fonts no) +) \ No newline at end of file diff --git a/schemes/mindmap.md b/specification/mindmap.md similarity index 100% rename from schemes/mindmap.md rename to specification/mindmap.md diff --git a/schemes/mvp_1.drawio b/specification/mvp_1.drawio similarity index 100% rename from schemes/mvp_1.drawio rename to specification/mvp_1.drawio diff --git a/schemes/mvp_1.jpg b/specification/mvp_1.jpg similarity index 100% rename from schemes/mvp_1.jpg rename to specification/mvp_1.jpg diff --git a/schemes/mvp_1.md b/specification/mvp_1.md similarity index 100% rename from schemes/mvp_1.md rename to specification/mvp_1.md diff --git a/specification/specification.md b/specification/specification.md new file mode 100644 index 0000000..9ef3ed6 --- /dev/null +++ b/specification/specification.md @@ -0,0 +1,97 @@ +Привет! Как инженер-конструктор и эксперт по электронике, я с удовольствием помогу тебе спроектировать этот макет. Задача ясна: создаем систему автоматизированной сортировки с точным управлением скоростью и маршрутизацией по высоте. + +Давай разберем твои вопросы по порядку. + +### 1. Выбор двигателя: Шаговый vs Коллекторный + +Для твоей задачи — **максимально точного выдерживания скорости** и управления с микроконтроллера — выбор очевиден. + +| Характеристика | Коллекторный двигатель (DC) | Шаговый двигатель (Stepper) | +| :--- | :--- | :--- | +| **Точность скорости** | Низкая. Скорость зависит от напряжения и нагрузки. Для точности нужен энкодер (обратная связь). | **Высокая**. Скорость задается частотой импульсов. Постоянна при заданной нагрузке. | +| **Управление** | Простое (PWM/ШИМ). | Требует специальный драйвер (например, A4988 или TMC2208). | +| **Пуск/Стоп** | Плавный разгон, сложно точно позиционировать. | **Идеальный**. Можно точно задать количество шагов и мгновенно остановиться. | +| **Крутящий момент** | Высокий на высоких оборотах. | Высокий на низких скоростях (идеально для ленты). | +| **Сложность реализации** | Очень низкая. | Средняя (нужен драйвер и настройка тока). | + +**Мой вердикт:** Используй **шаговый двигатель (например, NEMA 17)**. +Если ты хочешь «выдерживать скорость максимально точно», обычный DC-мотор тебя разочарует: при увеличении веса объекта на ленте скорость будет падать. Шаговый же двигатель будет поддерживать заданный темп, пока не будет достигнут предел его крутящего момента. + +--- + +### 2. Селекторы (Сервоприводы) + +Использование сервоприводов с барьером под 45° — это классическое и эффективное решение для макета. + +**Советы по реализации:** +* **Механика:** Чтобы объект не застревал и не «зажевывался», сделай барьер обтекаемым или используй гладкий пластик/алюминий. +* **Угол:** 45 градусов — оптимально, но убедись, что при срабатывании сервопривод не толкает объект слишком резко, чтобы тот не перевернулся. +* **Логика:** В промышленном подходе, как отмечено в контексте, важно отслеживать «корректность маршрутизации» [1]. Рекомендую добавить в код проверку: действительно ли объект ушел в нужную зону, или произошла ошибка. + +--- + +### 3. Датчик определения высоты + +Для измерения высоты объекта сверху, когда лента движется, тебе подойдут три варианта в зависимости от требуемой точности: + +1. **Ультразвуковой датчик (HC-SR04):** Самый дешевый и популярный. + * *Минус:* Широкий луч (может «цеплять» борта конвейера) и низкая скорость обновления. +2. **ИК-датчик расстояния (Sharp GP2Y0A21YK0F):** Более точный, узкий луч. + * *Минус:* Аналоговый сигнал, чувствителен к цвету объекта (черный поглощает ИК). +3. **Лазерный ToF-датчик (VL53L0X / VL53L1X):** **Мой выбор для этого проекта.** + * *Плюсы:* Измеряет время полета фотона (Time-of-Flight), работает независимо от цвета объекта, очень высокая точность (до миллиметров) и очень узкий луч. + +--- + +### Итоговая архитектура (предложение): + +* **Контроллер:** Arduino (Uno или Mega, если планируешь расширять количество датчиков). +* **Привод ленты:** Шаговый двигатель NEMA 17 $\rightarrow$ Драйвер A4988/TMC2208 $\rightarrow$ Arduino. +* **Сортировка:** 3 $\times$ Сервоприводы SG90 или MG90S (с металлическим редуктором надежнее). +* **Датчик высоты:** VL53L0X (I2C интерфейс). +* **Питание:** Отдельный блок питания 12В для двигателя и 5В для Arduino/сервоприводов (общий минус/земля). + +**Важное замечание из спецификации:** +Не забудь предусмотреть в логике категорию «Не подходит для сортировки» [1]. Если датчик зафиксирует объект, который либо слишком высокий, либо слишком низкий (выходит за допустимые габариты), система должна отправить его в отдельный поток или оставить на ленте до конца [1]. + +Поскольку мы проектируем макет, важно учитывать не только функциональность, но и ограничения, упомянутые в техническом контексте: доступную площадь участка [1], разнообразие форм товаров (включая круглые в сечении) и необходимость бережного обращения с хрупкими или ценными объектами [1]. + + +# Сервоприводы с барьером — это надежный вариант, но в зависимости от того, какие объекты вы будете сортировать, рассмотрите следующие альтернативы: + +### 1. Электромагнитные толкатели (Solenoids) +Вместо плавного поворота барьера, соленоид дает резкий линейный толчок. +* **Плюсы:** Очень высокая скорость срабатывания, компактность [1]. +* **Минусы:** Резкий удар. Если ваши объекты хрупкие, этот вариант **не рекомендуется**, так как он противоречит требованию к «мягкости обращения» [1]. +* **Когда использовать:** Для прочных, тяжелых или однотипных деталей. + +### 2. Откидная платформа (Tipping Platform) +Это участок конвейера, который может наклоняться в сторону или под ним открывается люк. +* **Плюсы:** Позволяет перемещать объекты за счет гравитации. Это один из самых бережных способов перемещения, что важно для ценных или хрупких товаров [1]. +* **Минусы:** Требует более сложной механической интеграции в саму ленту. +* **Когда использовать:** Если приоритетом является сохранность объекта и минимизация механических ударов. + +### 3. Поворотный диск-распределитель (Rotating Disc) +В конце основной ленты устанавливается диск, который поворачивается на определенный угол, направляя объект в один из трех лотков. +* **Плюсы:** Занимает минимум места (оптимально для ограниченной площади участка [1]). Отлично работает с объектами, имеющими круг в сечении [1]. +* **Минусы:** Требует точной синхронизации остановки ленты и поворота диска. +* **Когда использовать:** Если макет должен быть максимально компактным, а объекты имеют схожую форму (например, цилиндры или сферы). + +### 4. Боковой конвейер (Cross-Belt / Diverter) +Это короткий перпендикулярный отрезок ленты, который включается только тогда, когда объект должен быть сброшен в зону. +* **Плюсы:** Самый профессиональный и «мягкий» метод. Идеален для хрупких товаров [1]. +* **Минусы:** Высокая стоимость и сложность (нужно еще 3 маленьких мотора и дополнительные ленты). +* **Когда использовать:** Если вы хотите создать максимально приближенный к реальному промышленному производству макет. + +### Сводная таблица для выбора: + +| Вариант | Бережность (для хрупких [1]) | Компактность (площадь [1]) | Сложность реализации | Работа с круглыми объектами [1] | +| :--- | :--- | :--- | :--- | :--- | +| **Серво-барьер** | Средняя | Высокая | Низкая | Хорошо | +| **Соленоид** | Низкая | Очень высокая | Низкая | Средне | +| **Платформа** | Высокая | Средняя | Средняя | Хорошо | +| **Диск** | Средняя | Очень высокая | Средняя | Идеально | +| **Боковой конвейер**| Очень высокая | Низкая | Высокая | Хорошо | + +**Моя рекомендация:** +Если вы хотите сохранить простоту управления через Arduino, но при этом учесть требования к бережности и компактности [1], я рекомендую остаться на **сервоприводах**, но изменить конструкцию барьера: вместо «толкателя» сделать **«поворотный желоб»** или **«шлюз»**. Это позволит объекту плавно скатываться в нужную зону, не подвергаясь резким ударам. \ No newline at end of file