adding backend script + test program for microcontroller
This commit is contained in:
10
arduino_code/Test/.vscode/extensions.json
vendored
Normal file
10
arduino_code/Test/.vscode/extensions.json
vendored
Normal file
@@ -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"
|
||||
]
|
||||
}
|
||||
37
arduino_code/Test/include/README
Normal file
37
arduino_code/Test/include/README
Normal file
@@ -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
|
||||
46
arduino_code/Test/lib/README
Normal file
46
arduino_code/Test/lib/README
Normal file
@@ -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 <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
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
|
||||
19
arduino_code/Test/platformio.ini
Normal file
19
arduino_code/Test/platformio.ini
Normal file
@@ -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
|
||||
129
arduino_code/Test/src/main.cpp
Normal file
129
arduino_code/Test/src/main.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
// arduino_code/Test/src/main.cpp
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <PubSubClient.h>
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
11
arduino_code/Test/test/README
Normal file
11
arduino_code/Test/test/README
Normal file
@@ -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
|
||||
6
backend_control/create_venv.sh
Normal file
6
backend_control/create_venv.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
python -m venv testing
|
||||
|
||||
source testing/bin/activate
|
||||
pip install paho-mqtt
|
||||
80
backend_control/main.py
Normal file
80
backend_control/main.py
Normal file
@@ -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 <value> - установить скорость (например: 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 <value>', 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()
|
||||
2
kicad/ozon/ozon.kicad_pcb
Normal file
2
kicad/ozon/ozon.kicad_pcb
Normal file
@@ -0,0 +1,2 @@
|
||||
(kicad_pcb (version 20260206) (generator "pcbnew") (generator_version "10.0")
|
||||
)
|
||||
1
kicad/ozon/ozon.kicad_pro
Normal file
1
kicad/ozon/ozon.kicad_pro
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
14
kicad/ozon/ozon.kicad_sch
Normal file
14
kicad/ozon/ozon.kicad_sch
Normal file
@@ -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)
|
||||
)
|
||||
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
97
specification/specification.md
Normal file
97
specification/specification.md
Normal file
@@ -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], я рекомендую остаться на **сервоприводах**, но изменить конструкцию барьера: вместо «толкателя» сделать **«поворотный желоб»** или **«шлюз»**. Это позволит объекту плавно скатываться в нужную зону, не подвергаясь резким ударам.
|
||||
Reference in New Issue
Block a user