Compare commits

..

118 Commits

Author SHA1 Message Date
Kseninia Mikhaylova 0b55d0a050 pallet pos 2024-12-17 15:26:25 +03:00
Kseninia Mikhaylova e4742efa86 model 2024-12-17 14:14:02 +03:00
Kseninia Mikhaylova ee27e79958 small urdf 2024-12-17 09:55:01 +03:00
Kseninia Mikhaylova de6c3bc657 readme 2024-12-16 13:17:25 +03:00
Kseninia Mikhaylova 410f22e5ba pallete 2024-12-16 13:13:19 +03:00
Kseninia Mikhaylova b00e8d46b2 pack lib 2024-12-16 11:25:40 +03:00
Kseninia Mikhaylova 10544e4308 normal loop 2024-12-16 10:00:22 +03:00
Kseninia Mikhaylova 5a0ef0082c loop 2024-12-13 16:54:40 +03:00
Kseninia Mikhaylova 2e439b0390 conv pos 2024-12-13 16:32:54 +03:00
Kseninia Mikhaylova b82ebbd9fb pallet 2024-12-13 16:27:27 +03:00
Kseninia Mikhaylova fbd148ed31 pick 2024-12-13 16:00:40 +03:00
Kseninia Mikhaylova dacbe2ec74 wall pos 2024-12-13 15:51:55 +03:00
Kseninia Mikhaylova 72a5eb2bbd conv pos 2024-12-13 15:43:53 +03:00
Kseninia Mikhaylova 1e4a30f911 constraint pos 2024-12-13 14:41:18 +03:00
user 23dc112f2a build exe 2024-12-13 10:47:49 +03:00
Kseninia Mikhaylova b94d7ab1e5 exp 2024-12-13 10:36:18 +03:00
Kseninia Mikhaylova cf2b7fe493 export coord to robot 2024-12-13 09:27:19 +03:00
Kseninia Mikhaylova 1ede0084f0 pick obj part 2024-12-12 16:58:39 +03:00
Kseninia Mikhaylova 82a8d9c480 remove world coord 2024-12-12 14:02:43 +03:00
Kseninia Mikhaylova d12288edb3 conv stopped flag 2024-12-12 12:56:46 +03:00
Kseninia Mikhaylova c92b603175 conv visualize 2024-12-12 12:47:50 +03:00
Kseninia Mikhaylova 44bf3a2639 load pallete pos 2024-12-12 12:32:45 +03:00
Kseninia Mikhaylova 31d1aff906 conv visualize 2024-12-12 11:50:09 +03:00
Kseninia Mikhaylova 886a9d0e5a palletizing btn 2024-12-11 16:57:13 +03:00
Kseninia Mikhaylova 4f1f7bfa16 add pallette 2024-12-11 13:58:25 +03:00
Kseninia Mikhaylova ac6b2e4e03 log 2024-12-11 11:08:42 +03:00
user 47d96dbc90 angle 2024-12-10 15:14:22 +03:00
user 1f02ad90d0 angle 2024-12-10 12:41:44 +03:00
Kseninia Mikhaylova 0433892eb6 filename 2024-12-02 14:41:33 +03:00
Kseninia Mikhaylova e40bbb7c5a new viz 2024-12-02 13:34:59 +03:00
aarizona 813e5de7c2 with tool visual urdf part 2024-11-25 15:53:22 +03:00
aarizona 1c9fb3fe8e part of visual fixing 2024-11-25 15:41:49 +03:00
aarizona 77ede646ab fixed joint in urdf 2024-11-25 12:04:54 +03:00
aarizona 3119951879 test tool 2024-11-22 16:48:08 +03:00
aarizona c59d7f1e54 imitate test 2024-11-22 10:26:38 +03:00
aarizona 5ec07195f6 no coord stop 2024-11-22 10:16:24 +03:00
aarizona 0f6fa7ed89 cmd len refactor 2024-11-22 10:10:39 +03:00
aarizona 695ae8ed1d axis refactor 2024-11-22 09:44:47 +03:00
aarizona 2c00a21415 some refactor 2024-11-22 08:58:55 +03:00
aarizona 6708978141 urdf for rviz test 2024-11-21 19:47:12 +03:00
aarizona 8b05ef6852 working model 2024-11-21 11:39:43 +03:00
aarizona bc0672d6f8 model fix 2024-11-21 10:10:49 +03:00
Kseninia Mikhaylova a2059f72ba test model 2024-11-20 17:59:32 +03:00
user a992e30bba logs 2024-11-20 16:03:25 +03:00
user 8ec738bbff logs 2024-11-20 16:02:42 +03:00
Kseninia Mikhaylova 93d7fe77b1 test euler coord 2024-11-20 09:49:06 +03:00
Kseninia Mikhaylova 7a2dcc70ab test world position 2024-11-20 09:29:54 +03:00
Kseninia Mikhaylova ef9d167f7e rename axis 2024-11-20 08:53:31 +03:00
Kseninia Mikhaylova f500bfcd6e radians fix 2024-11-19 17:00:17 +03:00
user 065284106c test joint coordinates 2024-11-19 09:01:33 +03:00
Kseninia Mikhaylova 865f8fe1b4 test 2024-11-15 16:55:08 +03:00
Kseninia Mikhaylova 3022f1b6b7 model test 2024-11-15 15:59:41 +03:00
Kseninia Mikhaylova c2f0343f0c [200~pybullet_industrial~ 2024-11-13 16:52:31 +03:00
Kseninia Mikhaylova ba0e6ea657 model fix 2024-11-13 13:26:22 +03:00
Kseninia Mikhaylova e50ec6c17d appliction path 2024-11-13 09:46:49 +03:00
user cf9532d5dd win build 2024-11-12 11:47:21 +03:00
user 4bb8c649d9 app path 2024-11-12 11:22:11 +03:00
user 330bc6d87c viz test 2024-11-12 09:52:33 +03:00
Kseninia Mikhaylova a690d34d99 test terminate process 2024-11-12 09:34:13 +03:00
Kseninia Mikhaylova 6048a54b38 fix shell 2024-11-12 09:17:28 +03:00
user 47878d37a8 upd data 2024-11-12 09:06:33 +03:00
user 012b01299a test 2024-11-12 09:03:54 +03:00
user 7d807f17d7 Merge branch 'urdf' of https://git.svs-tech.pro/ksenia_mikhailova/modbus_test into urdf 2024-11-12 08:49:28 +03:00
user ddd3d855f5 test 2024-11-12 08:48:54 +03:00
Kseninia Mikhaylova 4b989a76d4 ver 2024-11-12 08:44:33 +03:00
user a6f60083c5 poetry 2024-11-11 18:51:58 +03:00
user eb73098984 poetry path 2024-11-11 13:46:33 +03:00
user 5c78df12e8 win adaptation 2024-11-11 12:10:03 +03:00
Kseninia Mikhaylova 27f5a51ed6 pyqt6 2024-11-11 11:27:41 +03:00
aarizona bc1d21ac22 Ref 2024-11-01 12:58:41 +03:00
aarizona 41f99d7636 imitate 2024-11-01 11:56:43 +03:00
Kseninia Mikhaylova 566285b400 model 2024-10-31 15:48:19 +03:00
Kseninia Mikhaylova 51f45f634f work model 2024-10-31 15:24:14 +03:00
Kseninia Mikhaylova d75007d604 model 2024-10-31 11:39:56 +03:00
aarizona fc319d757e test 2024-10-30 17:02:11 +03:00
aarizona 754256ee96 test app 2024-10-30 16:57:03 +03:00
aarizona 9a0f836d62 test model 2024-10-30 16:55:39 +03:00
Kseninia Mikhaylova 3aa4d6b3ea remove zip 2024-10-30 12:59:49 +03:00
Kseninia Mikhaylova 12dc688dcd build spec 2024-10-30 12:48:12 +03:00
Kseninia Mikhaylova 85aa58a12a mode 2024-10-29 16:46:52 +03:00
Kseninia Mikhaylova bd8dbcfa05 decorator 2024-10-29 16:06:07 +03:00
Kseninia Mikhaylova 79b69cfffa joint 2024-10-29 15:52:04 +03:00
Kseninia Mikhaylova 37a2a725d5 joint 2024-10-29 15:36:18 +03:00
Kseninia Mikhaylova ca0d3c07b8 norm intervals 2024-10-29 14:52:59 +03:00
Kseninia Mikhaylova f5ecc08fde imitator 2024-10-29 13:35:06 +03:00
Kseninia Mikhaylova 9f8706e036 gui 2024-10-29 11:53:37 +03:00
Kseninia Mikhaylova 6a35a25a5b shell script 2024-10-29 10:06:18 +03:00
Kseninia Mikhaylova 28a15ab61e size 2024-10-29 09:50:37 +03:00
Kseninia Mikhaylova e5ecf4c3ec work in process 2024-10-29 09:20:41 +03:00
Kseninia Mikhaylova baac2d138c part of load file 2024-10-28 16:59:01 +03:00
Kseninia Mikhaylova 775395e9ec hmmm 2024-10-28 15:19:13 +03:00
Kseninia Mikhaylova d7f1edce9c it move 2024-10-28 13:33:53 +03:00
Kseninia Mikhaylova aad39b5736 vis start 2024-10-25 16:58:38 +03:00
Kseninia Mikhaylova 233417c50b start imitate 2024-10-25 11:29:20 +03:00
Kseninia Mikhaylova b1d10fe3b1 observable connect 2024-10-25 10:55:03 +03:00
Kseninia Mikhaylova 24b88da023 imitator tab 2024-10-15 16:55:25 +03:00
Kseninia Mikhaylova ccc97c6529 imitator tab 2024-10-15 16:55:07 +03:00
Kseninia Mikhaylova a35ef4a153 status 2024-10-15 15:19:34 +03:00
Kseninia Mikhaylova b906a1a04c set enabled radio 2024-10-15 15:17:25 +03:00
Kseninia Mikhaylova d9305bd88e moving 2024-10-15 15:07:14 +03:00
Kseninia Mikhaylova 8e7be135b4 qt gui 2024-10-15 10:25:29 +03:00
Kseninia Mikhaylova e32ed18dfb qt gui 2024-10-15 10:17:39 +03:00
Kseninia Mikhaylova de92e54a6c qt test 2024-10-15 10:07:04 +03:00
Kseninia Mikhaylova 69f2fd810d status panel 2024-10-15 09:23:59 +03:00
Kseninia Mikhaylova 81761e7fbb connect 2024-10-14 17:20:31 +03:00
Kseninia Mikhaylova 8babbd50f5 robot panel 2024-10-14 14:55:07 +03:00
Kseninia Mikhaylova 3a101821b7 test gui 2024-10-14 13:50:28 +03:00
aarizona 4b04411c20 work ok 2024-10-11 14:27:05 +03:00
aarizona fa776c91d2 upd model 2024-10-11 13:07:07 +03:00
Kseninia Mikhaylova 3355c37bd5 AHAHA 2024-10-11 11:46:51 +03:00
Kseninia Mikhaylova 96fe6de6ba Merge branch 'urdf' of https://git.svs-tech.pro/ksenia_mikhailova/modbus_test into urdf 2024-10-10 16:37:05 +03:00
Kseninia Mikhaylova f3bb5bd8fc test el 2024-10-10 16:35:50 +03:00
Kseninia Mikhaylova 0dd0b01744 sample urdf 2024-10-10 15:59:44 +03:00
aarizona 00f29fac2b hexa 2024-10-08 15:37:44 +03:00
Kseninia Mikhaylova 73e784bdb6 heregit add .git add . 2024-10-08 11:46:16 +03:00
Kseninia Mikhaylova 461364821d base viz 2024-10-01 16:23:09 +03:00
Kseninia Mikhaylova b58db72f74 format 2024-10-01 12:32:20 +03:00
Kseninia Mikhaylova 3bea136c0c test mode 2024-10-01 12:15:19 +03:00
70 changed files with 4427 additions and 27203 deletions

7
.gitignore vendored
View File

@ -2,4 +2,9 @@ __pycache__/
.venv/ .venv/
.vscode/ .vscode/
build/ build/
dist/ data/*
/dist/**/*
dist.zip
.venv
*.log
log/*

16
README.md Normal file
View File

@ -0,0 +1,16 @@
## Работа с роботом
### Окружение
* Запустить сокет сервер - для теста
* Запустить pybullet сервер - визуализация в отдельном ПРОЦЕССЕ
* Запустить gui
### Локальный запуск
* `poetry install`
* Запустить в отдельном окне тестовый сокет `poetry run python utils/test_socket_server.py`
* Запустить программу с визуализацией в отдельном окне `poetry run python ru.py --start-py --bullet-gui`
### На чем работает
* Визуализация и расчет положения робота - pybullet
* Паллетизация py3dbp
* Отправка данных по сокету `robot/socket_manager.py` и подготовка данных в нужном формате `robot/prepare_data.py`

0
__init__.py Normal file
View File

View File

@ -1,230 +0,0 @@
import socket
import json
import sys
from pprint import pprint
import tkinter
from func import *
class SocketRobotArm:
line_speed = 100.0
line_smooth = 9
line_tool = 1
global_speed = 100
physical_speed = 50
# laser_id = 15
laser_id = 14
# filename = 'half-sphere-no-angle'
filename = "half-sphere"
pass_size = 4
def __init__(self, *args, **kwargs):
self.socket = socket.socket()
self.host = MODBUS_SERVER_HOST
self.port = 9760
# self.host = "127.0.0.1"
# self.port = 65432
self.tkinter_root = tkinter.Tk()
self.connect()
def __exit__(self, exc_type, exc_value, traceback):
self.socket.close()
def close(self):
self.socket.close()
self.tkinter_root.destroy()
sys.exit()
def set_text(self, text):
label = tkinter.Label(self.tkinter_root, text=text)
label.pack()
self.tkinter_root.update()
def connect(self):
self.socket.connect((self.host, self.port))
self.tkinter_root.geometry("500x300")
self.get_axis()
self.set_text(text=f"Координаты осей {self.start_axis_coordinates}")
self.get_world()
self.set_text( text=f"Мировые координаты {self.start_world_coordinates}")
self.get_command_count()
self.set_text( text=f"Команд в очереди {self.remote_command_count}")
self.send_data(self.set_global_speed())
self.set_text( text=f"Установили глобальную скорость {self.global_speed}")
self.send_data(self.start_cycle())
self.set_text( text=f"Старт одиночного цикла")
self.add_rcc_list = (
[self.set_physical_speed(True), self.set_output_laser(True)]
+ self.steps_from_file()
+ [self.set_physical_speed(False), self.set_output_laser(False)]
)
my_label = tkinter.Label(self.tkinter_root, text=f"Отправка данных")
my_label.pack()
self.tkinter_root.update()
exit_button = tkinter.Button(self.tkinter_root, text="Exit", command=self.close)
exit_button.pack(pady=20)
step = 2
for i in range(0, len(self.add_rcc_list), step):
print(f"Отправка данных {i}...{i+step-1}")
# self.update_text(m, text=f"Отправка данных {i}...{i+step-1}")
my_label.config(text=f"Отправка данных {i}...{i+step-1}")
self.tkinter_root.update()
self.send_data(
make_addrcc_data(self.add_rcc_list[i : i + step], int(not i))
)
time.sleep(0.5)
def send_data(self, data):
response = None
# if data["reqType"] == "AddRCC":
# return
self.socket.send(str.encode(json.dumps(data)))
response_data = self.socket.recv(1024)
response = json.loads(response_data)
if data["reqType"] == "query":
return response["queryData"]
elif data["reqType"] == "command":
return response["cmdReply"]
elif data["reqType"] == "AddRCC" and "cmdReply" in response.keys():
return response["cmdReply"]
else:
pprint(response)
def get_axis(self):
axis_coord_raw = self.send_data(
make_query_data(
["axis-0", "axis-1", "axis-2", "axis-3", "axis-4", "axis-5"]
)
)
self.start_axis_coordinates = [float(i) for i in axis_coord_raw]
print("start_axis_coordinates", self.start_axis_coordinates)
def get_world(self):
world_coord_raw = self.send_data(
make_query_data(
["world-0", "world-1", "world-2", "world-3", "world-4", "world-5"]
)
)
self.start_world_coordinates = [float(i) for i in world_coord_raw]
print("start_world_coordinates", self.start_world_coordinates)
def get_command_count(self):
res = self.send_data(make_query_data(["RemoteCmdLen"]))
self.remote_command_count = res
print(res)
def set_global_speed(self):
# Изменили глобальную скорость на global_speed%
return make_command_data(["modifyGSPD", str(self.global_speed * 10)])
def start_cycle(self):
return make_command_data(["actionSingleCycle"])
def round(v):
return round(v, 3)
def make_world_step(self, type, point):
step = {
"oneshot": "0",
"delay": "0.0",
"speed": str(self.line_speed),
"smooth": str(self.line_smooth),
"coord": "0",
"tool": str(self.line_tool),
"ckStatus": "0x3F",
}
if type == "line":
pairs = zip(self.start_world_coordinates, point)
m0, m1, m2, m3, m4, m5 = [round(sum(i), 3) for i in pairs]
step.update({"action": "10"})
step.update({"m0": m0, "m1": m1, "m2": m2, "m3": m3, "m4": m4, "m5": m5})
step.update({"m6": 0, "m7": 0})
elif type == "curve":
pairs = zip(self.start_world_coordinates, point[:5])
m0, m1, m2, m3, m4, m5 = [round(sum(i), 3) for i in pairs]
pairs_p = zip(self.start_world_coordinates, point[6:])
m0_p, m1_p, m2_p, m3_p, m4_p, m5_p = [round(sum(i), 3) for i in pairs_p]
step.update({"action": "17"})
step.update({"m0": m0, "m1": m1, "m2": m2, "m3": m3, "m4": m4, "m5": m5})
step.update({"m6": 0, "m7": 0})
step.update(
{
"m0_p": m0_p,
"m1_p": m1_p,
"m2_p": m2_p,
"m3_p": m3_p,
"m4_p": m4_p,
"m5_p": m5_p,
}
)
step.update({"m6_p": 0, "m7_p": 0})
for s in step:
step[s] = str(step[s])
return step
def set_physical_speed(self, status: bool = False):
return (
{
"oneshot": "0",
"action": "51",
"isUse": str(int(status)),
"speed": str(self.physical_speed * 1000),
},
)
def set_output_laser(self, status: bool = False):
return (
{
"oneshot": "0",
"action": "200",
"type": "0",
"io_status": str(int(status)),
"point": str(self.laser_id),
},
)
def steps_from_file(self):
result = []
with open(f"data/{self.filename}.nc.result", "r") as fp:
for line in fp:
data = line.strip().split(" ")
prep = {}
for item in data:
prep[item[:1]] = float(item[1:])
result.append(
self.make_world_step(
"line",
(
prep.get("X", 0),
prep.get("Y", 0),
prep.get("Z", 0),
prep.get("U", 0),
prep.get("V", 0),
prep.get("W", 0),
),
)
)
return result
SocketRobotArm()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

11
data/test.nc.result Normal file
View File

@ -0,0 +1,11 @@
X0 Y0 Z0
X-300 Y0 Z0
X-300 Y-300 Z0
X0 Y-300 Z0
X0 Y0 Z0
X0 Y0 Z300
X-300 Y0 Z300
X-300 Y-300 Z300
X0 Y-300 Z300
X0 Y0 Z300
X0 Y0 Z0

0
delta.json Normal file
View File

55
gui/command.py Normal file
View File

@ -0,0 +1,55 @@
from PyQt6.QtWidgets import QWidget, QLabel, QVBoxLayout, QPushButton
from PyQt6.QtCore import QTimer, Qt
import time
from logger import logger
class Command(QWidget):
def __init__(self, startCommand, changeType, command_data, command_type):
super().__init__()
self.command_data = command_data
self.command_type = command_type
self.startCommand = startCommand
self.changeType = changeType
self.initUI()
self.timer = QTimer()
self.timer.timeout.connect(self.updateState)
self.timer.start(int(100))
def initUI(self):
self.layout = QVBoxLayout()
self.setLayout(self.layout)
self.stepLabel = QLabel(text="Загрузка данных")
self.commandLabel = QLabel(text="Тип загрузки")
for l in [self.commandLabel, self.stepLabel]:
l.setWordWrap(True)
self.layout.addWidget(l)
self.updButton = QPushButton("Запустить single cycle")
self.updButton.clicked.connect(self.startCommand)
self.layout.addWidget(self.updButton)
self.chgButton = QPushButton("Изменить тип")
cur_types = ["base", "calc", "pallette"]
self.chgButton.clicked.connect(
lambda: self.changeType(
cur_types[(cur_types.index(self.command_type()) + 1) % len(cur_types)]
)
)
self.layout.addWidget(self.chgButton)
def paintEvent(self, event):
# Установка цвета фона
self.setAutoFillBackground(True)
p = self.palette()
p.setColor(self.backgroundRole(), Qt.GlobalColor.lightGray)
self.setPalette(p)
def updateState(self):
self.stepLabel.setText(f"{self.command_data()}")
self.commandLabel.setText(f"Тип загрузки {self.command_type()}")

55
gui/filename.py Normal file
View File

@ -0,0 +1,55 @@
import time
from PyQt6.QtWidgets import (
QWidget,
QVBoxLayout,
QLabel,
QRadioButton,
QPushButton,
QButtonGroup,
)
from PyQt6.QtCore import Qt, QTimer
from logger import logger
class ChangeFile(QWidget):
def __init__(self, files, getFilename, setFilename):
super().__init__()
self.files = files or []
self.getFilename = getFilename
self.setFilename = setFilename
self.initUI()
self.old_status = None
self.counter = 0
def initUI(self):
self.layout = QVBoxLayout()
self.fileLabel = QLabel("Выберите файл")
self.layout.addWidget(self.fileLabel)
self.buttonGroup = QButtonGroup(self)
self.fileRadio = []
for i, r in enumerate(self.files):
radioButton = QRadioButton(r)
self.buttonGroup.addButton(radioButton, i)
self.fileRadio.append(radioButton)
self.layout.addWidget(radioButton)
self.setButton = QPushButton("Указать")
self.setButton.clicked.connect(self.setFilenameFunc)
self.layout.addWidget(self.setButton)
self.setLayout(self.layout)
def setFilenameFunc(self):
selectedId = self.buttonGroup.checkedId()
v = self.files[selectedId].split('.')[0]
self.setFilename(v)
def paintEvent(self, event):
p = self.palette()
p.setColor(self.backgroundRole(), Qt.GlobalColor.lightGray)
self.setPalette(p)
super().paintEvent(event)

42
gui/imitator.py Normal file
View File

@ -0,0 +1,42 @@
from PyQt6.QtWidgets import QWidget, QLabel, QVBoxLayout, QPushButton
from PyQt6.QtCore import QTimer, Qt
import time
from logger import logger
class Imitator(QWidget):
def __init__(self, startImitate, imitate_point):
super().__init__()
self.imitate_point = imitate_point
self.startImitate = startImitate
self.initUI()
self.timer = QTimer()
self.timer.timeout.connect(self.updateState)
self.timer.start(int(100))
def initUI(self):
self.layout = QVBoxLayout()
self.setLayout(self.layout)
self.stepLabel = QLabel(f"Отправлено шагов {0}")
for l in [self.stepLabel]:
l.setWordWrap(True)
self.layout.addWidget(l)
self.updButton = QPushButton("Запустить имитацию")
self.updButton.clicked.connect(self.startImitate)
self.layout.addWidget(self.updButton)
def paintEvent(self, event):
# Установка цвета фона
self.setAutoFillBackground(True)
p = self.palette()
p.setColor(self.backgroundRole(), Qt.GlobalColor.lightGray)
self.setPalette(p)
def updateState(self):
self.stepLabel.setText(f"Отправлено шагов {self.imitate_point()}")

51
gui/informer.py Normal file
View File

@ -0,0 +1,51 @@
from PyQt6.QtWidgets import QWidget, QLabel, QVBoxLayout, QPushButton
from PyQt6.QtCore import QTimer, Qt
import time
from logger import logger
class Informer(QWidget):
def __init__(self, updateData, world_coord, axis_coord, command_count):
super().__init__()
self.world_coord = world_coord
self.axis_coord = axis_coord
self.command_count = command_count
self.updateData = updateData
self.timer = QTimer()
self.timer.timeout.connect(self.updateState)
self.timer.start(int(100))
# Инициализация пользовательского интерфейса
self.initUI()
def initUI(self):
self.layout = QVBoxLayout()
self.setLayout(self.layout)
self.wLabel = QLabel(f'Мировые координаты {self.world_coord()}')
self.aLabel = QLabel(f'Поворот осей {self.axis_coord()}')
self.cLabel = QLabel(f'Количество команд в стеке {self.command_count()}')
for l in [self.wLabel, self.aLabel, self.cLabel]:
l.setWordWrap(True)
self.layout.addWidget(l)
self.updButton = QPushButton('Обновить данные')
self.updButton.clicked.connect(self.updateData)
self.layout.addWidget(self.updButton)
def paintEvent(self, event):
# Установка цвета фона
self.setAutoFillBackground(True)
p = self.palette()
p.setColor(self.backgroundRole(), Qt.GlobalColor.lightGray)
self.setPalette(p)
def updateState(self):
self.wLabel.setText(f'Мировые координаты {self.world_coord()}')
self.aLabel.setText(f'Поворот осей {self.axis_coord()}')
self.cLabel.setText(f'Количество команд в стеке {self.command_count()}')

126
gui/init.py Normal file
View File

@ -0,0 +1,126 @@
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QColor, QPalette
from gui.robot import ChangeRobot
from gui.filename import ChangeFile
from gui.status import Status
from gui.informer import Informer
from gui.imitator import Imitator
from gui.command import Command
from gui.visualize import Visualize
from gui.palletizing import Palletizing
from gui.observable import Observable
from logger import logger
class MyPanel(QWidget):
def __init__(self, panels, color):
super().__init__()
layout = QVBoxLayout()
for panel in panels:
layout.addWidget(panel)
self.color = QColor(*color)
self.setLayout(layout)
self.initUI()
def initUI(self):
palette = self.palette()
palette.setColor(QPalette.ColorRole.Window, self.color)
self.setAutoFillBackground(True)
self.setPalette(palette)
class MainContentComponent(QWidget):
def __init__(self, **kwargs):
super().__init__()
self.observable = Observable(kwargs.get("get_status"))
self.observable.value_changed.connect(self.handle_value_change)
robotArgs = kwargs.get("robotPanel", {})
self.robotPanel = ChangeRobot(**robotArgs)
statusArgs = kwargs.get("statusPanel", {})
self.statusPanel = Status(**statusArgs)
informerArgs = kwargs.get("informerPanel", {})
self.informerPanel = Informer(**informerArgs)
filenameArgs = kwargs.get("filenamePanel", {})
self.filenamePanel = ChangeFile(**filenameArgs)
imitatorArgs = kwargs.get("imitatorPanel", {})
self.imitatorPanel = Imitator(**imitatorArgs)
commandArgs = kwargs.get("commandPanel", {})
self.commandPanel = Command(**commandArgs)
palletizingArgs = kwargs.get("palletizingPanel", {})
self.palletizingPanel = Palletizing(**palletizingArgs)
self.rightPanel = MyPanel(
panels=[
# self.statusPanel,
self.robotPanel,
self.informerPanel,
# self.filenamePanel,
# self.imitatorPanel,
self.palletizingPanel,
self.commandPanel,
],
color=(169, 169, 169),
)
visArgs = kwargs.get("visPanel", {})
self.visPanel = Visualize(**visArgs)
self.mainPanel = MyPanel(
panels=[
self.visPanel,
],
color=(200, 200, 200),
)
layout = QHBoxLayout()
layout.addWidget(self.mainPanel)
layout.addWidget(self.rightPanel)
self.setLayout(layout)
self.setFixedSize(800, 800)
self.initUI()
def initUI(self):
palette = QPalette()
palette.setColor(QPalette.ColorRole.Window, QColor(240, 240, 240))
self.setPalette(palette)
def resizeEvent(self, event):
width = self.width()
rightPanelWidth = int(width * 0.25)
self.rightPanel.setFixedWidth(rightPanelWidth)
super().resizeEvent(event)
def handle_value_change(self, new_value):
panels = [
self.informerPanel,
self.filenamePanel,
self.imitatorPanel,
self.commandPanel,
self.palletizingPanel,
]
for p in panels:
if new_value == "not_connected":
p.setDisabled(True)
if new_value == "connected":
p.setDisabled(False)
if __name__ == "__main__":
app = QApplication(sys.argv)
mainWindow = MainContentComponent(
robotPanel={"arg1": "value1"}, statusPanel={"arg1": "value1"}
)
mainWindow.show()
sys.exit(app.exec_())

22
gui/observable.py Normal file
View File

@ -0,0 +1,22 @@
from PyQt6.QtCore import pyqtSignal, QObject, QTimer
from logger import logger
class Observable(QObject):
value_changed = pyqtSignal(object) # Сигнал с переданным значением
def __init__(self, func, interval=1000):
super().__init__()
self.get_dynamic_value = func
self._value = None
# Таймер для периодической проверки значения
self.timer = QTimer(self)
self.timer.timeout.connect(self.check_function) # Вызываем some_function на каждом таймере
self.timer.start(interval) # Интервал в миллисекундах
def check_function(self):
# Пример функции, которая обновляет значение
new_value = self.get_dynamic_value()
if new_value != self._value:
self._value = new_value
self.value_changed.emit(new_value)

40
gui/palletizing.py Normal file
View File

@ -0,0 +1,40 @@
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QPushButton, QLabel
from PyQt6.QtCore import Qt, QTimer
from logger import logger
class Palletizing(QWidget):
def __init__(self, load_palletizing, start_moving):
super().__init__()
self.load_palletizing = load_palletizing
self.start_moving = start_moving
self.initUI()
def initUI(self):
self.layout = QVBoxLayout()
self.robotsLabel = QLabel("Паллетирование")
self.layout.addWidget(self.robotsLabel)
self.palletButton = QPushButton("Визуализировать")
self.palletButton.clicked.connect(self.startPalletzing)
self.layout.addWidget(self.palletButton)
self.startButton = QPushButton("Конвейер")
self.startButton.clicked.connect(self.startMoving)
self.layout.addWidget(self.startButton)
self.setLayout(self.layout)
def startPalletzing(self):
self.load_palletizing()
def startMoving(self):
self.start_moving()
def paintEvent(self, event):
p = self.palette()
p.setColor(self.backgroundRole(), Qt.GlobalColor.lightGray)
self.setPalette(p)
super().paintEvent(event)

87
gui/robot.py Normal file
View File

@ -0,0 +1,87 @@
import time
from PyQt6.QtWidgets import (
QWidget,
QVBoxLayout,
QLabel,
QRadioButton,
QPushButton,
QButtonGroup,
)
from PyQt6.QtCore import Qt, QTimer
from logger import logger
class ChangeRobot(QWidget):
def __init__(self, robots, updateRobot, status):
super().__init__()
self.robots = robots or []
self.updateRobot = updateRobot
self.status = status
self.initUI()
self.old_status = None
self.counter = 0
self.timer = QTimer(self)
self.timer.timeout.connect(self.timerCallback)
def initUI(self):
self.layout = QVBoxLayout()
self.robotsLabel = QLabel("Выберите робота")
self.layout.addWidget(self.robotsLabel)
self.buttonGroup = QButtonGroup(self)
self.robotsRadio = []
for i, r in enumerate(self.robots):
radioButton = QRadioButton(r["name"])
self.buttonGroup.addButton(radioButton, i)
self.robotsRadio.append(radioButton)
self.layout.addWidget(radioButton)
self.connectButton = QPushButton("Соединить")
self.connectButton.clicked.connect(self.connectRobot)
self.layout.addWidget(self.connectButton)
self.setLayout(self.layout)
self.updateConnectButtonText()
def updateConnectButtonText(self):
radioState = True
if self.status() == "not_connected":
self.connectButton.setText("Соединить")
elif self.status() == "connected":
self.connectButton.setText("Отключить")
radioState = False
for radioButton in self.robotsRadio:
radioButton.setEnabled(radioState)
def timerCallback(self):
new_status = self.status()
self.counter += 1
if new_status == self.old_status and self.counter <= 10:
self.connectButton.setText(self.connectButton.text() + ".")
else:
self.old_status = None
self.timer.stop()
self.updateConnectButtonText()
def connectRobot(self):
self.updateConnectButtonText()
selectedId = self.buttonGroup.checkedId()
if selectedId == -1:
self.connectButton.setText("Выберите робота")
return
self.old_status = self.status()
self.timer.start(500)
time.sleep(0.3)
self.updateRobot(self.robots[selectedId])
def paintEvent(self, event):
p = self.palette()
p.setColor(self.backgroundRole(), Qt.GlobalColor.lightGray)
self.setPalette(p)
super().paintEvent(event)

37
gui/status.py Normal file
View File

@ -0,0 +1,37 @@
from PyQt6.QtWidgets import QWidget, QLabel, QVBoxLayout, QApplication
from PyQt6.QtCore import QTimer, Qt
class Status(QWidget):
def __init__(self, status):
super().__init__()
self.status = status
# Инициализация пользовательского интерфейса
self.initUI()
# Таймер для обновления статуса
self.timer = QTimer(self)
self.timer.timeout.connect(self.updateStatus)
self.timer.start(1000) # Обновление каждые 1000 мс (1 секунда)
def initUI(self):
self.layout = QVBoxLayout()
# Создание метки для отображения статуса
self.statusLabel = QLabel(self.status())
self.layout.addWidget(self.statusLabel)
self.setLayout(self.layout)
self.setFixedHeight(100)
def paintEvent(self, event):
# Установка цвета фона
self.setAutoFillBackground(True)
p = self.palette()
p.setColor(self.backgroundRole(), Qt.GlobalColor.lightGray)
self.setPalette(p)
def updateStatus(self):
# Обновление текста метки статуса
self.statusLabel.setText(self.status())

53
gui/visualize.py Normal file
View File

@ -0,0 +1,53 @@
import time
import numpy as np
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy
from PyQt6.QtGui import QImage, QPixmap
from PyQt6.QtCore import Qt, QTimer
from logger import logger
class Visualize(QWidget):
def __init__(self, get_pybullet_image):
super().__init__()
self.get_pybullet_image = get_pybullet_image
# Настройка компоновки
self.layout = QVBoxLayout(self)
self.layout.setContentsMargins(0, 0, 0, 0) # Убираем отступы по краям
self.h_layout = QHBoxLayout()
self.h_layout.setContentsMargins(0, 0, 0, 0) # Убираем отступы по краям
self.label = QLabel(self)
self.layout.addWidget(self.label)
# Таймер для обновления изображения
self.timer = QTimer()
self.timer.timeout.connect(self.update_image)
self.timer.start(300)
def update_image(self):
res = self.get_pybullet_image()
if not res:
return
(rgb, width, height) = res
rgb_array = np.array(rgb, dtype=np.uint8)
bytesPerLine = 4 * width
# print(type(rgb))
image = QImage(rgb_array, width, height, bytesPerLine, QImage.Format.Format_RGBA8888).rgbSwapped()
image = image.convertToFormat(QImage.Format.Format_RGB888)
pixmap = QPixmap.fromImage(image)
self.label.setPixmap(pixmap)
self.label.setAlignment(Qt.AlignmentFlag.AlignHCenter)
self.label.update()
def paintEvent(self, event):
p = self.palette()
p.setColor(self.backgroundRole(), Qt.GlobalColor.magenta)
self.setPalette(p)
super().paintEvent(event)

14
logger.py Normal file
View File

@ -0,0 +1,14 @@
import sys
import logging
# Настройка логгера
logging.basicConfig(
level=logging.DEBUG, # Уровень логирования
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s - %(filename)s - %(lineno)d",
handlers=[
logging.FileHandler("app.log"), # Запись в файл
logging.StreamHandler(sys.stdout), # Вывод в консоль
],
)
logger = logging.getLogger("logger")

202
main.py Normal file
View File

@ -0,0 +1,202 @@
import os
import sys
import glob
import json
import time
import argparse
import threading
from PyQt6.QtCore import QThread
from PyQt6.QtWidgets import QApplication
from robot.client_socket import SocketRobotArm
from gui.init import MainContentComponent
from logger import logger
class MyApp:
if getattr(sys, "frozen", False):
# Если приложение собрано в один файл
application_path = os.path.dirname(sys.executable)
else:
# Если приложение запускается как скрипт
application_path = os.path.dirname(os.path.abspath(__file__))
robots_json_path = os.path.join(application_path, "robots.json")
with open(robots_json_path, "r") as file:
robots = json.load(file)
robot_app = None
def __init__(self, mode):
self.mode = mode
self.startGui()
self.startRobot()
self.startWindow()
def startGui(self):
self.app = QApplication(sys.argv)
mainWindow = MainContentComponent(
get_status=self.get_status,
robotPanel={
"robots": self.robots,
"updateRobot": self.updateRobot,
"status": self.get_status,
},
statusPanel={
"status": self.get_status,
},
informerPanel={
"world_coord": self.get_world_coordinates,
"axis_coord": self.get_axis_coordinates,
"command_count": self.get_command_count,
"updateData": self.update_data_wrapper,
},
imitatorPanel={
"startImitate": self.imitate_wrapper,
"imitate_point": self.get_imitate_point,
},
commandPanel={
"startCommand": self.command_wrapper,
"changeType": self.change_type_wrapper,
"command_data": self.get_command_data,
"command_type": self.get_command_type,
},
visPanel={
"get_pybullet_image": self.get_pybullet_image_wrapper,
},
filenamePanel={
"files": self.get_data_files(),
"getFilename": self.get_filename,
"setFilename": self.set_filename,
},
palletizingPanel={
"load_palletizing": self.load_palletizing,
"start_moving": self.start_moving
},
)
mainWindow.setWindowTitle("ROBOT GUI")
self.window = mainWindow
def get_data_files(self):
files = glob.glob(f"{self.application_path}/data/*.nc.result")
return [os.path.basename(x) for x in files]
def startWindow(self):
self.window.show()
sys.exit(self.app.exec())
def startRobot(self):
self.robot_app = SocketRobotArm(application_path=self.application_path)
# Запускаем SocketRobotArm в отдельном потоке
threading.Thread(target=self.run_robot_arm, daemon=True).start()
def run_robot_arm(self):
time.sleep(1)
self.robot_app.start("SHARED_MEMORY")
def updateRobot(self, robot):
if robot in self.robots:
selected_robot = robot
if self.mode == "test":
robot["host"] = "127.0.0.1"
if self.robot_app.status == "connected":
self.robot_app.close()
time.sleep(0.3)
else:
self.robot_app.connect(
selected_robot["host"], selected_robot["slave_id"]
)
self.robot_app.start_loop(selected_robot["urdf"])
def check_robot_app(func):
def wrapper(self, *args, **kwargs):
if self.robot_app:
return func(self, *args, **kwargs)
else:
logger.info(f"robot_app еще не инициализирован. Метод: {func.__name__}")
return None # Или любое значение по умолчанию
return wrapper
@check_robot_app
def get_status(self):
return self.robot_app.get_status()
@check_robot_app
def get_world_coordinates(self):
return self.robot_app.world_coordinates
@check_robot_app
def get_axis_coordinates(self):
return self.robot_app.axis_coordinates
@check_robot_app
def get_command_count(self):
return self.robot_app.command_count
@check_robot_app
def get_command_data(self):
return self.robot_app.get_command_data()
@check_robot_app
def get_command_type(self):
return self.robot_app.get_command_type()
@check_robot_app
def get_imitate_point(self):
return self.robot_app.get_imitate_point()
@check_robot_app
def change_type_wrapper(self, type="base"):
return self.robot_app.set_command_type(type)
@check_robot_app
def command_wrapper(self, *args, **kwargs):
# logger.info(args)
# logger.info(kwargs)
return self.robot_app.cycle_start()
@check_robot_app
def imitate_wrapper(self, *args, **kwargs):
return self.robot_app.imitate()
@check_robot_app
def update_data_wrapper(self, *args, **kwargs):
return self.robot_app.upd_model()
@check_robot_app
def get_pybullet_image_wrapper(self):
return self.robot_app.get_pybullet_image()
@check_robot_app
def get_filename(self):
return self.robot_app.filename
@check_robot_app
def set_filename(self, filename):
self.robot_app.filename = filename
@check_robot_app
def load_palletizing(self):
return self.robot_app.load_palletizing()
@check_robot_app
def start_moving(self):
return self.robot_app.start_moving()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="MyApp Command Line Interface")
parser.add_argument(
"--mode",
type=str,
choices=["test", "prod"],
default="prod",
help="Mode of operation",
)
# MyApp()
args = parser.parse_args()
app = MyApp(args.mode)

39
main.spec Normal file
View File

@ -0,0 +1,39 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['main.py'],
pathex=['.', './.venv', './.venv/Lib', './.venv/Lib/site-packages', 'robot/', 'gui/'],
binaries=[],
datas=[('robots.json', '.'), ('urdf', 'urdf'), ('data', 'data')],
hiddenimports=['numpy', 'libpython3.10'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
contents_directory='test',
)

45
packer/packer.py Normal file
View File

@ -0,0 +1,45 @@
from py3dbp import Packer, Bin, Item
from logger import logger
class PalletPacker:
def __init__(self, pallet: dict, box: dict):
self.pallet_width = pallet.get("x", 1.2)
self.pallet_height = pallet.get("y", 0.8)
self.pallet_depth = pallet.get("z", 0.144)
gap = 0
self.box_width = box.get("x", 0.2) + gap
self.box_height = box.get("y", 0.2) + gap
self.box_depth = box.get("z", 0.2)
def pack(self):
packer = Packer()
packer.add_bin(
Bin(
"pallet", self.pallet_width, self.pallet_height, self.pallet_depth, 1000
)
)
# Вычисляем, сколько коробок поместится на паллете в один слой
num_boxes_x = self.pallet_width // self.box_width
num_boxes_y = self.pallet_height // self.box_height
num_boxes = int(num_boxes_x * num_boxes_y)
# Добавляем коробки в пакер
for i in range(num_boxes):
packer.add_item(
Item(f"box{i}", self.box_width, self.box_height, self.box_depth, 1)
)
# Упаковываем коробки
packer.pack()
# Получаем результат
coordinates = []
for b in packer.bins:
for item in b.items:
coordinates.append([float(i) for i in item.position])
return coordinates

99
pallete.json Normal file

File diff suppressed because one or more lines are too long

969
palletizing.json Normal file
View File

@ -0,0 +1,969 @@
[
{
"action": 50000,
"comment": "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*<font size=\"4\" color=\"green\">pociya_1_korobki</font> Line3D-Pose:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Next:X:1092.016,Y:417.880,Z:-297.773,U:-179.999,V:0.000,W:-90.004 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;V100.0 DLY0.000 Smooth:None tool:0:Null coord:0:Null ",
"commentAction": {
"action": 10,
"bindIOInfo": 0,
"ckStatus": "63",
"customName": "pociya_1_korobki",
"delay": "0.000",
"distance": "0.000",
"insertedIndex": 12,
"passTrans": 0,
"points": [
{
"pointName": "",
"pos": {
"m0": "1092.016",
"m1": "417.880",
"m2": "-297.773",
"m3": "-179.999",
"m4": "0.000",
"m5": "-90.004",
"m6": "0.000",
"m7": "0.000"
}
}
],
"quotePoint": [
0,
0,
0
],
"relativeType": 0,
"smooth": 0,
"speed": "100.0",
"toolCoord": 0
},
"insertedIndex": 12
},
{
"action": 50000,
"comment": "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*<font size=\"4\" color=\"green\">po_odnoj_1korobka</font> Line3D-Pose:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Next:X:1225.936,Y:417.871,Z:-297.768,U:-179.998,V:0.000,W:-90.006 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;V100.0 DLY0.000 Smooth:None tool:0:Null coord:0:Null ",
"commentAction": {
"action": 10,
"bindIOInfo": 0,
"ckStatus": "63",
"customName": "po_odnoj_1korobka",
"delay": "0.000",
"distance": "0.000",
"insertedIndex": 19,
"passTrans": 0,
"points": [
{
"pointName": "",
"pos": {
"m0": "1225.936",
"m1": "417.871",
"m2": "-297.768",
"m3": "-179.998",
"m4": "0.000",
"m5": "-90.006",
"m6": "0.000",
"m7": "0.000"
}
}
],
"quotePoint": [
0,
0,
0
],
"relativeType": 0,
"smooth": 0,
"speed": "100.0",
"toolCoord": 0
},
"insertedIndex": 19
},
{
"action": 50000,
"comment": "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*<font size=\"4\" color=\"green\">free_poziciya</font> Line3D-Pose:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Next:X:877.893,Y:-470.669,Z:1124.063,U:-180.000,V:-0.015,W:151.736 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;V100.0 DLY0.000 Smooth:None tool:0:Null coord:0:Null ",
"commentAction": {
"action": 10,
"bindIOInfo": 0,
"ckStatus": "63",
"customName": "free_poziciya",
"delay": "0.000",
"distance": "0.000",
"insertedIndex": 1,
"passTrans": 0,
"points": [
{
"pointName": "",
"pos": {
"m0": "877.893",
"m1": "-470.669",
"m2": "1124.063",
"m3": "-180.000",
"m4": "-0.015",
"m5": "151.736",
"m6": "0.000",
"m7": "0.000"
}
}
],
"quotePoint": [
0,
0,
0
],
"relativeType": 0,
"smooth": 0,
"speed": "100.0",
"toolCoord": 0
},
"insertedIndex": 1
},
{
"action": 4,
"bindIOInfo": 0,
"ckStatus": "63",
"customName": "startovaya_poziciya",
"delay": "0.000",
"distance": "0.000",
"insertedIndex": 2,
"passTrans": 0,
"points": [
{
"pointName": "",
"pos": {
"m0": "-28.261",
"m1": "0.281",
"m2": "-2.815",
"m3": "0.000",
"m4": "-87.481",
"m5": "0.002",
"m6": "0.000",
"m7": "0.000"
}
}
],
"quotePoint": [
0,
0,
0
],
"relativeType": 0,
"smooth": 0,
"speed": "100.0",
"toolCoord": 0
},
{
"action": 401,
"counterID": "0",
"customName": "ochischaem_schetchik",
"insertedIndex": 3
},
{
"action": 59999,
"comment": "start_cikla",
"customName": "nachalo_cikla_ukladki",
"flag": 0,
"insertedIndex": 4
},
{
"action": 50000,
"comment": "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*<font size=\"4\" color=\"green\">u_konveera</font> Line3D-Pose:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Next:X:685.097,Y:-1139.102,Z:205.713,U:-179.991,V:-0.002,W:179.468 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;V100.0 DLY0.000 Smooth:None tool:0:Null coord:0:Null ",
"commentAction": {
"action": 10,
"bindIOInfo": 0,
"ckStatus": "63",
"customName": "u_konveera",
"delay": "0.000",
"distance": "0.000",
"insertedIndex": 4,
"passTrans": 0,
"points": [
{
"pointName": "",
"pos": {
"m0": "685.097",
"m1": "-1139.102",
"m2": "205.713",
"m3": "-179.991",
"m4": "-0.002",
"m5": "179.468",
"m6": "0.000",
"m7": "0.000"
}
}
],
"quotePoint": [
0,
0,
0
],
"relativeType": 0,
"smooth": 0,
"speed": "100.0",
"toolCoord": 0
},
"insertedIndex": 5
},
{
"action": 4,
"bindIOInfo": 0,
"ckStatus": "63",
"customName": "podhod_k_konveeru",
"delay": "0.000",
"distance": "0.000",
"insertedIndex": 6,
"passTrans": 0,
"points": [
{
"pointName": "",
"pos": {
"m0": "-59.023",
"m1": "-50.957",
"m2": "-0.568",
"m3": "-0.009",
"m4": "-38.466",
"m5": "-58.482",
"m6": "0.000",
"m7": "0.000"
}
}
],
"quotePoint": [
0,
0,
0
],
"relativeType": 0,
"smooth": 0,
"speed": "100.0",
"toolCoord": 0
},
{
"action": 50000,
"comment": "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*<font size=\"4\" color=\"green\">naezd_na_korobki</font> Line3D-Pose:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Next:X:829.456,Y:-1139.107,Z:205.720,U:-179.989,V:0.000,W:179.464 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;V100.0 DLY0.000 Smooth:None tool:0:Null coord:0:Null ",
"commentAction": {
"action": 10,
"bindIOInfo": 0,
"ckStatus": "63",
"customName": "naezd_na_korobki",
"delay": "0.000",
"distance": "0.000",
"insertedIndex": 5,
"passTrans": 0,
"points": [
{
"pointName": "",
"pos": {
"m0": "829.456",
"m1": "-1139.107",
"m2": "205.720",
"m3": "-179.989",
"m4": "0.000",
"m5": "179.464",
"m6": "0.000",
"m7": "0.000"
}
}
],
"quotePoint": [
0,
0,
0
],
"relativeType": 0,
"smooth": 0,
"speed": "100.0",
"toolCoord": 0
},
"insertedIndex": 7
},
{
"action": 4,
"bindIOInfo": 0,
"ckStatus": "63",
"customName": "naezd_na_korobku",
"delay": "0.000",
"distance": "0.000",
"insertedIndex": 8,
"passTrans": 0,
"points": [
{
"pointName": "",
"pos": {
"m0": "-53.983",
"m1": "-55.666",
"m2": "8.628",
"m3": "-0.009",
"m4": "-42.953",
"m5": "-53.440",
"m6": "0.000",
"m7": "0.000"
}
}
],
"quotePoint": [
0,
0,
0
],
"relativeType": 0,
"smooth": 0,
"speed": "50.0",
"toolCoord": 0
},
{
"action": 50000,
"comment": "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*<font size=\"4\" color=\"green\">otriv_korobok_promezutochnaya</font> Line3D-Pose:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Next:X:829.493,Y:-1139.102,Z:443.818,U:-179.987,V:0.002,W:179.461 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;V100.0 DLY0.000 Smooth:9 tool:0:Null coord:0:Null ",
"commentAction": {
"action": 10,
"bindIOInfo": 0,
"ckStatus": "63",
"customName": "otriv_korobok_promezutochnaya",
"delay": "0.000",
"distance": "0.000",
"insertedIndex": 6,
"passTrans": 0,
"points": [
{
"pointName": "",
"pos": {
"m0": "829.493",
"m1": "-1139.102",
"m2": "443.818",
"m3": "-179.987",
"m4": "0.002",
"m5": "179.461",
"m6": "0.000",
"m7": "0.000"
}
}
],
"quotePoint": [
0,
0,
0
],
"relativeType": 0,
"smooth": 9,
"speed": "100.0",
"toolCoord": 0
},
"insertedIndex": 9
},
{
"action": 50000,
"comment": "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*<font size=\"4\" color=\"green\">start_na_paletu</font> Line3D-Pose:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Next:X:829.539,Y:-775.127,Z:605.033,U:-179.979,V:-0.003,W:-89.998 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;V100.0 DLY0.000 Smooth:9 tool:0:Null coord:0:Null ",
"commentAction": {
"action": 10,
"bindIOInfo": 0,
"ckStatus": "63",
"customName": "start_na_paletu",
"delay": "0.000",
"distance": "0.000",
"insertedIndex": 7,
"passTrans": 0,
"points": [
{
"pointName": "",
"pos": {
"m0": "829.539",
"m1": "-775.127",
"m2": "605.033",
"m3": "-179.979",
"m4": "-0.003",
"m5": "-89.998",
"m6": "0.000",
"m7": "0.000"
}
}
],
"quotePoint": [
0,
0,
0
],
"relativeType": 0,
"smooth": 9,
"speed": "100.0",
"toolCoord": 0
},
"insertedIndex": 10
},
{
"action": 50000,
"comment": "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Line3D-Pose:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Next:X:640.604,Y:-775.059,Z:1023.864,U:-179.946,V:0.000,W:-90.341 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;V50.0 DLY0.000 Smooth:9 tool:0:Null coord:0:Null ",
"commentAction": {
"action": 10,
"bindIOInfo": 0,
"ckStatus": "63",
"customName": "",
"delay": "0.000",
"distance": "0.000",
"insertedIndex": 28,
"passTrans": 0,
"points": [
{
"pointName": "",
"pos": {
"m0": "640.604",
"m1": "-775.059",
"m2": "1023.864",
"m3": "-179.946",
"m4": "0.000",
"m5": "-90.341",
"m6": "0.000",
"m7": "0.000"
}
}
],
"quotePoint": [
0,
0,
0
],
"relativeType": 0,
"smooth": 9,
"speed": "50.0",
"toolCoord": 0
},
"insertedIndex": 11
},
{
"action": 4,
"bindIOInfo": 0,
"ckStatus": "63",
"customName": "podjem_korobki",
"delay": "0.000",
"distance": "0.000",
"insertedIndex": 12,
"passTrans": 0,
"points": [
{
"pointName": "",
"pos": {
"m0": "-35.787",
"m1": "-6.346",
"m2": "-2.779",
"m3": "0.028",
"m4": "-80.826",
"m5": "-125.450",
"m6": "0.000",
"m7": "0.000"
}
}
],
"quotePoint": [
0,
0,
0
],
"relativeType": 0,
"smooth": 9,
"speed": "100.0",
"toolCoord": 0
},
{
"action": 50000,
"comment": "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*<font size=\"4\" color=\"green\">vozvrat_k_konveeru</font> Line3D-Pose:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Next:X:829.556,Y:-775.120,Z:605.066,U:179.571,V:-0.005,W:-152.101 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;V100.0 DLY0.000 Smooth:9 tool:0:Null coord:0:Null ",
"commentAction": {
"action": 10,
"bindIOInfo": 0,
"ckStatus": "63",
"customName": "vozvrat_k_konveeru",
"delay": "0.000",
"distance": "0.000",
"insertedIndex": 13,
"passTrans": 0,
"points": [
{
"pointName": "",
"pos": {
"m0": "829.556",
"m1": "-775.120",
"m2": "605.066",
"m3": "179.571",
"m4": "-0.005",
"m5": "-152.101",
"m6": "0.000",
"m7": "0.000"
}
}
],
"quotePoint": [
0,
0,
0
],
"relativeType": 0,
"smooth": 9,
"speed": "100.0",
"toolCoord": 0
},
"insertedIndex": 13
},
{
"action": 300,
"away_xoffset": "0.000",
"away_yoffset": "0.000",
"away_zoffset": "0.000",
"counterID": 0,
"customName": "plan_paletirovaniya",
"fullAlarm": 0,
"insertedIndex": 20,
"interval_always_out": 0,
"interval_en": 0,
"interval_number": "10",
"interval_out_choose": -1,
"interval_out_id": -1,
"interval_out_time": "1",
"intervalbox_always_out": 0,
"intervalbox_en": 0,
"intervalbox_number": "10",
"intervalbox_out_choose": 0,
"intervalbox_out_id": 0,
"intervalbox_out_time": "1",
"ls_xdir": 0,
"ls_ydir": 0,
"ls_zdir": 0,
"put_stack": true,
"ready_xoffset": 1,
"ready_yoffset": "0.000",
"ready_zoffset": "0.000",
"rs_xdir": 0,
"rs_ydir": 0,
"rs_zdir": 0,
"set_leave_point": 0,
"set_ready_point": 0,
"speed0": "80.0",
"speed1": "80.0",
"speedY": "80.0",
"speedZ": "80.0",
"stackID": "1",
"stack_delay": "0.0"
},
{
"actType": 1,
"action": 50,
"coord": "1",
"customName": "trans_points",
"delay": "0.00",
"insertedIndex": 21,
"pathAction": 10,
"pointType": 0,
"smooth": 9,
"speed": "80.0",
"stackId": "1",
"tool": "0"
},
{
"actType": 1,
"action": 50,
"coord": "1",
"customName": "ready_points",
"delay": "0.00",
"insertedIndex": 22,
"pathAction": 10,
"pointType": 1,
"smooth": 9,
"speed": "80.0",
"stackId": "1",
"tool": "0"
},
{
"actType": 1,
"action": 50,
"coord": "1",
"customName": "point_ukladki",
"delay": "0.00",
"insertedIndex": 23,
"pathAction": 10,
"pointType": 2,
"smooth": 0,
"speed": "80.0",
"stackId": "1",
"tool": "0"
},
{
"actType": 1,
"action": 50,
"coord": "1",
"customName": "othod_ot_ustanovlennoj_korobki",
"delay": "0.00",
"insertedIndex": 24,
"pathAction": 10,
"pointType": 3,
"smooth": 9,
"speed": "80.0",
"stackId": "1",
"tool": "0"
},
{
"action": 4,
"bindIOInfo": 0,
"ckStatus": "63",
"customName": "vozvrat_v_nachalnuyu_pozciu",
"delay": "0.000",
"distance": "0.000",
"insertedIndex": 14,
"passTrans": 0,
"points": [
{
"pointName": "",
"pos": {
"m0": "-62.233",
"m1": "-24.320",
"m2": "5.996",
"m3": "0.000",
"m4": "-71.666",
"m5": "-61.820",
"m6": "0.000",
"m7": "0.000"
}
}
],
"quotePoint": [
0,
0,
0
],
"relativeType": 0,
"smooth": 9,
"speed": "100.0",
"toolCoord": 0
},
{
"action": 400,
"counterID": "0",
"customName": "uvelichivaem_schetchik",
"insertedIndex": 15
},
{
"action": 10002,
"autoClear": false,
"compareID": 7,
"compareTarget": "10",
"counterID": 0,
"customName": "proveka_usloviya_cikla",
"flag": 0,
"insertedIndex": 16
},
{
"action": 50000,
"comment": "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cmd Set:Stop",
"commentAction": {
"action": 53000,
"addr": 98304,
"data": 2561,
"insertedIndex": 17,
"op": 0,
"specialType": 1,
"type": 0,
"typeSel": 1
},
"insertedIndex": 17
},
{
"action": 60000,
"insertedIndex": 18
}
][
{
"action": 60000,
"insertedIndex": 0
}
][
{
"action": 60000,
"insertedIndex": 0
}
][
{
"action": 60000,
"insertedIndex": 0
}
][
{
"action": 60000,
"insertedIndex": 0
}
][
{
"action": 60000,
"insertedIndex": 0
}
][
{
"action": 60000,
"insertedIndex": 0
}
][
{
"action": 60000,
"insertedIndex": 0
}
][
{
"action": 60000,
"insertedIndex": 0
}
]{
"0": {
"si0": {
"m0pos": "0",
"m1pos": "0",
"m2pos": "0",
"m3pos": "0",
"m4pos": "0",
"m5pos": "0",
"space0": "0",
"space1": "0",
"space2": "0",
"count0": "0",
"count1": "0",
"count2": "0",
"sequence": 0,
"dir0": 0,
"dir1": 0,
"dir2": 0,
"doesBindingCounter": true,
"counterID": 0,
"isOffsetEn": false,
"isZWithYEn": false,
"offsetX": "0",
"offsetY": "0",
"offsetZ": "0",
"dataSourceName": "Custom Pos",
"dataSourceID": "custompoint[0]",
"runSeq": 3,
"holdSel": 0,
"armSel": 0,
"coordinate": 1,
"tool": 0
},
"si1": {
"m0pos": "0",
"m1pos": "0",
"m2pos": "0",
"m3pos": "0",
"m4pos": "0",
"m5pos": "0",
"space0": "0",
"space1": "0",
"space2": "0",
"count0": "0",
"count1": "0",
"count2": "0",
"sequence": 0,
"dir0": 0,
"dir1": 0,
"dir2": 0,
"doesBindingCounter": true,
"counterID": 0,
"isOffsetEn": false,
"isZWithYEn": false,
"offsetX": "0",
"offsetY": "0",
"offsetZ": "0",
"dataSourceName": "Custom Pos",
"dataSourceID": "custompoint[0]",
"runSeq": 3,
"holdSel": 0,
"armSel": -1,
"coordinate": -1,
"tool": -1
},
"type": 7,
"descr": "scuko",
"dsName": "custompoint[0]",
"dsHostID": 0,
"posData": [
{
"pointName": 0,
"pointPos": {
"m0": 150,
"m1": "0.000",
"m2": "100.000",
"m3": 0,
"m4": 0,
"m5": 0
}
}
]
},
"1": {
"si0": {
"m0pos": "0",
"m1pos": "0",
"m2pos": "0",
"m3pos": "0",
"m4pos": "0",
"m5pos": "0",
"space0": "0",
"space1": "0",
"space2": "0",
"count0": "0",
"count1": "0",
"count2": "0",
"sequence": 0,
"dir0": 0,
"dir1": 0,
"dir2": 0,
"doesBindingCounter": true,
"counterID": 0,
"isOffsetEn": false,
"isZWithYEn": false,
"offsetX": "0",
"offsetY": "0",
"offsetZ": "0",
"dataSourceName": "Custom Pos",
"dataSourceID": "custompoint[1]",
"runSeq": 3,
"holdSel": 0,
"armSel": 0,
"coordinate": 1,
"tool": 0
},
"si1": {
"m0pos": "0",
"m1pos": "0",
"m2pos": "0",
"m3pos": "0",
"m4pos": "0",
"m5pos": "0",
"space0": "0",
"space1": "0",
"space2": "0",
"count0": "0",
"count1": "0",
"count2": "0",
"sequence": 0,
"dir0": 0,
"dir1": 0,
"dir2": 0,
"doesBindingCounter": true,
"counterID": 0,
"isOffsetEn": false,
"isZWithYEn": false,
"offsetX": "0",
"offsetY": "0",
"offsetZ": "0",
"dataSourceName": "Custom Pos",
"dataSourceID": "custompoint[1]",
"runSeq": 3,
"holdSel": 0,
"armSel": -1,
"coordinate": -1,
"tool": -1
},
"type": 7,
"descr": "padla",
"dsName": "custompoint[1]",
"dsHostID": 1,
"posData": [
{
"pointName": 0,
"pointPos": {
"m0": 170,
"m1": "0.000",
"m2": "200.000",
"m3": 0,
"m4": 0,
"m5": 0
}
},
{
"pointName": 1,
"pointPos": {
"m0": 170,
"m1": "200.000",
"m2": "200.000",
"m3": 0,
"m4": 0,
"m5": 0
}
},
{
"pointName": 2,
"pointPos": {
"m0": 170,
"m1": "200.000",
"m2": "200.000",
"m3": 0,
"m4": 0,
"m5": 0
}
},
{
"pointName": 3,
"pointPos": {
"m0": 170,
"m1": "200.000",
"m2": "200.000",
"m3": 0,
"m4": 0,
"m5": 0
}
},
{
"pointName": 4,
"pointPos": {
"m0": 170,
"m1": "200.000",
"m2": "200.000",
"m3": 0,
"m4": 0,
"m5": 0
}
},
{
"pointName": 5,
"pointPos": {
"m0": 170,
"m1": "200.000",
"m2": "200.000",
"m3": 0,
"m4": 0,
"m5": 0
}
}
]
}
}[][
{
"action": 60000,
"insertedIndex": 0
}
][
{
"action": 60000,
"insertedIndex": 0
}
][
{
"action": 60000,
"insertedIndex": 0
}
][
{
"action": 60000,
"insertedIndex": 0
}
][
{
"action": 60000,
"insertedIndex": 0
}
][
{
"action": 60000,
"insertedIndex": 0
}
][
{
"action": 60000,
"insertedIndex": 0
}
][
{
"action": 60000,
"insertedIndex": 0
}
]

720
poetry.lock generated
View File

@ -1,258 +1,361 @@
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. # This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
[[package]]
name = "attrs"
version = "24.2.0"
description = "Classes Without Boilerplate"
optional = false
python-versions = ">=3.7"
files = [
{file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"},
{file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"},
]
[package.extras]
benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
[[package]]
name = "automat"
version = "22.10.0"
description = "Self-service finite-state machines for the programmer on the go."
optional = false
python-versions = "*"
files = [
{file = "Automat-22.10.0-py2.py3-none-any.whl", hash = "sha256:c3164f8742b9dc440f3682482d32aaff7bb53f71740dd018533f9de286b64180"},
{file = "Automat-22.10.0.tar.gz", hash = "sha256:e56beb84edad19dcc11d30e8d9b895f75deeb5ef5e96b84a467066b3b84bb04e"},
]
[package.dependencies]
attrs = ">=19.2.0"
six = "*"
[package.extras]
visualize = ["Twisted (>=16.1.1)", "graphviz (>0.5.1)"]
[[package]]
name = "constantly"
version = "23.10.4"
description = "Symbolic constants in Python"
optional = false
python-versions = ">=3.8"
files = [
{file = "constantly-23.10.4-py3-none-any.whl", hash = "sha256:3fd9b4d1c3dc1ec9757f3c52aef7e53ad9323dbe39f51dfd4c43853b68dfa3f9"},
{file = "constantly-23.10.4.tar.gz", hash = "sha256:aa92b70a33e2ac0bb33cd745eb61776594dc48764b06c35e0efd050b7f1c7cbd"},
]
[[package]]
name = "hyperlink"
version = "21.0.0"
description = "A featureful, immutable, and correct URL for Python."
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
{file = "hyperlink-21.0.0-py2.py3-none-any.whl", hash = "sha256:e6b14c37ecb73e89c77d78cdb4c2cc8f3fb59a885c5b3f819ff4ed80f25af1b4"},
{file = "hyperlink-21.0.0.tar.gz", hash = "sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b"},
]
[package.dependencies]
idna = ">=2.5"
[[package]]
name = "idna"
version = "3.7"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.5"
files = [
{file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"},
{file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"},
]
[[package]]
name = "incremental"
version = "24.7.2"
description = "A small library that versions your Python projects."
optional = false
python-versions = ">=3.8"
files = [
{file = "incremental-24.7.2-py3-none-any.whl", hash = "sha256:8cb2c3431530bec48ad70513931a760f446ad6c25e8333ca5d95e24b0ed7b8fe"},
{file = "incremental-24.7.2.tar.gz", hash = "sha256:fb4f1d47ee60efe87d4f6f0ebb5f70b9760db2b2574c59c8e8912be4ebd464c9"},
]
[package.dependencies]
setuptools = ">=61.0"
tomli = {version = "*", markers = "python_version < \"3.11\""}
[package.extras]
scripts = ["click (>=6.0)"]
[[package]]
name = "modbus"
version = "3.2"
description = "Modbus TCP Server and Client Programs"
optional = false
python-versions = "*"
files = [
{file = "modbus-3.2.tar.gz", hash = "sha256:f4cd6efa24e7e2c5295672467722c2ed32faec7f43bbc1cabafe8a9f521439f2"},
]
[package.dependencies]
numpy = "*"
[[package]] [[package]]
name = "numpy" name = "numpy"
version = "2.0.1" version = "1.26.4"
description = "Fundamental package for array computing in Python" description = "Fundamental package for array computing in Python"
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.9"
files = [ files = [
{file = "numpy-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fbb536eac80e27a2793ffd787895242b7f18ef792563d742c2d673bfcb75134"}, {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"},
{file = "numpy-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:69ff563d43c69b1baba77af455dd0a839df8d25e8590e79c90fcbe1499ebde42"}, {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"},
{file = "numpy-2.0.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:1b902ce0e0a5bb7704556a217c4f63a7974f8f43e090aff03fcf262e0b135e02"}, {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"},
{file = "numpy-2.0.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:f1659887361a7151f89e79b276ed8dff3d75877df906328f14d8bb40bb4f5101"}, {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"},
{file = "numpy-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4658c398d65d1b25e1760de3157011a80375da861709abd7cef3bad65d6543f9"}, {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"},
{file = "numpy-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4127d4303b9ac9f94ca0441138acead39928938660ca58329fe156f84b9f3015"}, {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"},
{file = "numpy-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e5eeca8067ad04bc8a2a8731183d51d7cbaac66d86085d5f4766ee6bf19c7f87"}, {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"},
{file = "numpy-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9adbd9bb520c866e1bfd7e10e1880a1f7749f1f6e5017686a5fbb9b72cf69f82"}, {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"},
{file = "numpy-2.0.1-cp310-cp310-win32.whl", hash = "sha256:7b9853803278db3bdcc6cd5beca37815b133e9e77ff3d4733c247414e78eb8d1"}, {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"},
{file = "numpy-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:81b0893a39bc5b865b8bf89e9ad7807e16717f19868e9d234bdaf9b1f1393868"}, {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"},
{file = "numpy-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75b4e316c5902d8163ef9d423b1c3f2f6252226d1aa5cd8a0a03a7d01ffc6268"}, {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"},
{file = "numpy-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6e4eeb6eb2fced786e32e6d8df9e755ce5be920d17f7ce00bc38fcde8ccdbf9e"}, {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"},
{file = "numpy-2.0.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a1e01dcaab205fbece13c1410253a9eea1b1c9b61d237b6fa59bcc46e8e89343"}, {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"},
{file = "numpy-2.0.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a8fc2de81ad835d999113ddf87d1ea2b0f4704cbd947c948d2f5513deafe5a7b"}, {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"},
{file = "numpy-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a3d94942c331dd4e0e1147f7a8699a4aa47dffc11bf8a1523c12af8b2e91bbe"}, {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"},
{file = "numpy-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15eb4eca47d36ec3f78cde0a3a2ee24cf05ca7396ef808dda2c0ddad7c2bde67"}, {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"},
{file = "numpy-2.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b83e16a5511d1b1f8a88cbabb1a6f6a499f82c062a4251892d9ad5d609863fb7"}, {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"},
{file = "numpy-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f87fec1f9bc1efd23f4227becff04bd0e979e23ca50cc92ec88b38489db3b55"}, {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"},
{file = "numpy-2.0.1-cp311-cp311-win32.whl", hash = "sha256:36d3a9405fd7c511804dc56fc32974fa5533bdeb3cd1604d6b8ff1d292b819c4"}, {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"},
{file = "numpy-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:08458fbf403bff5e2b45f08eda195d4b0c9b35682311da5a5a0a0925b11b9bd8"}, {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"},
{file = "numpy-2.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6bf4e6f4a2a2e26655717a1983ef6324f2664d7011f6ef7482e8c0b3d51e82ac"}, {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"},
{file = "numpy-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6fddc5fe258d3328cd8e3d7d3e02234c5d70e01ebe377a6ab92adb14039cb4"}, {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"},
{file = "numpy-2.0.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5daab361be6ddeb299a918a7c0864fa8618af66019138263247af405018b04e1"}, {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"},
{file = "numpy-2.0.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:ea2326a4dca88e4a274ba3a4405eb6c6467d3ffbd8c7d38632502eaae3820587"}, {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"},
{file = "numpy-2.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:529af13c5f4b7a932fb0e1911d3a75da204eff023ee5e0e79c1751564221a5c8"}, {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"},
{file = "numpy-2.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6790654cb13eab303d8402354fabd47472b24635700f631f041bd0b65e37298a"}, {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"},
{file = "numpy-2.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cbab9fc9c391700e3e1287666dfd82d8666d10e69a6c4a09ab97574c0b7ee0a7"}, {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"},
{file = "numpy-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:99d0d92a5e3613c33a5f01db206a33f8fdf3d71f2912b0de1739894668b7a93b"}, {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"},
{file = "numpy-2.0.1-cp312-cp312-win32.whl", hash = "sha256:173a00b9995f73b79eb0191129f2455f1e34c203f559dd118636858cc452a1bf"}, {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"},
{file = "numpy-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:bb2124fdc6e62baae159ebcfa368708867eb56806804d005860b6007388df171"}, {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"},
{file = "numpy-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bfc085b28d62ff4009364e7ca34b80a9a080cbd97c2c0630bb5f7f770dae9414"}, {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"},
{file = "numpy-2.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8fae4ebbf95a179c1156fab0b142b74e4ba4204c87bde8d3d8b6f9c34c5825ef"}, {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"},
{file = "numpy-2.0.1-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:72dc22e9ec8f6eaa206deb1b1355eb2e253899d7347f5e2fae5f0af613741d06"}, {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"},
{file = "numpy-2.0.1-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:ec87f5f8aca726117a1c9b7083e7656a9d0d606eec7299cc067bb83d26f16e0c"}, {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"},
{file = "numpy-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f682ea61a88479d9498bf2091fdcd722b090724b08b31d63e022adc063bad59"}, {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"},
{file = "numpy-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8efc84f01c1cd7e34b3fb310183e72fcdf55293ee736d679b6d35b35d80bba26"}, {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"},
{file = "numpy-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3fdabe3e2a52bc4eff8dc7a5044342f8bd9f11ef0934fcd3289a788c0eb10018"},
{file = "numpy-2.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:24a0e1befbfa14615b49ba9659d3d8818a0f4d8a1c5822af8696706fbda7310c"},
{file = "numpy-2.0.1-cp39-cp39-win32.whl", hash = "sha256:f9cf5ea551aec449206954b075db819f52adc1638d46a6738253a712d553c7b4"},
{file = "numpy-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:e9e81fa9017eaa416c056e5d9e71be93d05e2c3c2ab308d23307a8bc4443c368"},
{file = "numpy-2.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61728fba1e464f789b11deb78a57805c70b2ed02343560456190d0501ba37b0f"},
{file = "numpy-2.0.1-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:12f5d865d60fb9734e60a60f1d5afa6d962d8d4467c120a1c0cda6eb2964437d"},
{file = "numpy-2.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eacf3291e263d5a67d8c1a581a8ebbcfd6447204ef58828caf69a5e3e8c75990"},
{file = "numpy-2.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2c3a346ae20cfd80b6cfd3e60dc179963ef2ea58da5ec074fd3d9e7a1e7ba97f"},
{file = "numpy-2.0.1.tar.gz", hash = "sha256:485b87235796410c3519a699cfe1faab097e509e90ebb05dcd098db2ae87e7b3"},
] ]
[[package]]
name = "pillow"
version = "11.0.0"
description = "Python Imaging Library (Fork)"
optional = false
python-versions = ">=3.9"
files = [
{file = "pillow-11.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6619654954dc4936fcff82db8eb6401d3159ec6be81e33c6000dfd76ae189947"},
{file = "pillow-11.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3c5ac4bed7519088103d9450a1107f76308ecf91d6dabc8a33a2fcfb18d0fba"},
{file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a65149d8ada1055029fcb665452b2814fe7d7082fcb0c5bed6db851cb69b2086"},
{file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9"},
{file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c26845094b1af3c91852745ae78e3ea47abf3dbcd1cf962f16b9a5fbe3ee8488"},
{file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f"},
{file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:674629ff60030d144b7bca2b8330225a9b11c482ed408813924619c6f302fdbb"},
{file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:598b4e238f13276e0008299bd2482003f48158e2b11826862b1eb2ad7c768b97"},
{file = "pillow-11.0.0-cp310-cp310-win32.whl", hash = "sha256:9a0f748eaa434a41fccf8e1ee7a3eed68af1b690e75328fd7a60af123c193b50"},
{file = "pillow-11.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:a5629742881bcbc1f42e840af185fd4d83a5edeb96475a575f4da50d6ede337c"},
{file = "pillow-11.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:ee217c198f2e41f184f3869f3e485557296d505b5195c513b2bfe0062dc537f1"},
{file = "pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc"},
{file = "pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a"},
{file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3"},
{file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5"},
{file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b"},
{file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa"},
{file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306"},
{file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9"},
{file = "pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5"},
{file = "pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291"},
{file = "pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9"},
{file = "pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923"},
{file = "pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903"},
{file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4"},
{file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f"},
{file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9"},
{file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7"},
{file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6"},
{file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc"},
{file = "pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6"},
{file = "pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47"},
{file = "pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25"},
{file = "pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699"},
{file = "pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38"},
{file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2"},
{file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2"},
{file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527"},
{file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa"},
{file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f"},
{file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb"},
{file = "pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798"},
{file = "pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de"},
{file = "pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84"},
{file = "pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b"},
{file = "pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003"},
{file = "pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2"},
{file = "pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a"},
{file = "pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8"},
{file = "pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8"},
{file = "pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904"},
{file = "pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3"},
{file = "pillow-11.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2e46773dc9f35a1dd28bd6981332fd7f27bec001a918a72a79b4133cf5291dba"},
{file = "pillow-11.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2679d2258b7f1192b378e2893a8a0a0ca472234d4c2c0e6bdd3380e8dfa21b6a"},
{file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eda2616eb2313cbb3eebbe51f19362eb434b18e3bb599466a1ffa76a033fb916"},
{file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ec184af98a121fb2da42642dea8a29ec80fc3efbaefb86d8fdd2606619045d"},
{file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:8594f42df584e5b4bb9281799698403f7af489fba84c34d53d1c4bfb71b7c4e7"},
{file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:c12b5ae868897c7338519c03049a806af85b9b8c237b7d675b8c5e089e4a618e"},
{file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:70fbbdacd1d271b77b7721fe3cdd2d537bbbd75d29e6300c672ec6bb38d9672f"},
{file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5178952973e588b3f1360868847334e9e3bf49d19e169bbbdfaf8398002419ae"},
{file = "pillow-11.0.0-cp39-cp39-win32.whl", hash = "sha256:8c676b587da5673d3c75bd67dd2a8cdfeb282ca38a30f37950511766b26858c4"},
{file = "pillow-11.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:94f3e1780abb45062287b4614a5bc0874519c86a777d4a7ad34978e86428b8dd"},
{file = "pillow-11.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:290f2cc809f9da7d6d622550bbf4c1e57518212da51b6a30fe8e0a270a5b78bd"},
{file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2"},
{file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2"},
{file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b"},
{file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21a0d3b115009ebb8ac3d2ebec5c2982cc693da935f4ab7bb5c8ebe2f47d36f2"},
{file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:73853108f56df97baf2bb8b522f3578221e56f646ba345a372c78326710d3830"},
{file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e58876c91f97b0952eb766123bfef372792ab3f4e3e1f1a2267834c2ab131734"},
{file = "pillow-11.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316"},
{file = "pillow-11.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5bd2d3bdb846d757055910f0a59792d33b555800813c3b39ada1829c372ccb06"},
{file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:375b8dd15a1f5d2feafff536d47e22f69625c1aa92f12b339ec0b2ca40263273"},
{file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:daffdf51ee5db69a82dd127eabecce20729e21f7a3680cf7cbb23f0829189790"},
{file = "pillow-11.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7326a1787e3c7b0429659e0a944725e1b03eeaa10edd945a86dead1913383944"},
{file = "pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739"},
]
[package.extras]
docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"]
fpx = ["olefile"]
mic = ["olefile"]
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
typing = ["typing-extensions"]
xmp = ["defusedxml"]
[[package]]
name = "popsicle"
version = "0.9.6"
description = "popsicle: Python integration for JUCE with pybind11."
optional = false
python-versions = ">=3.10"
files = [
{file = "popsicle-0.9.6-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:0abedd3790cfe63b14ac3aa46263993e8d859b2c1f769dad8e8685d9995e8e2e"},
{file = "popsicle-0.9.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10ef070c120e782d852eb47a55a187cf7276e8a759110bbbec713e5bbd0faf6a"},
{file = "popsicle-0.9.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2d51bd173da55f84aec6c2a3b5c4b8c0ac3742491a20110531fcc3a3f308bc"},
{file = "popsicle-0.9.6-cp310-cp310-win_amd64.whl", hash = "sha256:c55c6f840269a49b395626ce600c65078aeeda8c727d305d1dca7bded5cf587b"},
{file = "popsicle-0.9.6-cp310-cp310-win_arm64.whl", hash = "sha256:1e22ffb9aca2b468915d7c4b5bd7ce82cdf52ce86e1f4d54eacf6a033dd13c98"},
{file = "popsicle-0.9.6-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:d013f08cfd2c491d3f4a35b6477592bd58ece3d59c37a513b6d1e620f50145f1"},
{file = "popsicle-0.9.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cafbace5fb0df51aac0336cce47fc5208335c43670a103d1a7f8ee0f3094f118"},
{file = "popsicle-0.9.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95063399a42258b56b469ae31a380d6c2ddb4ab01d729a52300ee3e55ecececb"},
{file = "popsicle-0.9.6-cp311-cp311-win_amd64.whl", hash = "sha256:f30b6309b015f3a26a461223c19d7c8f962f42868575af076f15f71f53b58496"},
{file = "popsicle-0.9.6-cp311-cp311-win_arm64.whl", hash = "sha256:0d0eafff83b08b6ada954e897a0e07b17f6994398c1860a5a9560af402c8f6e9"},
{file = "popsicle-0.9.6-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:a42d53580ddbaca15e64e34c4971f83a862a95c5e50d3e1be5b127c4ff056e48"},
{file = "popsicle-0.9.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4429eeee549cf340b3bcc60e7244881b08b8357aeafc88a2a9aee9dd1e3b9fc1"},
{file = "popsicle-0.9.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11de3ccfb5a8f422f1532aaca835ab6907affcbf91ff45312ebcb1d424b4723f"},
{file = "popsicle-0.9.6-cp312-cp312-win_amd64.whl", hash = "sha256:ce7f79069151860a1bd43ba50e786d57c8db3e2f6e8538db45bb0ac67adba7f6"},
{file = "popsicle-0.9.6-cp312-cp312-win_arm64.whl", hash = "sha256:c40d8301b08690b041ed5710f0e9a63bf83c48ab51f5cf015b6fb7cf95921744"},
]
[[package]]
name = "psutil"
version = "6.1.0"
description = "Cross-platform lib for process and system monitoring in Python."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
files = [
{file = "psutil-6.1.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ff34df86226c0227c52f38b919213157588a678d049688eded74c76c8ba4a5d0"},
{file = "psutil-6.1.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c0e0c00aa18ca2d3b2b991643b799a15fc8f0563d2ebb6040f64ce8dc027b942"},
{file = "psutil-6.1.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:000d1d1ebd634b4efb383f4034437384e44a6d455260aaee2eca1e9c1b55f047"},
{file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5cd2bcdc75b452ba2e10f0e8ecc0b57b827dd5d7aaffbc6821b2a9a242823a76"},
{file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:045f00a43c737f960d273a83973b2511430d61f283a44c96bf13a6e829ba8fdc"},
{file = "psutil-6.1.0-cp27-none-win32.whl", hash = "sha256:9118f27452b70bb1d9ab3198c1f626c2499384935aaf55388211ad982611407e"},
{file = "psutil-6.1.0-cp27-none-win_amd64.whl", hash = "sha256:a8506f6119cff7015678e2bce904a4da21025cc70ad283a53b099e7620061d85"},
{file = "psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688"},
{file = "psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e"},
{file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38"},
{file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b"},
{file = "psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a"},
{file = "psutil-6.1.0-cp36-cp36m-win32.whl", hash = "sha256:6d3fbbc8d23fcdcb500d2c9f94e07b1342df8ed71b948a2649b5cb060a7c94ca"},
{file = "psutil-6.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1209036fbd0421afde505a4879dee3b2fd7b1e14fee81c0069807adcbbcca747"},
{file = "psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e"},
{file = "psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be"},
{file = "psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a"},
]
[package.extras]
dev = ["black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "wheel"]
test = ["pytest", "pytest-xdist", "setuptools"]
[[package]]
name = "py3dbp"
version = "1.1.2"
description = "3D Bin Packing"
optional = false
python-versions = "*"
files = [
{file = "py3dbp-1.1.2.tar.gz", hash = "sha256:d8c92c120eecfbee600a4dfd8b0a42d63459c97de67a26ff8ad39529a5125e07"},
]
[[package]]
name = "pybullet"
version = "3.2.6"
description = "Official Python Interface for the Bullet Physics SDK specialized for Robotics Simulation and Reinforcement Learning"
optional = false
python-versions = "*"
files = [
{file = "pybullet-3.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f71d0bed6824875b521066571d612274f1d2dead3ede50f8fbdde1946ec0c40"},
{file = "pybullet-3.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a476d51726efa7aabe1dc8c4ee676b78bcd9fc19d4a2ce9776f2c9a9dacd9e8b"},
{file = "pybullet-3.2.6-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8af791050e927f407a85fa9de15754fbe0973f8c798fd2893773b52fa1fc70e0"},
{file = "pybullet-3.2.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72be1e68c61bbe49af5b7c609d59ede92d3fbbfca072e9b31d4819575c8f332b"},
{file = "pybullet-3.2.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba46f9d8ae76d2bcae4bf4b5768b1dccc0b3b15110b69ba3d78cd0b11f8f21cf"},
{file = "pybullet-3.2.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f928444471186c5d6092d71371b03436e23ec96acd7800dfefcd8e96572c6581"},
{file = "pybullet-3.2.6.tar.gz", hash = "sha256:da27525433c88698dc9fd8bc20fa4ae4d07738b4656633659ebd82c2d2884e08"},
]
[[package]]
name = "pybullet-industrial"
version = "1.0.3"
description = "Pybullet_industrial is a process-aware robot simulation framework for pybullet."
optional = false
python-versions = "*"
files = [
{file = "pybullet_industrial-1.0.3-py3-none-any.whl", hash = "sha256:826db59d9451e360aa92470e4df7afceb09500bca391cfb136753cfc87beed53"},
{file = "pybullet_industrial-1.0.3.tar.gz", hash = "sha256:b7a3f263e305ce269ec3bd464106f03886a13c29da5eb5de35e0980c7d9ac8da"},
]
[package.dependencies]
numpy = "*"
pybullet = "*"
scipy = "*"
[[package]] [[package]]
name = "pymodbus" name = "pymodbus"
version = "3.7.0" version = "3.7.4"
description = "A fully featured modbus protocol stack in python" description = "A fully featured modbus protocol stack in python"
optional = false optional = false
python-versions = ">=3.9.0" python-versions = ">=3.9.0"
files = [ files = [
{file = "pymodbus-3.7.0-py3-none-any.whl", hash = "sha256:4d4caedea604e294d9a39248dcac05e903e6143e5adfe49aa7edb79d461527e1"}, {file = "pymodbus-3.7.4-py3-none-any.whl", hash = "sha256:dfb45ef9a2c1663875ad32378f780b5824628cd3c0a486851e64b8a3341a3e82"},
{file = "pymodbus-3.7.0.tar.gz", hash = "sha256:5c772babaa61a65ff908293faa668aedcd9d9e10f4bcf5c77a8fe51a6fd9ed47"}, {file = "pymodbus-3.7.4.tar.gz", hash = "sha256:573c370aea04523403eea1e159616a583cd7b93cfc5c81b07340d3cccd52c99f"},
] ]
[package.extras] [package.extras]
all = ["pymodbus[development,documentation,repl,serial,simulator]"] all = ["pymodbus[development,documentation,repl,serial,simulator]"]
development = ["build (>=1.2.1)", "codespell (>=2.3.0)", "coverage (>=7.6.0)", "mypy (>=1.10.1)", "pylint (>=3.2.5)", "pytest (>=8.2.2)", "pytest-asyncio (>=0.23.8)", "pytest-cov (>=5.0.0)", "pytest-profiling (>=1.7.0)", "pytest-timeout (>=2.3.1)", "pytest-xdist (>=3.6.1)", "ruff (>=0.5.3)", "twine (>=5.1.1)", "types-Pygments", "types-pyserial"] development = ["build (>=1.2.2)", "codespell (>=2.3.0)", "coverage (>=7.6.1)", "mypy (>=1.11.2)", "pylint (>=3.3.0)", "pytest (>=8.3.3)", "pytest-aiohttp (>=1.0.5)", "pytest-asyncio (>=0.24.0)", "pytest-cov (>=5.0.0)", "pytest-profiling (>=1.7.0)", "pytest-timeout (>=2.3.1)", "pytest-xdist (>=3.6.1)", "ruff (>=0.5.3)", "twine (>=5.1.1)", "types-Pygments", "types-pyserial"]
documentation = ["Sphinx (>=7.3.7)", "recommonmark (>=0.7.1)", "sphinx-rtd-theme (>=2.0.0)"] documentation = ["Sphinx (>=7.3.7)", "recommonmark (>=0.7.1)", "sphinx-rtd-theme (>=2.0.0)"]
repl = ["pymodbus-repl (>=2.0.3)"] repl = ["pymodbus-repl (>=2.0.4)"]
serial = ["pyserial (>=3.5)"] serial = ["pyserial (>=3.5)"]
simulator = ["aiohttp (>=3.8.6)", "aiohttp (>=3.9.5)"] simulator = ["aiohttp (>=3.10.5)", "aiohttp (>=3.8.6)"]
[[package]] [[package]]
name = "pymodbus3" name = "pyqt6"
version = "1.0.0" version = "6.7.1"
description = "A fully featured modbus protocol stack in python" description = "Python bindings for the Qt cross platform application toolkit"
optional = false optional = false
python-versions = "*" python-versions = ">=3.8"
files = [ files = [
{file = "pymodbus3-1.0.0.tar.gz", hash = "sha256:4a340660a5e56a8f2f945e650b00b78c0bfce05911140338101b37d3b9ed3f8c"}, {file = "PyQt6-6.7.1-1-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7f397f4b38b23b5588eb2c0933510deb953d96b1f0323a916c4839c2a66ccccc"},
{file = "PyQt6-6.7.1-1-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2f202b7941aa74e5c7e1463a6f27d9131dbc1e6cabe85571d7364f5b3de7397"},
{file = "PyQt6-6.7.1-cp38-abi3-macosx_11_0_universal2.whl", hash = "sha256:f053378e3aef6248fa612c8afddda17f942fb63f9fe8a9aeb2a6b6b4cbb0eba9"},
{file = "PyQt6-6.7.1-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0adb7914c732ad1dee46d9cec838a98cb2b11bc38cc3b7b36fbd8701ae64bf47"},
{file = "PyQt6-6.7.1-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2d771fa0981514cb1ee937633dfa64f14caa902707d9afffab66677f3a73e3da"},
{file = "PyQt6-6.7.1-cp38-abi3-win_amd64.whl", hash = "sha256:fa3954698233fe286a8afc477b84d8517f0788eb46b74da69d3ccc0170d3714c"},
{file = "PyQt6-6.7.1.tar.gz", hash = "sha256:3672a82ccd3a62e99ab200a13903421e2928e399fda25ced98d140313ad59cb9"},
] ]
[package.dependencies] [package.dependencies]
pyserial = ">=2.6" PyQt6-Qt6 = ">=6.7.0,<6.8.0"
twisted = ">=12.2.0" PyQt6-sip = ">=13.8,<14"
[package.extras]
documents = ["sphinx (>=1.1.3)"]
quality = ["coverage (>=3.5.3)", "mock (>=1.0.0)", "nose (>=1.2.1)", "pep8 (>=1.3.3)"]
twisted = ["pyasn1 (>=0.1.4)", "pycrypto (>=2.6)"]
[[package]] [[package]]
name = "pymodbustcp" name = "pyqt6-qt6"
version = "0.2.2" version = "6.7.3"
description = "A simple Modbus/TCP library for Python" description = "The subset of a Qt installation needed by PyQt6."
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
{file = "pyModbusTCP-0.2.2-py3-none-any.whl", hash = "sha256:6f018792c891b725da99d978c7d156c71340fa26d389d22310f99bf5829ce773"}, {file = "PyQt6_Qt6-6.7.3-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:f517a93b6b1a814d4aa6587adc312e812ebaf4d70415bb15cfb44268c5ad3f5f"},
{file = "pyModbusTCP-0.2.2.tar.gz", hash = "sha256:30ed8bdba98ef8c423aa8421be454d5079fd5952ef78557f287ec263c57b5ba6"}, {file = "PyQt6_Qt6-6.7.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:8551732984fb36a5f4f3db51eafc4e8e6caf18617365830285306f2db17a94c2"},
{file = "PyQt6_Qt6-6.7.3-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:50c7482bcdcf2bb78af257fb10ed8b582f8daf91d829782393bc50ac5a0a900c"},
{file = "PyQt6_Qt6-6.7.3-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:cb525fdd393332de60887953029276a44de480fce1d785251ae639580f5e7246"},
{file = "PyQt6_Qt6-6.7.3-py3-none-win_amd64.whl", hash = "sha256:36ea0892b8caeb983af3f285f45fb8dfbb93cfd972439f4e01b7efb2868f6230"},
] ]
[[package]] [[package]]
name = "pyserial" name = "pyqt6-sip"
version = "3.5" version = "13.8.0"
description = "Python Serial Port Extension" description = "The sip module support for PyQt6"
optional = false optional = false
python-versions = "*" python-versions = ">=3.8"
files = [ files = [
{file = "pyserial-3.5-py2.py3-none-any.whl", hash = "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0"}, {file = "PyQt6_sip-13.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cedd554c643e54c4c2e12b5874781a87441a1b405acf3650a4a2e1df42aae231"},
{file = "pyserial-3.5.tar.gz", hash = "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb"}, {file = "PyQt6_sip-13.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f57275b5af774529f9838adcfb58869ba3ebdaf805daea113bb0697a96a3f3cb"},
{file = "PyQt6_sip-13.8.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:835ed22eab977f75fd77e60d4ff308a1fa794b1d0c04849311f36d2a080cdf3b"},
{file = "PyQt6_sip-13.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d8b22a6850917c68ce83fc152a8b606ecb2efaaeed35be53110468885d6cdd9d"},
{file = "PyQt6_sip-13.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b203b6fbae4a8f2d27f35b7df46200057033d9ecd9134bcf30e3eab66d43572c"},
{file = "PyQt6_sip-13.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:beaddc1ec96b342f4e239702f91802706a80cb403166c2da318cec4ad8b790cb"},
{file = "PyQt6_sip-13.8.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5c086b7c9c7996ea9b7522646cc24eebbf3591ec9dd38f65c0a3fdb0dbeaac7"},
{file = "PyQt6_sip-13.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:dd168667addf01f8a4b0fa7755323e43e4cd12ca4bade558c61f713a5d48ba1a"},
{file = "PyQt6_sip-13.8.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:33d9b399fc9c9dc99496266842b0fb2735d924604774e97cf9b555667cc0fc59"},
{file = "PyQt6_sip-13.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:056af69d1d8d28d5968066ec5da908afd82fc0be07b67cf2b84b9f02228416ce"},
{file = "PyQt6_sip-13.8.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:08dd81037a2864982ece2bf9891f3bf4558e247034e112993ea1a3fe239458cb"},
{file = "PyQt6_sip-13.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:fbb249b82c53180f1420571ece5dc24fea1188ba435923edd055599dffe7abfb"},
{file = "PyQt6_sip-13.8.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:6bce6bc5870d9e87efe5338b1ee4a7b9d7d26cdd16a79a5757d80b6f25e71edc"},
{file = "PyQt6_sip-13.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd81144b0770084e8005d3a121c9382e6f9bc8d0bb320dd618718ffe5090e0e6"},
{file = "PyQt6_sip-13.8.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:755beb5d271d081e56618fb30342cdd901464f721450495cb7cb0212764da89e"},
{file = "PyQt6_sip-13.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:7a0bbc0918eab5b6351735d40cf22cbfa5aa2476b55e0d5fe881aeed7d871c29"},
{file = "PyQt6_sip-13.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7f84c472afdc7d316ff683f63129350d645ef82d9b3fd75a609b08472d1f7291"},
{file = "PyQt6_sip-13.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1bf29e95f10a8a00819dac804ca7e5eba5fc1769adcd74c837c11477bf81954"},
{file = "PyQt6_sip-13.8.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9ea9223c94906efd68148f12ae45b51a21d67e86704225ddc92bce9c54e4d93c"},
{file = "PyQt6_sip-13.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:2559afa68825d08de09d71c42f3b6ad839dcc30f91e7c6d0785e07830d5541a5"},
{file = "PyQt6_sip-13.8.0.tar.gz", hash = "sha256:2f74cf3d6d9cab5152bd9f49d570b2dfb87553ebb5c4919abfde27f5b9fd69d4"},
] ]
[package.extras]
cp2110 = ["hidapi"]
[[package]] [[package]]
name = "scipy" name = "scipy"
version = "1.14.0" version = "1.14.1"
description = "Fundamental algorithms for scientific computing in Python" description = "Fundamental algorithms for scientific computing in Python"
optional = false optional = false
python-versions = ">=3.10" python-versions = ">=3.10"
files = [ files = [
{file = "scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484"}, {file = "scipy-1.14.1-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:b28d2ca4add7ac16ae8bb6632a3c86e4b9e4d52d3e34267f6e1b0c1f8d87e389"},
{file = "scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6"}, {file = "scipy-1.14.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d0d2821003174de06b69e58cef2316a6622b60ee613121199cb2852a873f8cf3"},
{file = "scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7"}, {file = "scipy-1.14.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8bddf15838ba768bb5f5083c1ea012d64c9a444e16192762bd858f1e126196d0"},
{file = "scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1"}, {file = "scipy-1.14.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:97c5dddd5932bd2a1a31c927ba5e1463a53b87ca96b5c9bdf5dfd6096e27efc3"},
{file = "scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0"}, {file = "scipy-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ff0a7e01e422c15739ecd64432743cf7aae2b03f3084288f399affcefe5222d"},
{file = "scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0"}, {file = "scipy-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e32dced201274bf96899e6491d9ba3e9a5f6b336708656466ad0522d8528f69"},
{file = "scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d"}, {file = "scipy-1.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8426251ad1e4ad903a4514712d2fa8fdd5382c978010d1c6f5f37ef286a713ad"},
{file = "scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359"}, {file = "scipy-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:a49f6ed96f83966f576b33a44257d869756df6cf1ef4934f59dd58b25e0327e5"},
{file = "scipy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6d056a8709ccda6cf36cdd2eac597d13bc03dba38360f418560a93050c76a16e"}, {file = "scipy-1.14.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:2da0469a4ef0ecd3693761acbdc20f2fdeafb69e6819cc081308cc978153c675"},
{file = "scipy-1.14.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f0a50da861a7ec4573b7c716b2ebdcdf142b66b756a0d392c236ae568b3a93fb"}, {file = "scipy-1.14.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c0ee987efa6737242745f347835da2cc5bb9f1b42996a4d97d5c7ff7928cb6f2"},
{file = "scipy-1.14.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:94c164a9e2498e68308e6e148646e486d979f7fcdb8b4cf34b5441894bdb9caf"}, {file = "scipy-1.14.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3a1b111fac6baec1c1d92f27e76511c9e7218f1695d61b59e05e0fe04dc59617"},
{file = "scipy-1.14.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a7d46c3e0aea5c064e734c3eac5cf9eb1f8c4ceee756262f2c7327c4c2691c86"}, {file = "scipy-1.14.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8475230e55549ab3f207bff11ebfc91c805dc3463ef62eda3ccf593254524ce8"},
{file = "scipy-1.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eee2989868e274aae26125345584254d97c56194c072ed96cb433f32f692ed8"}, {file = "scipy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:278266012eb69f4a720827bdd2dc54b2271c97d84255b2faaa8f161a158c3b37"},
{file = "scipy-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3154691b9f7ed73778d746da2df67a19d046a6c8087c8b385bc4cdb2cfca74"}, {file = "scipy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fef8c87f8abfb884dac04e97824b61299880c43f4ce675dd2cbeadd3c9b466d2"},
{file = "scipy-1.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c40003d880f39c11c1edbae8144e3813904b10514cd3d3d00c277ae996488cdb"}, {file = "scipy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b05d43735bb2f07d689f56f7b474788a13ed8adc484a85aa65c0fd931cf9ccd2"},
{file = "scipy-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:5b083c8940028bb7e0b4172acafda6df762da1927b9091f9611b0bcd8676f2bc"}, {file = "scipy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:716e389b694c4bb564b4fc0c51bc84d381735e0d39d3f26ec1af2556ec6aad94"},
{file = "scipy-1.14.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bff2438ea1330e06e53c424893ec0072640dac00f29c6a43a575cbae4c99b2b9"}, {file = "scipy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:631f07b3734d34aced009aaf6fedfd0eb3498a97e581c3b1e5f14a04164a456d"},
{file = "scipy-1.14.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:bbc0471b5f22c11c389075d091d3885693fd3f5e9a54ce051b46308bc787e5d4"}, {file = "scipy-1.14.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:af29a935803cc707ab2ed7791c44288a682f9c8107bc00f0eccc4f92c08d6e07"},
{file = "scipy-1.14.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:64b2ff514a98cf2bb734a9f90d32dc89dc6ad4a4a36a312cd0d6327170339eb0"}, {file = "scipy-1.14.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2843f2d527d9eebec9a43e6b406fb7266f3af25a751aa91d62ff416f54170bc5"},
{file = "scipy-1.14.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:7d3da42fbbbb860211a811782504f38ae7aaec9de8764a9bef6b262de7a2b50f"}, {file = "scipy-1.14.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:eb58ca0abd96911932f688528977858681a59d61a7ce908ffd355957f7025cfc"},
{file = "scipy-1.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d91db2c41dd6c20646af280355d41dfa1ec7eead235642178bd57635a3f82209"}, {file = "scipy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30ac8812c1d2aab7131a79ba62933a2a76f582d5dbbc695192453dae67ad6310"},
{file = "scipy-1.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a01cc03bcdc777c9da3cfdcc74b5a75caffb48a6c39c8450a9a05f82c4250a14"}, {file = "scipy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f9ea80f2e65bdaa0b7627fb00cbeb2daf163caa015e59b7516395fe3bd1e066"},
{file = "scipy-1.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:65df4da3c12a2bb9ad52b86b4dcf46813e869afb006e58be0f516bc370165159"}, {file = "scipy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:edaf02b82cd7639db00dbff629995ef185c8df4c3ffa71a5562a595765a06ce1"},
{file = "scipy-1.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:4c4161597c75043f7154238ef419c29a64ac4a7c889d588ea77690ac4d0d9b20"}, {file = "scipy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2ff38e22128e6c03ff73b6bb0f85f897d2362f8c052e3b8ad00532198fbdae3f"},
{file = "scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b"}, {file = "scipy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1729560c906963fc8389f6aac023739ff3983e727b1a4d87696b7bf108316a79"},
{file = "scipy-1.14.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:4079b90df244709e675cdc8b93bfd8a395d59af40b72e339c2287c91860deb8e"},
{file = "scipy-1.14.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e0cf28db0f24a38b2a0ca33a85a54852586e43cf6fd876365c86e0657cfe7d73"},
{file = "scipy-1.14.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0c2f95de3b04e26f5f3ad5bb05e74ba7f68b837133a4492414b3afd79dfe540e"},
{file = "scipy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b99722ea48b7ea25e8e015e8341ae74624f72e5f21fc2abd45f3a93266de4c5d"},
{file = "scipy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5149e3fd2d686e42144a093b206aef01932a0059c2a33ddfa67f5f035bdfe13e"},
{file = "scipy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4f5a7c49323533f9103d4dacf4e4f07078f360743dec7f7596949149efeec06"},
{file = "scipy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:baff393942b550823bfce952bb62270ee17504d02a1801d7fd0719534dfb9c84"},
{file = "scipy-1.14.1.tar.gz", hash = "sha256:5a275584e726026a5699459aa72f828a610821006228e841b94275c4a7c08417"},
] ]
[package.dependencies] [package.dependencies]
@ -260,62 +363,28 @@ numpy = ">=1.23.5,<2.3"
[package.extras] [package.extras]
dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"]
doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.13.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.13.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<=7.3.7)", "sphinx-design (>=0.4.0)"]
test = ["Cython", "array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] test = ["Cython", "array-api-strict (>=2.0)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"]
[[package]] [[package]]
name = "setuptools" name = "setuptools"
version = "72.1.0" version = "75.4.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages" description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.9"
files = [ files = [
{file = "setuptools-72.1.0-py3-none-any.whl", hash = "sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1"}, {file = "setuptools-75.4.0-py3-none-any.whl", hash = "sha256:b3c5d862f98500b06ffdf7cc4499b48c46c317d8d56cb30b5c8bce4d88f5c216"},
{file = "setuptools-72.1.0.tar.gz", hash = "sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec"}, {file = "setuptools-75.4.0.tar.gz", hash = "sha256:1dc484f5cf56fd3fe7216d7b8df820802e7246cfb534a1db2aa64f14fcb9cdcb"},
] ]
[package.extras] [package.extras]
core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.7.0)"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] core = ["importlib-metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"]
test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
[[package]] enabler = ["pytest-enabler (>=2.2)"]
name = "six" test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"]
version = "1.16.0" type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.12,<1.14)", "pytest-mypy"]
description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
files = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
[[package]]
name = "svgpathtools"
version = "1.6.1"
description = "A collection of tools for manipulating and analyzing SVG Path objects and Bezier curves."
optional = false
python-versions = "*"
files = [
{file = "svgpathtools-1.6.1-py2.py3-none-any.whl", hash = "sha256:39967f9a817b8a12cc6dd1646fc162d522fca6c3fd5f8c94913c15ee4cb3a906"},
{file = "svgpathtools-1.6.1.tar.gz", hash = "sha256:7054e6de1953e295bf565d535d585695453b09f8db4a2f7c4853348732097a3e"},
]
[package.dependencies]
numpy = "*"
scipy = "*"
svgwrite = "*"
[[package]]
name = "svgwrite"
version = "1.4.3"
description = "A Python library to create SVG drawings."
optional = false
python-versions = ">=3.6"
files = [
{file = "svgwrite-1.4.3-py3-none-any.whl", hash = "sha256:bb6b2b5450f1edbfa597d924f9ac2dd099e625562e492021d7dd614f65f8a22d"},
{file = "svgwrite-1.4.3.zip", hash = "sha256:a8fbdfd4443302a6619a7f76bc937fc683daf2628d9b737c891ec08b8ce524c3"},
]
[[package]] [[package]]
name = "tk" name = "tk"
@ -328,144 +397,7 @@ files = [
{file = "tk-0.1.0.tar.gz", hash = "sha256:60bc8923d5d35f67f5c6bd93d4f0c49d2048114ec077768f959aef36d4ed97f8"}, {file = "tk-0.1.0.tar.gz", hash = "sha256:60bc8923d5d35f67f5c6bd93d4f0c49d2048114ec077768f959aef36d4ed97f8"},
] ]
[[package]]
name = "tomli"
version = "2.0.1"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.7"
files = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
[[package]]
name = "twisted"
version = "24.3.0"
description = "An asynchronous networking framework written in Python"
optional = false
python-versions = ">=3.8.0"
files = [
{file = "twisted-24.3.0-py3-none-any.whl", hash = "sha256:039f2e6a49ab5108abd94de187fa92377abe5985c7a72d68d0ad266ba19eae63"},
{file = "twisted-24.3.0.tar.gz", hash = "sha256:6b38b6ece7296b5e122c9eb17da2eeab3d98a198f50ca9efd00fb03e5b4fd4ae"},
]
[package.dependencies]
attrs = ">=21.3.0"
automat = ">=0.8.0"
constantly = ">=15.1"
hyperlink = ">=17.1.1"
incremental = ">=22.10.0"
twisted-iocpsupport = {version = ">=1.0.2,<2", markers = "platform_system == \"Windows\""}
typing-extensions = ">=4.2.0"
zope-interface = ">=5"
[package.extras]
all-non-platform = ["twisted[conch,http2,serial,test,tls]", "twisted[conch,http2,serial,test,tls]"]
conch = ["appdirs (>=1.4.0)", "bcrypt (>=3.1.3)", "cryptography (>=3.3)"]
dev = ["coverage (>=6b1,<7)", "pyflakes (>=2.2,<3.0)", "python-subunit (>=1.4,<2.0)", "twisted[dev-release]", "twistedchecker (>=0.7,<1.0)"]
dev-release = ["pydoctor (>=23.9.0,<23.10.0)", "pydoctor (>=23.9.0,<23.10.0)", "sphinx (>=6,<7)", "sphinx (>=6,<7)", "sphinx-rtd-theme (>=1.3,<2.0)", "sphinx-rtd-theme (>=1.3,<2.0)", "towncrier (>=23.6,<24.0)", "towncrier (>=23.6,<24.0)"]
gtk-platform = ["pygobject", "pygobject", "twisted[all-non-platform]", "twisted[all-non-platform]"]
http2 = ["h2 (>=3.0,<5.0)", "priority (>=1.1.0,<2.0)"]
macos-platform = ["pyobjc-core", "pyobjc-core", "pyobjc-framework-cfnetwork", "pyobjc-framework-cfnetwork", "pyobjc-framework-cocoa", "pyobjc-framework-cocoa", "twisted[all-non-platform]", "twisted[all-non-platform]"]
mypy = ["mypy (>=1.8,<2.0)", "mypy-zope (>=1.0.3,<1.1.0)", "twisted[all-non-platform,dev]", "types-pyopenssl", "types-setuptools"]
osx-platform = ["twisted[macos-platform]", "twisted[macos-platform]"]
serial = ["pyserial (>=3.0)", "pywin32 (!=226)"]
test = ["cython-test-exception-raiser (>=1.0.2,<2)", "hypothesis (>=6.56)", "pyhamcrest (>=2)"]
tls = ["idna (>=2.4)", "pyopenssl (>=21.0.0)", "service-identity (>=18.1.0)"]
windows-platform = ["pywin32 (!=226)", "pywin32 (!=226)", "twisted[all-non-platform]", "twisted[all-non-platform]"]
[[package]]
name = "twisted-iocpsupport"
version = "1.0.4"
description = "An extension for use in the twisted I/O Completion Ports reactor."
optional = false
python-versions = "*"
files = [
{file = "twisted-iocpsupport-1.0.4.tar.gz", hash = "sha256:858096c0d15e33f15ac157f455d8f86f2f2cdd223963e58c0f682a3af8362d89"},
{file = "twisted_iocpsupport-1.0.4-cp310-cp310-win32.whl", hash = "sha256:afa2b630797f9ed2f27f3d9f55e3f72b4244911e45a8c82756f44babbf0b243e"},
{file = "twisted_iocpsupport-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:0058c963c8957bcd3deda62122e89953c9de1e867a274facc9b15dde1a9f31e8"},
{file = "twisted_iocpsupport-1.0.4-cp311-cp311-win32.whl", hash = "sha256:196f7c7ccad4ba4d1783b1c4e1d1b22d93c04275cd780bf7498d16c77319ad6e"},
{file = "twisted_iocpsupport-1.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:4e5f97bcbabdd79cbaa969b63439b89801ea560f11d42b0a387634275c633623"},
{file = "twisted_iocpsupport-1.0.4-cp312-cp312-win32.whl", hash = "sha256:6081bd7c2f4fcf9b383dcdb3b3385d75a26a7c9d2be25b6950c3d8ea652d2d2d"},
{file = "twisted_iocpsupport-1.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:76f7e67cec1f1d097d1f4ed7de41be3d74546e1a4ede0c7d56e775c4dce5dfb0"},
{file = "twisted_iocpsupport-1.0.4-cp36-cp36m-win32.whl", hash = "sha256:3d306fc4d88a6bcf61ce9d572c738b918578121bfd72891625fab314549024b5"},
{file = "twisted_iocpsupport-1.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:391ac4d6002a80e15f35adc4ad6056f4fe1c17ceb0d1f98ba01b0f4f917adfd7"},
{file = "twisted_iocpsupport-1.0.4-cp37-cp37m-win32.whl", hash = "sha256:0c1b5cf37f0b2d96cc3c9bc86fff16613b9f5d0ca565c96cf1f1fb8cfca4b81c"},
{file = "twisted_iocpsupport-1.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:3c5dc11d72519e55f727320e3cee535feedfaee09c0f0765ed1ca7badff1ab3c"},
{file = "twisted_iocpsupport-1.0.4-cp38-cp38-win32.whl", hash = "sha256:cc86c2ef598c15d824a243c2541c29459881c67fc3c0adb6efe2242f8f0ec3af"},
{file = "twisted_iocpsupport-1.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:c27985e949b9b1a1fb4c20c71d315c10ea0f93fdf3ccdd4a8c158b5926edd8c8"},
{file = "twisted_iocpsupport-1.0.4-cp39-cp39-win32.whl", hash = "sha256:e311dfcb470696e3c077249615893cada598e62fa7c4e4ca090167bd2b7d331f"},
{file = "twisted_iocpsupport-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:4574eef1f3bb81501fb02f911298af3c02fe8179c31a33b361dd49180c3e644d"},
{file = "twisted_iocpsupport-1.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:872747a3b64e2909aee59c803ccd0bceb9b75bf27915520ebd32d69687040fa2"},
{file = "twisted_iocpsupport-1.0.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:c2712b778bacf1db434e3e065adfed3db300754186a29aecac1efae9ef4bcaff"},
{file = "twisted_iocpsupport-1.0.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7c66fa0aa4236b27b3c61cb488662d85dae746a6d1c7b0d91cf7aae118445adf"},
{file = "twisted_iocpsupport-1.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:300437af17396a945a58dcfffd77863303a8b6d9e65c6e81f1d2eed55b50d444"},
]
[[package]]
name = "typing-extensions"
version = "4.12.2"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
]
[[package]]
name = "zope-interface"
version = "7.0.1"
description = "Interfaces for Python"
optional = false
python-versions = ">=3.8"
files = [
{file = "zope.interface-7.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ec4e87e6fdc511a535254daa122c20e11959ce043b4e3425494b237692a34f1c"},
{file = "zope.interface-7.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:51d5713e8e38f2d3ec26e0dfdca398ed0c20abda2eb49ffc15a15a23eb8e5f6d"},
{file = "zope.interface-7.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea8d51e5eb29e57d34744369cd08267637aa5a0fefc9b5d33775ab7ff2ebf2e3"},
{file = "zope.interface-7.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55bbcc74dc0c7ab489c315c28b61d7a1d03cf938cc99cc58092eb065f120c3a5"},
{file = "zope.interface-7.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10ebac566dd0cec66f942dc759d46a994a2b3ba7179420f0e2130f88f8a5f400"},
{file = "zope.interface-7.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:7039e624bcb820f77cc2ff3d1adcce531932990eee16121077eb51d9c76b6c14"},
{file = "zope.interface-7.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03bd5c0db82237bbc47833a8b25f1cc090646e212f86b601903d79d7e6b37031"},
{file = "zope.interface-7.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f52050c6a10d4a039ec6f2c58e5b3ade5cc570d16cf9d102711e6b8413c90e6"},
{file = "zope.interface-7.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af0b33f04677b57843d529b9257a475d2865403300b48c67654c40abac2f9f24"},
{file = "zope.interface-7.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:696c2a381fc7876b3056711717dba5eddd07c2c9e5ccd50da54029a1293b6e43"},
{file = "zope.interface-7.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f89a420cf5a6f2aa7849dd59e1ff0e477f562d97cf8d6a1ee03461e1eec39887"},
{file = "zope.interface-7.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:b59deb0ddc7b431e41d720c00f99d68b52cb9bd1d5605a085dc18f502fe9c47f"},
{file = "zope.interface-7.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52f5253cca1b35eaeefa51abd366b87f48f8714097c99b131ba61f3fdbbb58e7"},
{file = "zope.interface-7.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88d108d004e0df25224de77ce349a7e73494ea2cb194031f7c9687e68a88ec9b"},
{file = "zope.interface-7.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c203d82069ba31e1f3bc7ba530b2461ec86366cd4bfc9b95ec6ce58b1b559c34"},
{file = "zope.interface-7.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f3495462bc0438b76536a0e10d765b168ae636092082531b88340dc40dcd118"},
{file = "zope.interface-7.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:192b7a792e3145ed880ff6b1a206fdb783697cfdb4915083bfca7065ec845e60"},
{file = "zope.interface-7.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:400d06c9ec8dbcc96f56e79376297e7be07a315605c9a2208720da263d44d76f"},
{file = "zope.interface-7.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c1dff87b30fd150c61367d0e2cdc49bb55f8b9fd2a303560bbc24b951573ae1"},
{file = "zope.interface-7.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f749ca804648d00eda62fe1098f229b082dfca930d8bad8386e572a6eafa7525"},
{file = "zope.interface-7.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ec212037becf6d2f705b7ed4538d56980b1e7bba237df0d8995cbbed29961dc"},
{file = "zope.interface-7.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d33cb526efdc235a2531433fc1287fcb80d807d5b401f9b801b78bf22df560dd"},
{file = "zope.interface-7.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b419f2144e1762ab845f20316f1df36b15431f2622ebae8a6d5f7e8e712b413c"},
{file = "zope.interface-7.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03f1452d5d1f279184d5bdb663a3dc39902d9320eceb63276240791e849054b6"},
{file = "zope.interface-7.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ba4b3638d014918b918aa90a9c8370bd74a03abf8fcf9deb353b3a461a59a84"},
{file = "zope.interface-7.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc0615351221926a36a0fbcb2520fb52e0b23e8c22a43754d9cb8f21358c33c0"},
{file = "zope.interface-7.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:ce6cbb852fb8f2f9bb7b9cdca44e2e37bce783b5f4c167ff82cb5f5128163c8f"},
{file = "zope.interface-7.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5566fd9271c89ad03d81b0831c37d46ae5e2ed211122c998637130159a120cf1"},
{file = "zope.interface-7.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da0cef4d7e3f19c3bd1d71658d6900321af0492fee36ec01b550a10924cffb9c"},
{file = "zope.interface-7.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f32ca483e6ade23c7caaee9d5ee5d550cf4146e9b68d2fb6c68bac183aa41c37"},
{file = "zope.interface-7.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da21e7eec49252df34d426c2ee9cf0361c923026d37c24728b0fa4cc0599fd03"},
{file = "zope.interface-7.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a8195b99e650e6f329ce4e5eb22d448bdfef0406404080812bc96e2a05674cb"},
{file = "zope.interface-7.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:19c829d52e921b9fe0b2c0c6a8f9a2508c49678ee1be598f87d143335b6a35dc"},
{file = "zope.interface-7.0.1.tar.gz", hash = "sha256:f0f5fda7cbf890371a59ab1d06512da4f2c89a6ea194e595808123c863c38eff"},
]
[package.dependencies]
setuptools = "*"
[package.extras]
docs = ["Sphinx", "repoze.sphinx.autointerface", "sphinx-rtd-theme"]
test = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "3.10.12" python-versions = "^3.10.11"
content-hash = "a224728a18ef19c1f754e77db7d8cba413724a9a4257af5704b0fad93f833c58" content-hash = "6d16510fd35519dee80acbeb09936403172391cc840df3b5be874e6eab27f242"

39
pybullet_server.spec Normal file
View File

@ -0,0 +1,39 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['utils/pybullet_server.py'],
pathex=['.', './.venv', './.venv/Lib', './.venv/Lib/site-packages'],
binaries=[],
datas=[('pyproject.toml', '.'), ('robots.json', '.'), ('urdf', 'urdf'), ('data', 'data')],
hiddenimports=['libpython3.10', 'numpy'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='pybullet_server',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
contents_directory='test',
)

View File

@ -4,16 +4,21 @@ version = "0.1.0"
description = "" description = ""
authors = ["aarizona <ar.ariz.arizona@gmail.com>"] authors = ["aarizona <ar.ariz.arizona@gmail.com>"]
readme = "README.md" readme = "README.md"
package-mode = false
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "3.10.12" python = "^3.10.11"
modbus = "^3.2"
pymodbustcp = "^0.2.2"
pymodbus = "^3.7.0" pymodbus = "^3.7.0"
pymodbus3 = "^1.0.0"
svgpathtools = "^1.6.1"
tk = "^0.1.0" tk = "^0.1.0"
pybullet = "^3.2.5"
numpy = "^1.23.3"
popsicle = "^0.9.6"
pillow = "^11.0.0"
pyqt6 = "^6.7.1"
setuptools = "^75.3.0"
psutil = "^6.1.0"
pybullet-industrial = "^1.0.3"
py3dbp = "^1.1.2"
[build-system] [build-system]
requires = ["poetry-core"] requires = ["poetry-core"]

1
robot/__init__.py Normal file
View File

@ -0,0 +1 @@
from .client_socket import SocketRobotArm

View File

@ -8,23 +8,25 @@ import tkinter as tk
from func import * from func import *
window = tk.Tk() window = tk.Tk()
window.geometry('520x300') window.geometry("520x300")
label = tk.Label(window, text="Hello, world!") label = tk.Label(window, text="Hello, world!")
label.pack() label.pack()
all_files = glob.glob("data/data.txt") all_files = glob.glob("data/*.nc")
file = all_files[0] file = all_files[0]
data = [] data = [
with open(file, "r") as fp: ("line", 0, 0, 277.8, 0, 5, 0),
lines = fp.readlines() ]
for l in lines: # with open(file, "r") as fp:
r = l.strip().split(",") # lines = fp.readlines()
r[1] = float(r[1]) # for l in lines:
r[2] = float(r[2]) # r = l.strip().split(",")
r[3] = float(r[3]) # r[1] = float(r[1])
# r[2] = float(r[2])
# r[3] = float(r[3])
data.append(r) # data.append(r)
client = ModbusTcpClient( client = ModbusTcpClient(
host=MODBUS_SERVER_HOST, host=MODBUS_SERVER_HOST,
@ -113,5 +115,5 @@ except Exception as e:
finally: finally:
client.close() client.close()
if __name__=="__main__": if __name__ == "__main__":
window.mainloop() window.mainloop()

456
robot/client_socket.py Normal file
View File

@ -0,0 +1,456 @@
import socket
import json
import os
import math
import numpy as np
from typing import Literal
from pprint import pprint
import threading
import pybullet as p
import pybullet_industrial as pi
from logger import logger
from robot.func import *
from robot.prepare_data import PrepareRobotData
from robot.urdf_manager import UrdfManager
from robot.socket_manager import SocketManager
# os.environ["LIBGL_ALWAYS_SOFTWARE"] = "1"
class SocketRobotArm:
global_speed = 10
physical_speed = 10
# laser_id = 15
laser_id = 14
filename = "axis"
urdf_filename = "sample"
pass_size = 4
connected_status = Literal["connected", "not_connected", "error"]
_axis_coordinates = []
_world_coordinates = []
_command_count = []
command_type = "base"
command_data = None
motion_type = "reset"
motion_type = "normal"
def __init__(self, application_path, *args, **kwargs):
self.socket = None
self.host = None
self.port = 9760
self.slave_id = None
self.status: SocketRobotArm.connected_status = "not_connected"
self.q_app = None
self.imitate_point = None
robot_start_position = [0, 0, 0]
self.prepare_data = PrepareRobotData()
self.socket_manager = SocketManager()
self.urdf_manager = UrdfManager(
robot_start_position,
application_path,
self.palletizing,
)
self.constraint_id = None
def __exit__(self, exc_type, exc_value, traceback):
logger.info("exiting")
self.socket.close()
def start(self, type="DIRECT"):
self.urdf_manager.run_pybullet(type)
def start_loop(self, urdf):
self.urdf_manager.start_loop(urdf)
self.body_id = self.urdf_manager.body_id
self.num_joints = p.getNumJoints(self.body_id)
def load_palletizing(self):
self.urdf_manager.load_palletizing()
def start_moving(self):
self.urdf_manager.conveyor.moving = True
def get_pybullet_image(self):
return self.urdf_manager.get_pybullet_image()
def close(self):
self.socket_manager.close()
def connect(self, host, slave_id):
self.socket_manager.connect(host)
with open("delta.json", "w") as f:
pass
def get_status(self):
return self.socket_manager.status
def motionFund(self, radians):
if self.motion_type == "reset":
for index, r in enumerate(radians):
p.resetJointState(self.urdf_manager.body_id, index, r)
time.sleep(0.3)
else:
p.setJointMotorControlArray(
self.urdf_manager.body_id,
[i for i in range(len(radians))],
p.POSITION_CONTROL,
radians,
)
time.sleep(1)
def upd_model(self):
threading.Thread(target=self.upd_model_func, daemon=True).start()
def upd_model_func(self):
self.get_coordinates("axis")
self.set_text(text=f"Координаты осей {self.axis_coordinates}")
time.sleep(0.5)
self.get_coordinates("world")
self.set_text(text=f"Мировые координаты {self.world_coordinates}")
time.sleep(0.5)
self._fetch_command_count()
time.sleep(0.5)
axisJointPoses = self.axis_coordinates
self.motionFund(np.radians(axisJointPoses))
time.sleep(0.5)
if False:
coordinates = [float(p) * 0.001 for p in self.world_coordinates[:3]]
angles = [math.radians(p) for p in self.world_coordinates[3:6]]
worldJointPoses = self.convert_to_joint_base(coordinates, angles)
for i in range(self.num_joints):
v = worldJointPoses[i] if i < len(worldJointPoses) else 0
self.motionFund(worldJointPoses)
time.sleep(0.5)
calcWorldPosition = p.getLinkState(
self.urdf_manager.body_id,
self.num_joints - 1,
computeForwardKinematics=True,
)
calcWorldPosition = list(
[p * 1000 for p in calcWorldPosition[0]]
+ [
np.degrees(p)
for p in p.getEulerFromQuaternion(calcWorldPosition[1])
]
)
time.sleep(0.5)
position_diff = np.linalg.norm(
self.world_coordinates[:3] - np.array(calcWorldPosition[:3])
)
# print(*[f"world delta {i} {self.world_coordinates[i] - calcWorldPosition[i]}" for i in range(6)])
# print(*[f"axis delta {i} {self.axis_coordinates[i] - np.rad2deg(worldJointPoses[i])}" for i in range(6)])
# print(self.axis_coordinates[4] - np.rad2deg(worldJointPoses[4]))
print(
"Разница между расчетом по модели и мировыми координатами:",
position_diff,
)
self.set_text(text=f"Команд в очереди {self.command_count}")
time.sleep(0.5)
def cycle_base(self):
self.upd_model()
self.send_data(self.set_global_speed())
self.set_text(text=f"Установили глобальную скорость {self.global_speed}")
time.sleep(0.5)
def cycle_start(self):
self.send_data(self.start_cycle())
self.set_text(text=f"Старт одиночного цикла")
time.sleep(0.5)
if self.command_type == "base":
commands = self.steps_from_file()
if self.command_type == "calc":
commands = self.convert_point_to_free()
if self.command_type == "pallette":
commands = self.get_palletizing_json()
with open(f"log/{self.command_type}.json", "w") as myfile:
myfile.write(json.dumps(commands))
self.add_rcc_list = (
[self.set_physical_speed(True), self.set_output_laser(True)]
+ commands
+ [self.set_physical_speed(False), self.set_output_laser(False)]
)
step = 4
empty = 1
for i in range(0, len(self.add_rcc_list), step):
self.command_data = f"Отправка данных {i}...{i+step-1}"
self.send_data(make_addrcc_data(self.add_rcc_list[i : i + step], empty))
empty = 0
time.sleep(0.05)
def imitate(self):
threading.Thread(target=self.imitate_func, daemon=True).start()
def palletizing(self, position, box_id, counter):
dir_wall = (self.urdf_manager.conv_direction + 1) % 2
near_position = position[:]
near_position[dir_wall] -= 0.4
object_position = position[:]
object_position[dir_wall] -= 0.02
pallet_position = self.urdf_manager.packing[
counter % len(self.urdf_manager.packing)
]
logger.info(f"pallete {pallet_position}")
base1_position = pallet_position[:]
base1_position[0] -= 0.2
base1_position[2] += 0.2
base_position = pallet_position[:]
base_position[0] -= 0.2
drop_position = pallet_position[:]
drop_position[0] -= 0.4
drop_position[2] += 0.4
json_res = []
tool_pos = [0, 0, 0]
steps = [
{"type": "move", "coordinates": near_position},
{"type": "move", "coordinates": object_position},
{"type": "create_constraint"},
{"type": "move", "coordinates": base1_position},
{"type": "move", "coordinates": base_position},
{"type": "move", "coordinates": pallet_position},
{"type": "remove_constraint"},
{"type": "move", "coordinates": base_position},
{"type": "move", "coordinates": base1_position},
{"type": "move", "coordinates": drop_position},
]
constraint_id = None
for step in steps:
if step["type"] == "move":
# logger.info(step["coordinates"])
jointPoses = self.convert_to_joint_base(
step["coordinates"],
np.radians(tool_pos),
)
json_res.append(
self.prepare_data.make_step(
"free", np.degrees(jointPoses), [0, 0, 0, 0, 0, 0]
)
)
self.motionFund(jointPoses)
# time.sleep(2)
if step["type"] == "create_constraint":
link_state = p.getLinkState(self.body_id, self.num_joints - 1)
orientation = link_state[1]
constraint_id = p.createConstraint(
parentBodyUniqueId=self.body_id,
parentLinkIndex=self.num_joints - 1,
childBodyUniqueId=box_id,
childLinkIndex=-1,
jointType=p.JOINT_FIXED,
jointAxis=[0, 0, 0],
parentFramePosition=[0, 0, 0],
childFramePosition=[0, 0.2, 0],
parentFrameOrientation=p.getQuaternionFromEuler(
np.radians([0, 0, 90])
),
childFrameOrientation=orientation,
)
if step["type"] == "remove_constraint":
time.sleep(0.5)
p.removeConstraint(constraint_id)
# time.sleep(0.5)
# p.resetBasePositionAndOrientation(
# box_id,
# pallet_position,
# p.getQuaternionFromEuler(np.radians([0, 0, 0])),
# )
with open(f"data/palletizing.json", "w") as myfile:
myfile.write(json.dumps(json_res))
self.urdf_manager.conveyor.conveyor_stopped = False
def set_text(self, text):
logger.info(text)
def send_data(self, data):
return self.socket_manager.send_data(data)
def get_coordinates(self, coord_type: Literal["axis", "world"] = "axis"):
request = make_query_data([f"{coord_type}-{i}" for i in range(6)])
result = self.send_data(request)
if not result:
return
data = [float(i) for i in result]
if coord_type == "axis":
self._axis_coordinates = data
elif coord_type == "world":
self._world_coordinates = data
@property
def axis_coordinates(self):
return self._axis_coordinates
@property
def world_coordinates(self):
return self._world_coordinates
def _fetch_command_count(self):
request = make_query_data(["RemoteCmdLen"])
result = self.send_data(request)
self._command_count = result
@property
def command_count(self):
return self._command_count
def set_command_type(self, data):
self.command_type = data
def get_command_type(self):
return self.command_type
def get_command_data(self):
return self.command_data
def get_imitate_point(self):
return self.imitate_point
def set_global_speed(self):
return make_command_data(["modifyGSPD", str(self.global_speed * 10)])
def start_cycle(self):
return make_command_data(["actionSingleCycle"])
def set_physical_speed(self, status: bool = False):
return (
{
"oneshot": "0",
"action": "51",
"isUse": str(int(status)),
"speed": str(self.physical_speed * 1000),
},
)
def set_output_laser(self, status: bool = False):
return (
{
"oneshot": "0",
"action": "200",
"type": "0",
"io_status": str(int(status)),
"point": str(self.laser_id),
},
)
def imitate_func(self):
points = self.convert_point_to_free()
for point in points:
jointPoses = [np.radians(float(point[f"m{i}"])) for i in range(6)]
self.motionFund(jointPoses)
def get_palletizing_json(self):
with open(f"data/palletizing.json", "r") as fp:
data = json.load(fp)
return data
def convert_point_to_free(self):
points = self.steps_from_file()
res = []
for i, point in enumerate(points):
if point["action"] == "10":
self.imitate_point = i
points = [
point["m0"],
point["m1"],
point["m2"],
]
angles = [
point["m3"],
point["m4"],
point["m5"],
]
jointPoses = self.convert_to_joint_base(
[float(p) * 0.001 for p in points],
np.radians([float(x) for x in angles]),
)
res.append(
self.prepare_data.make_step(
"free", np.degrees(jointPoses), [0, 0, 0, 0, 0, 0]
)
)
return res
def convert_to_joint_base(self, coordinates, angles):
lower_limits = []
upper_limits = []
for i in range(self.num_joints):
limit = p.getJointInfo(self.body_id, i)
lower_limits.append(limit[8])
upper_limits.append(limit[9])
joint_angles = p.calculateInverseKinematics(
self.body_id,
endEffectorLinkIndex=self.num_joints - 1,
targetPosition=[float(c) for c in coordinates],
targetOrientation=p.getQuaternionFromEuler(angles),
lowerLimits=lower_limits,
upperLimits=upper_limits,
)
return joint_angles
def steps_from_file(self):
if not self.world_coordinates:
return []
result = []
with open(f"data/{self.filename}.nc.result", "r") as fp:
for line in fp:
data = line.strip().split(" ")
prep = {}
axis = ["X", "Y", "Z", "U", "V", "W"]
for item in data:
if item and item[0] and item[0] in axis:
prep[item[:1]] = float(item[1:])
if len(prep) > 0:
r = self.prepare_data.make_step(
"line",
(
prep.get("X", 0),
prep.get("Y", 0),
prep.get("Z", 0),
prep.get("U", 0),
prep.get("V", 0),
prep.get("W", 0),
),
self.world_coordinates,
)
# print(r)
result.append(r)
return result

141
robot/conveyor.py Normal file
View File

@ -0,0 +1,141 @@
import pybullet as p
import time
import threading
from logger import logger
class ConveyorBelt:
moving = False
def __init__(
self,
size,
position,
direction,
box_size,
box_spacing,
box_speed,
palletizinFunc,
):
self.direction = direction
self.conveyor_size = size
self.conveyor_position = position
self.conveyor_id = self.create_conveyor(size, position)
self.conveyor_stopped = False
self.box_size = box_size
self.box_spacing = box_spacing
self.box_speed = box_speed
self.boxes = []
self.box_counter = 0
self.create_boxes()
self.stop_thread = False
self.thread = threading.Thread(target=self.run)
self.thread.start()
self.palletizingFunc = palletizinFunc
def create_conveyor(self, size, position):
collision_shape_id = p.createCollisionShape(
shapeType=p.GEOM_BOX,
halfExtents=[size[i] / 2.0 for i in range(3)],
)
visual_shape_id = p.createVisualShape(
shapeType=p.GEOM_BOX,
halfExtents=[size[i] / 2.0 for i in range(3)],
rgbaColor=[0.5, 0.5, 0.5, 1],
)
conveyor_id = p.createMultiBody(
baseMass=0.0,
baseCollisionShapeIndex=collision_shape_id,
baseVisualShapeIndex=visual_shape_id,
basePosition=position,
)
return conveyor_id
def box_position(self, i=0):
position = self.conveyor_position[:]
position[self.direction] = (
self.conveyor_position[self.direction]
- self.conveyor_size[self.direction] * 0.5
+ i * (self.box_size[self.direction] + self.box_spacing)
+ self.box_size[0] * 0.5
)
return position
def create_boxes(self):
num_boxes = int(
self.conveyor_size[self.direction] / (self.box_size[0] + self.box_spacing)
)
for i in range(num_boxes):
position = self.box_position(i)
self.boxes.append(self.create_box(position))
def create_box(self, position):
collision_shape_id = p.createCollisionShape(
shapeType=p.GEOM_BOX,
halfExtents=[self.box_size[i] / 2.0 for i in range(3)],
)
visual_shape_id = p.createVisualShape(
shapeType=p.GEOM_BOX,
halfExtents=[self.box_size[i] / 2.0 for i in range(3)],
rgbaColor=[1, 0, 0, 1],
)
box_id = p.createMultiBody(
baseMass=10.0,
baseCollisionShapeIndex=collision_shape_id,
baseVisualShapeIndex=visual_shape_id,
basePosition=position,
baseOrientation=p.getQuaternionFromEuler([0, 0, 0]),
)
return box_id
def move_boxes(self):
if self.moving and not self.conveyor_stopped:
for box_id in self.boxes[:]:
pos, orn = p.getBasePositionAndOrientation(box_id)
if (
pos[self.direction] + self.box_size[0] * 0.5
> self.conveyor_position[self.direction]
+ self.conveyor_size[self.direction] * 0.5
):
# Если коробка выходит за конец конвейера, она падает вниз (физика продолжает действовать)
# Удаляем коробку с конвейера
self.boxes.remove(box_id)
self.conveyor_stopped = True
wall_position = list(pos)
dir_wall = (self.direction + 1) % (3 - 1)
wall_position[dir_wall] -= self.box_size[dir_wall] * 0.5
self.call_robot(wall_position, box_id, self.box_counter)
self.box_counter += 1
else:
new_pos = list(pos[:])
new_pos[self.direction] += self.box_speed
p.resetBasePositionAndOrientation(box_id, new_pos, orn)
# Добавляем новые коробки, если на конвейере меньше, чем максимально возможное количество
num_boxes = int(
self.conveyor_size[self.direction] / (self.box_size[0] + self.box_spacing)
)
if len(self.boxes) < num_boxes:
new_box = self.create_box(self.box_position())
self.boxes.append(new_box)
def call_robot(self, position, box_id, counter):
# Здесь можно вызвать робота для выполнения операции, например:
logger.info("Конвейер остановлен, вызываем робота для работы с коробкой.")
self.palletizingFunc(position, box_id, counter)
# time.sleep(5)
# self.conveyor_stopped = False
def run(self):
while not self.stop_thread:
self.move_boxes()
time.sleep(1)
def stop(self):
self.stop_thread = True
self.thread.join()

View File

@ -1,7 +1,9 @@
# Настройки клиента Modbus # Настройки клиента Modbus
MODBUS_SERVER_HOST = "192.168.70.55" # IP-адрес Modbus-сервера MODBUS_SERVER_HOST = "192.168.70.55" # IP-адрес Modbus-сервера
# MODBUS_SERVER_HOST = "192.168.70.65" # IP-адрес Modbus-сервера
MODBUS_SERVER_PORT = 502 MODBUS_SERVER_PORT = 502
MODBUS_SLAVE_ID = 11 MODBUS_SLAVE_ID = 11
# MODBUS_SLAVE_ID = 22
indent = 21100 indent = 21100
s = 800 s = 800
@ -22,7 +24,7 @@ def two_byte_convert(result):
return value return value
def bulb(addr, new_state, client): def bulb(addr, new_state, client, slave_id):
try: try:
coils = client.read_coils(addr, 1, MODBUS_SLAVE_ID) coils = client.read_coils(addr, 1, MODBUS_SLAVE_ID)
# print("читаем начальное состояние", coils.bits) # print("читаем начальное состояние", coils.bits)

34
robot/pallet.py Normal file
View File

@ -0,0 +1,34 @@
import pybullet as p
class Pallet:
def __init__(
self, position=[1, 1, 0], size=[0.8, 1.2, 0.144], color=[0.6, 0.3, 0.1, 0.5]
):
self.size = size
self.position = position
self.color = color
self.create_pallet()
def create_pallet(self):
half_size = [s * 0.5 for s in self.size]
# Создаем collision shape для паллеты
collision_shape = p.createCollisionShape(p.GEOM_BOX, halfExtents=half_size)
# Создаем визуальное отображение (shape) для паллеты
visual_shape = p.createVisualShape(
p.GEOM_BOX, halfExtents=half_size, rgbaColor=self.color
)
# Создаем объект паллеты в физическом мире
self.pallet_id = p.createMultiBody(
baseMass=0, # Масса 0, чтобы паллета не взаимодействовала с физикой
baseCollisionShapeIndex=collision_shape,
baseVisualShapeIndex=visual_shape,
basePosition=self.position,
)
# Устанавливаем позицию объекта паллеты в физическом мире
p.resetBasePositionAndOrientation(self.pallet_id, self.position, [0, 0, 0, 1])

60
robot/prepare_data.py Normal file
View File

@ -0,0 +1,60 @@
from robot.func import *
# os.environ["LIBGL_ALWAYS_SOFTWARE"] = "1"
class PrepareRobotData:
line_speed = 100.0
line_smooth = 0
line_tool = 0
def make_step(self, type, point, start_coordinates):
step = {
"oneshot": "1",
"delay": "0.0",
"speed": str(self.line_speed),
"smooth": str(self.line_smooth),
"coord": "0",
"tool": str(self.line_tool),
"ckStatus": "0x3F",
}
if type == "line" or type == "free":
pairs = zip(start_coordinates, point)
data = []
for pair in pairs:
data.append(round(sum(pair), 3))
m0, m1, m2, m3, m4, m5 = data
if type == "line":
step.update({"action": "10"})
if type == "free":
step.update({"action": "4"})
# m3 = 0
# m4 = 0
# m5 = 0
step.update({"m0": m0, "m1": m1, "m2": m2, "m3": m3, "m4": m4, "m5": m5})
step.update({"m6": 0, "m7": 0})
elif type == "curve":
pairs = zip(self.world_coordinates, point[:5])
m0, m1, m2, m3, m4, m5 = [round(sum(i), 3) for i in pairs]
pairs_p = zip(self.world_coordinates, point[6:])
m0_p, m1_p, m2_p, m3_p, m4_p, m5_p = [round(sum(i), 3) for i in pairs_p]
step.update({"action": "17"})
step.update({"m0": m0, "m1": m1, "m2": m2, "m3": m3, "m4": m4, "m5": m5})
step.update({"m6": 0, "m7": 0})
step.update(
{
"m0_p": m0_p,
"m1_p": m1_p,
"m2_p": m2_p,
"m3_p": m3_p,
"m4_p": m4_p,
"m5_p": m5_p,
}
)
step.update({"m6_p": 0, "m7_p": 0})
for s in step:
step[s] = str(step[s])
return step

58
robot/socket_manager.py Normal file
View File

@ -0,0 +1,58 @@
import socket
import json
import os
import math
import numpy as np
from typing import Literal
from pprint import pprint
import threading
import pybullet as p
import pybullet_industrial as pi
from logger import logger
class SocketManager:
def __init__(self):
self.host = None
self.port = 9760
self.socket = None
self.status: Literal["connected", "not_connected", "error"] = "not_connected"
def connect(self, host):
self.host = host
if self.socket is None:
self.socket = socket.socket()
logger.info(f"trying connect to {(self.host, self.port)}")
self.socket.connect((self.host, self.port))
self.status = "connected"
def close(self):
if self.socket:
self.socket.close()
self.socket = None
self.status = "not_connected"
def send_data(self, data):
if not self.socket:
return
try:
self.socket.send(str.encode(json.dumps(data)))
response_data = self.socket.recv(1024)
response = json.loads(response_data)
if data["reqType"] == "query":
return response["queryData"]
elif data["reqType"] == "command":
return response["cmdReply"]
elif data["reqType"] == "AddRCC" and "cmdReply" in response.keys():
return response["cmdReply"]
else:
pprint(response_data)
return json.loads(response_data)
except Exception as e:
logger.error(f"Error sending data: {e}")
return None

139
robot/urdf_manager.py Normal file
View File

@ -0,0 +1,139 @@
import os
import numpy as np
import time
import pybullet as p
from logger import logger
from robot.conveyor import ConveyorBelt
from robot.pallet import Pallet
from packer.packer import PalletPacker
class UrdfManager:
urdf_filename = None
urdf_filename_tool = "welding_gun"
physics_client = None
body_id = None
def __init__(self, robot_start_position, application_path, palletizing):
self.robot_start_position = robot_start_position
self.application_path = application_path
self.palletizing = palletizing
self.conveyor = None
self.pallet = None
def start_loop(self, urdf):
self.urdf_filename = urdf
p.resetSimulation()
self.load_models()
p.setGravity(0, 0, -9.81, physicsClientId=self.physics_client)
self.state_id = p.saveState()
def run_pybullet(self, type="DIRECT"):
self.physics_client = p.connect(getattr(p, type))
logger.info(f"Connect to {self.physics_client} by {type}")
def load_models(self):
p.loadURDF(
os.path.join(self.application_path, "urdf", "plane.urdf"),
[0,0,-1],
physicsClientId=self.physics_client,
)
urdf_path = os.path.join(
self.application_path, "urdf", f"{self.urdf_filename}.urdf"
)
self.body_id = p.loadURDF(
urdf_path,
self.robot_start_position,
useFixedBase=True,
)
def load_palletizing(self):
if self.conveyor:
self.conveyor = None
if self.pallet:
self.pallet = None
self.start_loop(self.urdf_filename)
k = 0.2
self.pallet_target = [1.366773, 0.59591, -0.624086]
self.pallet_size = [0.8, 1.2, 0.144]
self.pallet_position = [
(self.pallet_target[i] - self.pallet_size[i] * 0.5)
for i in range(len(self.pallet_target))
]
self.pallet = Pallet(self.pallet_position)
self.box_size = [0.2, 0.2, 0.2]
# положение дальнего угла
self.conv_target = [1.045, -0.989, -0.094]
self.conv_size = [0.5, 3.0, 0.1]
self.conv_direction = self.conv_size.index(max(self.conv_size))
self.conv_pos = [
(self.conv_target[i] - self.conv_size[i] * 0.5)
for i in range(len(self.conv_target))
]
self.conveyor = ConveyorBelt(
self.conv_size,
self.conv_pos,
self.conv_direction,
self.box_size,
0.2,
0.1,
self.palletizing,
)
self.packing = PalletPacker(
{
"x": self.pallet_size[0],
"y": self.pallet_size[1],
"z": self.box_size[2], # высота паллеты в один слой
},
{
"x": self.box_size[0],
"y": self.box_size[1],
"z": self.box_size[2],
},
).pack()
self.packing = sorted(self.packing, key=lambda x: (x[0], x[1]))
for p in self.packing:
# logger.info(p)
for i in range(len(self.box_size)):
p[i] = self.pallet_target[i] - p[i] - self.box_size[i] * 0.5
dir_wall = (self.conv_direction + 1) % (3 - 1)
p[dir_wall] -= self.box_size[dir_wall]
p[self.conv_direction] -= self.box_size[self.conv_direction] * 0.5
p[2] += self.pallet_size[2]
# logger.info(f"{self.packing[0]} {self.pallet_target}")
time.sleep(1)
def get_pybullet_image(self):
if self.physics_client is None:
return
width, height, rgb, _, _ = p.getCameraImage(
width=500,
height=500,
viewMatrix=p.computeViewMatrix(
cameraEyePosition=[4, -4, 1.5],
# cameraEyePosition=[4,-4,4],
cameraTargetPosition=[0, 0, 0], # Центр фокусировки камеры
cameraUpVector=[0, 0, 1], # Направление вверх
),
projectionMatrix=p.computeProjectionMatrixFOV(
fov=60.0, aspect=1.0, nearVal=0.1, farVal=10.0
),
# renderer=p.ER_TINY_RENDERER,
physicsClientId=self.physics_client,
)
return (rgb, width, height)

33
robots.json Normal file
View File

@ -0,0 +1,33 @@
[
{
"name": "big",
"host": "192.168.70.55",
"slave_id": 11,
"urdf": "sample"
},
{
"name": "big WITHOUT",
"host": "192.168.70.55",
"slave_id": 11,
"urdf": "sample_without"
},
{
"name": "test",
"host": "127.0.0.1",
"slave_id": 11,
"urdf": "sample"
},
{
"name": "test WITHOUT",
"host": "127.0.0.1",
"slave_id": 11,
"urdf": "sample_without"
},
{
"name": "test small WITHOUT",
"host": "127.0.0.1",
"slave_id": 11,
"urdf": "small_without"
}
]

125
run.py Normal file
View File

@ -0,0 +1,125 @@
import subprocess
import argparse
import sys
import signal
import psutil
# Параметры для процессов
server_process = None
test_server_process = None
command_type = 'exe'
def usage():
"""Функция для отображения помощи"""
print("Usage: run_all.py [--test]")
sys.exit(1)
def terminate_process(process):
"""Функция для корректного завершения процесса и всех его дочерних процессов"""
if process:
proc = psutil.Process(process.pid)
for child in proc.children(recursive=True):
child.terminate()
proc.terminate()
proc.wait()
# Обработчик для сигналов выхода
def cleanup(*args):
"""Функция для остановки серверов при выходе"""
global server_process, test_server_process
print("Остановка серверов...")
terminate_process(server_process)
terminate_process(test_server_process)
print("Серверы остановлены.")
sys.exit(0) # Завершение работы после очистки
# Назначаем функции очистки для сигналов
signal.signal(signal.SIGINT, lambda *_: cleanup())
signal.signal(signal.SIGTERM, lambda *_: cleanup())
# Парсер аргументов командной строки
parser = argparse.ArgumentParser(description="Python launcher script.")
parser.add_argument(
"--test-socket", action="store_true", help="Запуск в режиме тестирования"
)
parser.add_argument(
"--bullet-gui", action="store_true", help="Вывод визуального pybullet"
)
parser.add_argument(
"--start-py", action="store_true", help="Запуск EXE или PY"
)
args = parser.parse_args()
if args.start_py:
command_type = 'local'
poetry_path = "poetry"
# Установка команды для pybullet_server
pybullet_command = [
poetry_path,
"run",
"python",
"utils/pybullet_server.py",
] if command_type == 'local' else ['pybullet_server.exe']
# Если включен режим тестирования, добавляем флаг --test
if args.bullet_gui:
# if type(pybullet_command) is str:
# pybullet_command += '--test'
# else:
pybullet_command.append("--test")
# Запуск pybullet_server.exe
print("Запуск pybullet_server...")
server_process = subprocess.Popen(pybullet_command)
# Проверяем успешный запуск сервера
if server_process.poll() is not None:
print("Ошибка при запуске pybullet_server")
sys.exit(1)
# Если включен режим тестирования, запускаем test_socket_server.exe
if args.test_socket:
print("Запуск test_socket_server...")
test_server_process = subprocess.Popen(
[
poetry_path,
"run",
"python",
"utils/test_socket_server.py",
] if command_type == 'local' else 'test_socket_server.exe'
) # Путь к исполняемому файлу
# Проверка успешного запуска тестового сервера
if test_server_process.poll() is not None:
print("Ошибка при запуске test_socket_server")
sys.exit(1)
# Запуск основного скрипта main.exe в режиме тестирования
subprocess.run(
[
poetry_path,
"run",
"python",
"main.py",
"--mode",
"test",
] if command_type == 'local' else 'main.exe --mode test'
) # Путь к исполняемому файлу
else:
# Запуск основного скрипта main.exe
subprocess.run(
[
poetry_path,
"run",
"python",
"main.py",
] if command_type == 'local' else 'main.exe'
) # Путь к исполняемому файлу
# Очистка после завершения
cleanup()

39
run.spec Normal file
View File

@ -0,0 +1,39 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['run.py'],
pathex=['.', './.venv', './.venv/Lib', './.venv/Lib/site-packages'],
binaries=[],
datas=[('pyproject.toml', '.'), ('robots.json', '.'), ('urdf', 'urdf'), ('data', 'data')],
hiddenimports=['libpython3.10'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='run',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
contents_directory='test',
)

View File

@ -1,27 +0,0 @@
import socket
import json
HOST = "127.0.0.1" # Standard loopback interface address (localhost)
PORT = 65432 # Port to listen on (non-privileged ports are > 1023)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print(f"Connected by {addr}")
while True:
data = conn.recv(1024)
if data:
req = json.loads(data)
res = {"queryData": ["ok"]}
if "queryAddr" in req.keys() and "axis-0" in req["queryAddr"]:
res["queryData"] = [10, 11, 12, 13, 14, 15]
if "queryAddr" in req and "world-0" in req["queryAddr"]:
res["queryData"] = [100, 101, 102, 103, 104, 105]
if req["reqType"] == "command":
res["cmdReply"] = ['ok']
conn.sendall(json.dumps(res).encode())

39
test_socket_server.spec Normal file
View File

@ -0,0 +1,39 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['utils/test_socket_server.py'],
pathex=['.', './.venv', './.venv/Lib', './.venv/Lib/site-packages'],
binaries=[],
datas=[('pyproject.toml', '.'), ('robots.json', '.'), ('urdf', 'urdf'), ('data', 'data')],
hiddenimports=['libpython3.10'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='test_socket_server',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
contents_directory='test',
)

24
urdf/europallet.urdf Normal file
View File

@ -0,0 +1,24 @@
<?xml version="1.0"?>
<robot name="europallet">
<link name="pallet">
<inertial>
<mass value="20.0" /> <!-- Масса палеты, можно изменить -->
<origin xyz="0 0 7.25" rpy="0 0 0" /> <!-- Центр масс (высота 7.25 см) -->
<inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0" /> <!-- Моменты
инерции, можно изменить -->
</inertial>
<visual>
<geometry>
<box size="1.2 0.8 0.145" /> <!-- Размеры (длина, ширина, высота) в метрах -->
</geometry>
<material name="wood">
<color rgba="0.58 0.29 0.19 1.0" /> <!-- Цвет, здесь коричневый -->
</material>
</visual>
<collision>
<geometry>
<box size="1.2 0.8 0.145" /> <!-- Размеры для коллизий также -->
</geometry>
</collision>
</link>
</robot>

28
urdf/plane.urdf Normal file
View File

@ -0,0 +1,28 @@
<?xml version="1.0" ?>
<robot name="plane">
<link name="planeLink">
<contact>
<lateral_friction value="1"/>
</contact>
<inertial>
<origin rpy="0 0 0" xyz="0 0 0"/>
<mass value=".0"/>
<inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0"/>
</inertial>
<visual>
<origin rpy="0 0 0" xyz="0 0 0"/>
<geometry>
<mesh filename="../urdf_support/plane.obj" scale="1 1 1"/>
</geometry>
<material name="white">
<color rgba="1 1 1 1"/>
</material>
</visual>
<collision>
<origin rpy="0 0 0" xyz="0 0 -5"/>
<geometry>
<box size="30 30 10"/>
</geometry>
</collision>
</link>
</robot>

218
urdf/sample.urdf Normal file
View File

@ -0,0 +1,218 @@
<?xml version="1.0"?>
<robot name="sample_robot">
<!-- Materials -->
<material name="grey">
<color rgba="0.0 0 0 1.0" />
</material>
<material name="red">
<color rgba="1.0 0.0 0.0 1.0" />
</material>
<material name="blue">
<color rgba="0 0.0 1.0 1.0" />
</material>
<material name="lightblue">
<color rgba="0.0 0.22 1.0 1.0" />
</material>
<material name="yellow">
<color rgba="0.96 0.76 0.13 1.0" />
</material>
<material name="orange">
<color rgba="1.0 0.5 0.0 1.0" />
</material>
<material name="black">
<color rgba="0.15 0.15 0.15 1.0" />
</material>
<!-- Links: main serial chain -->
<link name="base_link">
<visual>
<origin rpy="0 0 0" xyz="0 0 0" />
<geometry>
<mesh filename="../urdf_support/sample/1.stl" />
</geometry>
<material name="grey" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0 0 0" />
<geometry>
<mesh filename="../urdf_support/sample/1.stl" />
</geometry>
</collision>
</link>
<link name="link_1">
<visual>
<origin rpy="0 0 0" xyz="0 0 0.23445" />
<geometry>
<mesh filename="../urdf_support/sample/2.stl" />
</geometry>
<material name="red" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0 0 0.23445" />
<geometry>
<mesh filename="../urdf_support/sample/2.stl" />
</geometry>
</collision>
</link>
<link name="link_2">
<visual>
<origin rpy="0 0 0" xyz="0.0 -0.103 0" />
<geometry>
<mesh filename="../urdf_support/sample/3.stl" />
</geometry>
<material name="blue" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0.0 -0.103 0" />
<geometry>
<mesh filename="../urdf_support/sample/3.stl" />
</geometry>
</collision>
</link>
<link name="link_3">
<visual>
<origin rpy="0 0 0" xyz="0 -0.103 0" />
<geometry>
<mesh filename="../urdf_support/sample/4.stl" />
</geometry>
<material name="lightblue" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0 -0.103 0" />
<geometry>
<mesh filename="../urdf_support/sample/4.stl" />
</geometry>
</collision>
</link>
<link name="link_4">
<visual>
<origin rpy="0 0 0" xyz="0.23345 0 0" />
<geometry>
<mesh filename="../urdf_support/sample/5.stl" />
</geometry>
<material name="yellow" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0.23345 0 0" />
<geometry>
<mesh filename="../urdf_support/sample/5.stl" />
</geometry>
</collision>
</link>
<link name="link_5">
<visual>
<origin rpy="0 0 0" xyz="0.02 0.04 0.0" />
<geometry>
<mesh filename="../urdf_support/sample/6.stl" />
</geometry>
<material name="orange" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0.02 0.04 0.0" />
<geometry>
<mesh filename="../urdf_support/sample/6.stl" />
</geometry>
</collision>
</link>
<link name="link_6">
<visual>
<origin rpy="0 0 0" xyz="0 0 0.0" />
<geometry>
<mesh filename="../urdf_support/sample/777.stl" />
</geometry>
<material name="black" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0 0 0.0" />
<geometry>
<mesh filename="../urdf_support/sample/777.stl" />
</geometry>
</collision>
</link>
<link name="welding_gun_body">
<visual>
<geometry>
<mesh filename="../urdf_support/sample/7.stl" /> <!-- Замените на путь к вашему STL-файлу -->
</geometry>
<material name="metal" />
<origin xyz="0 0 0" rpy="0 0 0" />
</visual>
</link>
<!-- Joints: main serial chain -->
<joint name="joint_1" type="revolute">
<limit lower="-2.705" upper="2.705" effort="0" velocity="0" />
<origin rpy="0 0 0" xyz="0 0 0" />
<parent link="base_link" />
<child link="link_1" />
<axis xyz="0 0 1" />
</joint>
<joint name="joint_2" type="revolute">
<limit lower="-2.444" upper="1.135" effort="0" velocity="0" />
<parent link="link_1" />
<child link="link_2" />
<axis xyz="0 -1 0" />
<origin rpy="0 0 0" xyz="0.17045 0 0.4946" />
</joint>
<joint name="joint_3" type="revolute">
<limit lower="-1.309" upper="1.919" effort="0" velocity="0" />
<parent link="link_2" />
<child link="link_3" />
<axis xyz="0 -1 0" />
<origin rpy="0 0 0" xyz="0 -0.001963 0.729921" />
</joint>
<joint name="joint_4" type="revolute">
<limit lower="-3.142" upper="3.142" effort="0" velocity="0" />
<parent link="link_3" />
<child link="link_4" />
<axis xyz="1 0 0" />
<origin rpy="0 0 0" xyz="0 0 0.098277" />
</joint>
<joint name="joint_5" type="revolute">
<limit lower="-2.007" upper="2.007" effort="0" velocity="0" />
<parent link="link_4" />
<child link="link_5" />
<axis xyz="0 -1 0" />
<origin rpy="0 0 0" xyz="1.109039 0 0" />
</joint>
<joint name="joint_6" type="revolute">
<limit lower="-6.283" upper="6.283" effort="0" velocity="0" />
<parent link="link_5" />
<child link="link_6" />
<axis xyz="1 0 0" />
<origin rpy="0 0 0" xyz="0.117 0 0" />
</joint>
<joint name="welding_gun_fixed_joint" type="fixed">
<parent link="link_6" />
<child link="welding_gun_body" />
<origin xyz="0 0 0" rpy="0 0 0" />
</joint>
<link name="tcp">
<visual>
<geometry>
<box size="0.05 0.05 0.05" />
</geometry>
<material name="red" />
</visual>
</link>
<joint name="tcp_joint" type="fixed">
<parent link="welding_gun_body" />
<child link="tcp" />
<origin xyz="0.353774 0.009203 -0.033794" rpy="110.766 1.620 -89.636" />
</joint>
</robot>

204
urdf/sample_without.urdf Normal file
View File

@ -0,0 +1,204 @@
<?xml version="1.0"?>
<robot name="sample_robot">
<!-- Materials -->
<material name="grey">
<color rgba="0.0 0 0 1.0" />
</material>
<material name="red">
<color rgba="1.0 0.0 0.0 1.0" />
</material>
<material name="blue">
<color rgba="0 0.0 1.0 1.0" />
</material>
<material name="lightblue">
<color rgba="0.0 0.22 1.0 1.0" />
</material>
<material name="yellow">
<color rgba="0.96 0.76 0.13 1.0" />
</material>
<material name="orange">
<color rgba="1.0 0.5 0.0 1.0" />
</material>
<material name="black">
<color rgba="0.15 0.15 0.15 1.0" />
</material>
<!-- Links: main serial chain -->
<link name="base_link">
<visual>
<origin rpy="0 0 0" xyz="0 0 0" />
<geometry>
<mesh filename="../urdf_support/sample/1.stl" />
</geometry>
<material name="grey" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0 0 0" />
<geometry>
<mesh filename="../urdf_support/sample/1.stl" />
</geometry>
</collision>
</link>
<link name="link_1">
<visual>
<origin rpy="0 0 0" xyz="0 0 0.23445" />
<geometry>
<mesh filename="../urdf_support/sample/2.stl" />
</geometry>
<material name="red" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0 0 0.23445" />
<geometry>
<mesh filename="../urdf_support/sample/2.stl" />
</geometry>
</collision>
</link>
<link name="link_2">
<visual>
<origin rpy="0 0 0" xyz="0.0 -0.103 0" />
<geometry>
<mesh filename="../urdf_support/sample/3.stl" />
</geometry>
<material name="blue" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0.0 -0.103 0" />
<geometry>
<mesh filename="../urdf_support/sample/3.stl" />
</geometry>
</collision>
</link>
<link name="link_3">
<visual>
<origin rpy="0 0 0" xyz="0 -0.103 0" />
<geometry>
<mesh filename="../urdf_support/sample/4.stl" />
</geometry>
<material name="lightblue" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0 -0.103 0" />
<geometry>
<mesh filename="../urdf_support/sample/4.stl" />
</geometry>
</collision>
</link>
<link name="link_4">
<visual>
<origin rpy="0 0 0" xyz="0.23345 0 0" />
<geometry>
<mesh filename="../urdf_support/sample/5.stl" />
</geometry>
<material name="yellow" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0.23345 0 0" />
<geometry>
<mesh filename="../urdf_support/sample/5.stl" />
</geometry>
</collision>
</link>
<link name="link_5">
<visual>
<origin rpy="0 0 0" xyz="0.02 0.04 0.0" />
<geometry>
<mesh filename="../urdf_support/sample/6.stl" />
</geometry>
<material name="orange" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0.02 0.04 0.0" />
<geometry>
<mesh filename="../urdf_support/sample/6.stl" />
</geometry>
</collision>
</link>
<link name="link_6">
<visual>
<origin rpy="0 0 0" xyz="0 0 0.0" />
<geometry>
<mesh filename="../urdf_support/sample/777.stl" />
</geometry>
<material name="black" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0 0 0.0" />
<geometry>
<mesh filename="../urdf_support/sample/777.stl" />
</geometry>
</collision>
</link>
<!-- Joints: main serial chain -->
<joint name="joint_1" type="revolute">
<limit lower="-2.705" upper="2.705" effort="0" velocity="0" />
<origin rpy="0 0 0" xyz="0 0 0" />
<parent link="base_link" />
<child link="link_1" />
<axis xyz="0 0 1" />
</joint>
<joint name="joint_2" type="revolute">
<limit lower="-2.444" upper="1.135" effort="0" velocity="0" />
<parent link="link_1" />
<child link="link_2" />
<axis xyz="0 -1 0" />
<origin rpy="0 0 0" xyz="0.17045 0 0.4946" />
</joint>
<joint name="joint_3" type="revolute">
<limit lower="-1.309" upper="1.919" effort="0" velocity="0" />
<parent link="link_2" />
<child link="link_3" />
<axis xyz="0 -1 0" />
<origin rpy="0 0 0" xyz="0 -0.001693 0.729921" />
</joint>
<joint name="joint_4" type="revolute">
<limit lower="-3.142" upper="3.142" effort="0" velocity="0" />
<parent link="link_3" />
<child link="link_4" />
<axis xyz="1 0 0" />
<origin rpy="0 0 0" xyz="0 0 0.098277" />
</joint>
<joint name="joint_5" type="revolute">
<limit lower="-2.007" upper="2.007" effort="0" velocity="0" />
<parent link="link_4" />
<child link="link_5" />
<axis xyz="0 -1 0" />
<origin rpy="0 0 0" xyz="1.109039 0 0" />
</joint>
<joint name="joint_6" type="revolute">
<limit lower="-6.283" upper="6.283" effort="0" velocity="0" />
<parent link="link_5" />
<child link="link_6" />
<axis xyz="1 0 0" />
<origin rpy="0 0 0" xyz="0.117 0 0" />
</joint>
<link name="tcp">
<visual>
<origin rpy="0 0 0" xyz="0.04 0 0" />
<geometry>
<box size="0.02 0.02 0.02" />
</geometry>
<material name="red" />
</visual>
</link>
<joint name="tcp_joint" type="fixed">
<parent link="link_6" />
<child link="tcp" />
<origin xyz="0 0 0" rpy="0 0 0" />
</joint>
</robot>

192
urdf/small_without.urdf Normal file
View File

@ -0,0 +1,192 @@
<?xml version="1.0"?>
<robot name="small_robot">
<!-- Materials -->
<material name="grey">
<color rgba="0.0 0 0 1.0" />
</material>
<material name="red">
<color rgba="1.0 0.0 0.0 1.0" />
</material>
<material name="blue">
<color rgba="0 0.0 1.0 1.0" />
</material>
<material name="lightblue">
<color rgba="0.0 0.22 1.0 1.0" />
</material>
<material name="yellow">
<color rgba="0.96 0.76 0.13 1.0" />
</material>
<material name="orange">
<color rgba="1.0 0.5 0.0 1.0" />
</material>
<material name="black">
<color rgba="0.15 0.15 0.15 1.0" />
</material>
<!-- Links: main serial chain -->
<link name="base_link">
<visual>
<origin rpy="0 0 0" xyz="0 0 0" />
<geometry>
<mesh filename="../urdf_support/small/1.stl" />
</geometry>
<material name="grey" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0 0 0" />
<geometry>
<mesh filename="../urdf_support/sample/1.stl" />
</geometry>
</collision>
</link>
<link name="link_1">
<visual>
<origin rpy="0 0 0" xyz="0 0 0.23445" />
<geometry>
<mesh filename="../urdf_support/small/2.stl" />
</geometry>
<material name="red" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0 0 0.23445" />
<geometry>
<mesh filename="../urdf_support/sample/2.stl" />
</geometry>
</collision>
</link>
<link name="link_2">
<visual>
<origin rpy="0 0 0" xyz="0 -0.103 0" />
<geometry>
<mesh filename="../urdf_support/small/3.stl" />
</geometry>
<material name="blue" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0 -0.103 0" />
<geometry>
<mesh filename="../urdf_support/sample/3.stl" />
</geometry>
</collision>
</link>
<link name="link_3">
<visual>
<origin rpy="0 0 0" xyz="0 -0.103 0" />
<geometry>
<mesh filename="../urdf_support/small/4.stl" />
</geometry>
<material name="lightblue" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0 -0.103 0" />
<geometry>
<mesh filename="../urdf_support/sample/4.stl" />
</geometry>
</collision>
</link>
<link name="link_4">
<visual>
<origin rpy="0 0 0" xyz="0.23345 0 0" />
<geometry>
<mesh filename="../urdf_support/small/5.stl" />
</geometry>
<material name="yellow" />
</visual>
<collision>
<origin rpy="0 0 0" xyz="0.23345 0 0" />
<geometry>
<mesh filename="../urdf_support/sample/5.stl" />
</geometry>
</collision>
</link>
<link name="link_5">
<visual>
<origin rpy="0 0 0" xyz="0 0 0.0" />
<geometry>
<mesh filename="../urdf_support/small/6.stl" />
</geometry>
<material name="orange" />
</visual>
</link>
<link name="link_6">
<visual>
<origin rpy="0 0 0" xyz="0 0 0" />
<geometry>
<mesh filename="../urdf_support/small/7.stl" />
</geometry>
<material name="black" />
</visual>
</link>
<!-- Joints: main serial chain -->
<joint name="joint_1" type="revolute">
<limit lower="-2.705" upper="2.705" effort="0" velocity="0" />
<origin rpy="0 0 0" xyz="0 0 0" />
<parent link="base_link" />
<child link="link_1" />
<axis xyz="0 0 1" />
</joint>
<joint name="joint_2" type="revolute">
<limit lower="-2.444" upper="1.135" effort="0" velocity="0" />
<parent link="link_1" />
<child link="link_2" />
<axis xyz="0 -1 0" />
<origin rpy="0 0 0" xyz="0.169740 0 0.4946" />
</joint>
<joint name="joint_3" type="revolute">
<limit lower="-1.309" upper="1.919" effort="0" velocity="0" />
<parent link="link_2" />
<child link="link_3" />
<axis xyz="0 -1 0" />
<origin rpy="0 0 0" xyz="0 -0.00118 0.730581" />
</joint>
<joint name="joint_4" type="revolute">
<limit lower="-3.142" upper="3.142" effort="0" velocity="0" />
<parent link="link_3" />
<child link="link_4" />
<axis xyz="1 0 0" />
<origin rpy="0 0 0" xyz="0 0 0.099522" />
</joint>
<joint name="joint_5" type="revolute">
<limit lower="-2.007" upper="2.007" effort="0" velocity="0" />
<parent link="link_4" />
<child link="link_5" />
<axis xyz="0 -1 0" />
<origin rpy="0 0 0" xyz="0.826407 0 0" />
</joint>
<joint name="joint_6" type="revolute">
<limit lower="-6.283" upper="6.283" effort="0" velocity="0" />
<parent link="link_5" />
<child link="link_6" />
<axis xyz="1 0 0" />
<origin rpy="0 0 0" xyz="0.164 0 0" />
</joint>
<link name="tcp">
<visual>
<origin rpy="0 0 0" xyz="0.04 0 0" />
<geometry>
<box size="0.02 0.02 0.02" />
</geometry>
<material name="red" />
</visual>
</link>
<joint name="tcp_joint" type="fixed">
<parent link="link_6" />
<child link="tcp" />
<origin xyz="0 0 0" rpy="0 0 0" />
</joint>
</robot>

27
urdf/welding_gun.urdf Normal file
View File

@ -0,0 +1,27 @@
<?xml version="1.0"?>
<robot name="welding_gun_robot">
<link name="welding_gun_body">
<visual>
<geometry>
<mesh filename="../urdf_support/sample/7.stl" />
</geometry>
<material name="metal" />
<origin xyz="0 0 0" rpy="0 0 0" />
</visual>
</link>
<link name="tcp">
<visual>
<geometry>
<box size="0.05 0.05 0.05" />
</geometry>
<material name="red" />
</visual>
</link>
<joint name="tcp_joint" type="fixed">
<parent link="welding_gun_body" />
<child link="tcp" />
<origin xyz="0.353774 0.009203 -0.033794" rpy="110.766 1.620 -89.636" />
</joint>
</robot>

18
urdf_support/plane.obj Normal file
View File

@ -0,0 +1,18 @@
# Blender v2.66 (sub 1) OBJ File: ''
# www.blender.org
mtllib plane.mtl
o Plane
v 15.000000 -15.000000 0.000000
v 15.000000 15.000000 0.000000
v -15.000000 15.000000 0.000000
v -15.000000 -15.000000 0.000000
vt 15.000000 0.000000
vt 15.000000 15.000000
vt 0.000000 15.000000
vt 0.000000 0.000000
usemtl Material
s off
f 1/1 2/2 3/3
f 1/1 3/3 4/4

BIN
urdf_support/sample/1.stl Normal file

Binary file not shown.

BIN
urdf_support/sample/2.stl Normal file

Binary file not shown.

BIN
urdf_support/sample/3.stl Normal file

Binary file not shown.

BIN
urdf_support/sample/4.stl Normal file

Binary file not shown.

BIN
urdf_support/sample/5.stl Normal file

Binary file not shown.

BIN
urdf_support/sample/6.stl Normal file

Binary file not shown.

BIN
urdf_support/sample/7.stl Normal file

Binary file not shown.

BIN
urdf_support/sample/777.stl Normal file

Binary file not shown.

BIN
urdf_support/small/1.stl Normal file

Binary file not shown.

BIN
urdf_support/small/2.stl Normal file

Binary file not shown.

BIN
urdf_support/small/3.stl Normal file

Binary file not shown.

BIN
urdf_support/small/4.stl Normal file

Binary file not shown.

BIN
urdf_support/small/5.stl Normal file

Binary file not shown.

BIN
urdf_support/small/6.stl Normal file

Binary file not shown.

BIN
urdf_support/small/7.stl Normal file

Binary file not shown.

0
utils/__init__.py Normal file
View File

42
utils/pybullet_server.py Normal file
View File

@ -0,0 +1,42 @@
# server.py
import time
import argparse
import pybullet as p
import pybullet_data
# from logger import logger
def main(type="SHARED_MEMORY_SERVER"):
# Подключаемся к графическому серверу в режиме SHARED_MEMORY_SERVER
# physicsClient = p.connect(p.SHARED_MEMORY_SERVER)
physicsClient = p.connect(getattr(p, type))
print(f"start pybullet ph client {physicsClient}")
# Настраиваем среду
p.setAdditionalSearchPath(pybullet_data.getDataPath())
p.setGravity(0, 0, -9.81, physicsClientId=physicsClient)
while True:
# Основной цикл физического движка
# if physicsClient != -1:
try:
p.stepSimulation()
except Exception as e:
print(f"Ошибка в pybullet_server{e}")
time.sleep(1)
time.sleep(1/240)
if __name__ == "__main__":
# Парсер аргументов командной строки
parser = argparse.ArgumentParser(description="Запуск PyBullet сервера.")
parser.add_argument(
"--test", action="store_true", help="Запустить сервер в режиме GUI_SERVER"
)
args = parser.parse_args()
# Если передан аргумент --test, устанавливаем тип подключения SHARED_MEMORY_SERVER
connection_type = "GUI_SERVER" if args.test else "SHARED_MEMORY_SERVER"
# connection_type = "SHARED_MEMORY_SERVER"
main(connection_type)

179
utils/test_socket_server.py Normal file
View File

@ -0,0 +1,179 @@
import socket
import json
HOST = "127.0.0.1" # Standard loopback interface address (localhost)
PORT = 9760 # Port to listen on (non-privileged ports are > 1023)
c_angles = [
{
"world": [
1131.959351,
-588.689941,
1277.805054,
6.181231,
54.227802,
-100.604988,
],
"axis": [-41.612457, 31.759747, -26.773878, 74.869049, -45.417992, -20.86335],
},
{
"world": [1282.244, -75.427, 1772.476, 84.629, 34.519, 153.999],
"axis": [-8.487, -8.681, 33.058, 88.070, -75.010, -10.566],
},
{
"world": [1630.006, 628.326, 1322.554, 0, 90, 0],
"axis": [22.493, -30.696, 35.997, -77.419, -23.007, 76.362],
},
{
"world": [1052.757, -1028.846, 334.417, 162.374, 20.467, 75.065],
"axis": [-43.742, -30.698, -12.227, -21.884, -23.078, 76.362],
},
{
"world": [1396.525, 1.687, 1322.697, 0, 90, 0],
"axis": [0, -0.002, -0.002, 0.003, -0.001, 0],
},
{
"world": [1396.513, 1.758, 1322.749, -0.002, 90, 0],
"axis": [0.002, -0.001, 0, 0, 0, 0],
},
{
"world": [-1.645, 1396.533, 1322.700, -89.998, 90.000, 0],
"axis": [89.998, -0.002, -0.001, 0.001, -0.001, -0.001],
},
{
"world": [-61.982, 1.689, 1955.771, 0, 25, 0.003],
"axis": [0.003, 65, -0.001, 0.001, 0, -0.001],
},
{
"world": [72.252, 1.696, 2450.564, 0, 0, 0],
"axis": [0.002, -0.001, 89.999, 0.002, 0, -0.001],
},
{
"world": [1396.542, 1.748, 1322.702, 90.004, 0.001, 90.003],
"axis": [0.002, -0.003, 0, 89.999, -0.001, 0],
},
{
"world": [1279.539, 1.716, 1439.725, 0.004, 0.005, 0.001],
"axis": [0.001, -0.002, -0.001, 0.004, 89.998, 0],
},
{
"world": [1396.518, 1.704, 1322.743, 90.002, -0.006, 90],
"axis": [0, -0.001, 0, 0.002, 0, 90.003],
},
]
c_angles = [
{
"world": [
894.159973,
-738.295654,
782.748047,
172.274109,
28.079031,
120.377357,
],
"axis": [-39.428261, 10.391139, -32.562145, 176.81929, 38.895988, -159.779755],
},
{
"world": [
1100.071655,
-347.347412,
782.754578,
172.284241,
28.079557,
142.505508,
],
"axis": [-17.409513, 10.897068, -33.003525, 176.892288, 38.957874, -159.934479],
},
]
c_small = [
{
"world": [549.087, -803.609, 939.418, 125.479, 50.992, 63.257],
"axis": [-55.721, 12.229, -33.657, 35.030, 0.00, -1.621],
},
{
"world": [202.361, 333.995, 1743.859, -33.7, 40.692, 12.951],
"axis": [58.637, 41.540, -2.386, -32.975, -0.052, 0.119],
},
{
"world": [915.212, 352.196, 1110.636, -109.839, 55.517, -85.605],
"axis": [20.987, 14.281, -25.313, -32.976, -0.054, 0.117],
},
{
"world": [915.172, 352.254, 1110.614, 179.937, 78.911, -159.077],
"axis": [20.986, 14.282, -25.313, -0.102, -0.057, 0.115],
},
{
"world": [1165.135, 1.142, 1312.130, 179.258, 89.223, 179.259],
"axis": [0.001, -0.299, -0.416, -0.103, -0.059, 0.113],
},
{
"world": [1410.226, 1.123, 1324.733, 0, 90, 0],
"axis": [0, -20.6, 23.854, -0.001, -3.249, 0.004],
},
{
"world": [943.3, -650.361, 783.806, 103.505, 55.005, 42.234],
"axis": [-31.249, -8.117, -28.424, 43.951, 36.544, 0.001],
},
{
"world": [721.214, 299.284, 1141.345, -133.593, 37.242, -120.067],
"axis": [27.053, 27.798, -28.423, -35.215, -41.446, 0.005],
},
]
c_angles = c_small
coordinates_index = 0
def handle_client(conn, addr):
print(f"Connected by {addr}")
try:
while True:
data = conn.recv(1024 * 2)
if not data:
break
req = json.loads(data)
print(req)
res = {"queryData": ["ok"]}
global coordinates_index
if "queryAddr" in req and "axis-0" in req["queryAddr"]:
print(f"----{coordinates_index}----")
limit = len(c_angles) - 1
# limit = 2
if coordinates_index < limit:
coordinates_index += 1
else:
coordinates_index = 0
c = c_angles[coordinates_index]
if "queryAddr" in req and "axis-0" in req["queryAddr"]:
res["queryData"] = c["axis"]
if "queryAddr" in req and "world-0" in req["queryAddr"]:
res["queryData"] = c["world"]
if "reqType" in req and (
req["reqType"] == "command" or req["reqType"] == "AddRCC"
):
res["cmdReply"] = ["it is local dear"]
# print(res)
conn.sendall(json.dumps(res).encode())
except json.JSONDecodeError as e:
print(f"JSON decode error: {e}")
except socket.error as e:
print(f"Socket error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
finally:
conn.close()
print(f"Connection with {addr} closed")
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
print(f"Server listening on {HOST}:{PORT}")
while True:
conn, addr = s.accept()
handle_client(conn, addr)

4
utils/urdf_convert.py Normal file
View File

@ -0,0 +1,4 @@
from xacrodoc import XacroDoc
doc = XacroDoc.from_file(path="fanuc_m16ib_support/urdf/fanucM16ib.urdf")
urdf_str = doc.to_urdf_string()
doc.to_urdf_file("urdf/fanucM16ib.urdf")