dev: Разработан парсер TXT данных от куки

This commit is contained in:
Andrew 2025-01-29 16:23:30 +03:00
parent a8a9d6fdb6
commit cc1cd28a36
2 changed files with 232 additions and 118 deletions

View File

@ -1,26 +1,119 @@
from typing import Optional from typing import Optional, Tuple
import os
import numpy as np import numpy as np
import pandas as pd import pandas as pd
from roboter import Performance
#TODO: Реализовать поиск времени простоя
class DowntimeAnalyzer:
def __init__(self) -> None:
...
class PerformanceProcessor: def generate_downtime_report(self) -> list:
...
def calc_performance(self, path:str, TWC_raw:pd.DataFrame): def _separate_conditions(self, TWC_raw:pd.DataFrame, robot_raw:pd.DataFrame) -> Tuple[dict, dict]:
factory = Performance() robot_splitter = RobotConditionSplitter()
comm_df, rob_df, TWC_df = factory.job(path, TWC_raw) TWC_splitter = TWC_ConditionSplitter()
#comm_splitter = CommConditionSplitter()
rob_conditions = robot_splitter.split(robot_raw)
TWC_conditions = TWC_splitter.split(TWC_raw)
#comm_df = comm_splitter.split(rob_conditions["communication"], TWC_conditions["communication"])
return (rob_conditions, TWC_conditions)
class ConditionSplitter:
def __init__(self):
self._signals = []
def _find_indexes(self,
signal: str,
dataframe: pd.DataFrame) -> list[list[float], list[float]]:
stage_diff = np.diff(dataframe[signal])
start_idx = np.where(stage_diff == 1)
finish_idx = np.where(stage_diff == -1)
return start_idx[0], finish_idx[0]
def _find_events(self,
dataframe: pd.DataFrame,
signals: list[str]) -> Optional[dict[dict[pd.Series]]]:
intervals = {}
end_time = 0
for signal in signals:
start_idx, finish_idx = np.array(self._find_indexes(signal, dataframe))
start_series = dataframe.loc[start_idx, "time"].reset_index(drop=True)
end_series = dataframe.loc[finish_idx, "time"].reset_index(drop=True)
end_series.fillna(end_time)
intervals[signal] = {"rise": start_series,
"fall": end_series}
return intervals
def _form_intervals(self,
start: pd.Series,
end: pd.Series) -> dict:
if len(start) != len(end):
for i in range(1, len(end)):
if end[i-1] > start[i]:
start = start.drop(i).reset_index(drop=True)
intervals = {'start':start.tolist, 'end':end.tolist}
return intervals
class RobotConditionSplitter(ConditionSplitter):
def __init__(self):
self._signals = [
"$OUT3012",
"$IN3003",
"$OUT3003",
"$OUT3244"
]
def split(self, dataframe: pd.DataFrame) -> dict:
events = self._find_events(dataframe, self._signals)
communication_sig = {'sent':events["$OUT3244"]["fall"], 'received':events[""][""]}
point_interval = self._form_intervals(start=events["$OUT3012"]["rise"], end=events["$OUT3012"]["fall"])
movement_interval = self._form_intervals(start=events["$OUT3244"]["rise"], end=events["$OUT3244"]["fall"])
conditions = {"communication":communication_sig, "waiting": point_interval, "moving": movement_interval}
return conditions
class TWC_ConditionSplitter(ConditionSplitter):
def __init__(self):
self._signals = [
"Closing",
"Squeeze",
"Welding",
"Relief",
"Oncoming"
]
def split(self, dataframe: pd.DataFrame) -> dict:
events = self._find_events(dataframe, self._signals)
communication_sig = {'sent':events[""][""], 'received':events[""][""]} #ситара что-то делает -конец сигнала
closing_interval = self._form_intervals(start=events["Closing"]["rise"], end=events["Closing"]["fall"])
squeeze_interval = self._form_intervals(start=events["Squeeze"]["rise"], end=events["Squeeze"]["fall"])
relief_interval = self._form_intervals(start=events["Relief"]["rise"], end=events["Relief"]["fall"])
oncoming_interval = self._form_intervals(start=events["Oncoming"]["rise"], end=events["Oncoming"]["fall"])
conditions = {
"communication":communication_sig,
'closing':closing_interval,
'squeeze':squeeze_interval,
'relief':relief_interval,
'oncoming':oncoming_interval
}
return conditions
class CommConditionSplitter(ConditionSplitter):
"""
Определяет промежуток, в который происходит взаимодействие между нодами.
"""
def split(self, node1: dict, node2: dict) -> pd.DataFrame:
n1_to_n2 = self._form_intervals(start=node1['sent'], end=node2['received'])
n2_to_n1 = self._form_intervals(start=node2['sent'], end=node1['received'])
return pd.concat([pd.DataFrame(n1_to_n2), pd.DataFrame(n2_to_n1)])
if __name__ == "__main__": if __name__ == "__main__":
path = "D:\downloads\Test2\TeslaTIME29_71_KRCIO.dat" path = "D:\downloads\Test2\TeslaTIME29_71_KRCIO.dat"

View File

@ -1,7 +1,7 @@
from __future__ import annotations from __future__ import annotations
import os import os
from typing import Optional, Tuple from typing import Tuple
from dataclasses import dataclass from dataclasses import dataclass, field
import numpy as np import numpy as np
import pandas as pd import pandas as pd
@ -14,6 +14,29 @@ class KukaDataHead:
channels: dict channels: dict
@dataclass
class KukaTXT:
time: float = 0
endtime: float = 0
#module: str
func: str = ""
type_: str = ""
signal: str = ""
#line: int = 0
#point_name: str = ""
#point_coord: dict = field(default_factory=lambda: {})
#blending: str = ""
#blending_param: float = 0
#velocities: dict = field(default_factory=lambda: {})
#accelerarions: dict = field(default_factory=lambda: {})
#base: dict = field(default_factory=lambda: {})
#tool: dict = field(default_factory=lambda: {})
#ipo_mode: str = ""
#motion_mode: str = ""
#load: dict = field(default_factory=lambda: {})
#load_a3: dict = field(default_factory=lambda: {})
class KukaDataParser: class KukaDataParser:
def parse(self, head_path: str) -> pd.DataFrame: def parse(self, head_path: str) -> pd.DataFrame:
@ -95,127 +118,125 @@ class KukaDataParser:
data = file.read() data = file.read()
floats = np.frombuffer(data, dtype='<d') floats = np.frombuffer(data, dtype='<d')
return floats return floats
#TODO: Реализовать поиск времени простоя
class DowntimeAnalyzer:
def __init__(self) -> None:
...
def generate_downtime_report(self) -> list:
...
def _separate_conditions(self, TWC_raw:pd.DataFrame, robot_raw:pd.DataFrame) -> Tuple[dict, dict]:
robot_splitter = RobotConditionSplitter()
TWC_splitter = TWC_ConditionSplitter()
#comm_splitter = CommConditionSplitter()
rob_conditions = robot_splitter.split(robot_raw)
TWC_conditions = TWC_splitter.split(TWC_raw)
#comm_df = comm_splitter.split(rob_conditions["communication"], TWC_conditions["communication"])
return (rob_conditions, TWC_conditions)
class ConditionSplitter: class TXT_Parser:
def __init__(self): def __init__(self):
self._signals = [] self._in_msg = False
self._datapacks = []
def _find_indexes(self, def parse(self, path:str ):
signal: str, self._datapacks = []
dataframe: pd.DataFrame) -> list[list[float], list[float]]: with open(path, 'r') as file:
stage_diff = np.diff(dataframe[signal]) datapack = KukaTXT()
start_idx = np.where(stage_diff == 1) for line in file:
finish_idx = np.where(stage_diff == -1) line = line.strip()
return start_idx[0], finish_idx[0] datapack = self._check_msg_flow(line, datapack)
def _find_events(self,
dataframe: pd.DataFrame,
signals: list[str]) -> Optional[dict[dict[pd.Series]]]:
intervals = {}
end_time = 0
for signal in signals:
start_idx, finish_idx = np.array(self._find_indexes(signal, dataframe))
start_series = dataframe.loc[start_idx, "time"].reset_index(drop=True)
end_series = dataframe.loc[finish_idx, "time"].reset_index(drop=True)
end_series.fillna(end_time)
intervals[signal] = {"rise": start_series,
"fall": end_series}
return intervals
def _form_intervals(self,
start: pd.Series,
end: pd.Series) -> dict:
if len(start) != len(end):
for i in range(1, len(end)):
if end[i-1] > start[i]:
start = start.drop(i).reset_index(drop=True)
intervals = {'start':start.tolist, 'end':end.tolist}
return intervals
class RobotConditionSplitter(ConditionSplitter): def _check_msg_flow(self, line:str, datapack:KukaTXT) -> KukaTXT:
def __init__(self): if line == "#BEGINMOTIONINFO":
self._signals = [ self._in_msg = True
"$OUT3012", datapack = KukaTXT()
"$IN3003", elif line == "#ENDMOTIONINFO":
"$OUT3003", self._in_msg = False
"$OUT3244" self._datapacks.append(datapack)
] datapack = KukaTXT()
elif self._in_msg:
datapack = self._process_line(line, datapack)
return datapack
def split(self, dataframe: pd.DataFrame) -> dict: def _process_line(self, line:str, datapack:KukaTXT) -> KukaTXT:
events = self._find_events(dataframe, self._signals) tag, data = line.split(":")
communication_sig = {'sent':events["$OUT3244"]["fall"], 'received':events[""][""]} match tag:
point_interval = self._form_intervals(start=events["$OUT3012"]["rise"], end=events["$OUT3012"]["fall"]) case "TIME":
movement_interval = self._form_intervals(start=events["$OUT3244"]["rise"], end=events["$OUT3244"]["fall"]) datapack.time = float(data)
conditions = {"communication":communication_sig, "waiting": point_interval, "moving": movement_interval} case "ENDTIME":
return conditions datapack.endtime = float(data)
case "MODULE":
pass
case "FUNCTION/PROCEDURE":
datapack.func = data
case "TYPE":
datapack.type_ = data
case "SIGNAL":
datapack.signal = data
case "LINE":
pass
case "POINT NAME":
pass
case "POINT COORDINATES":
pass
case "BLENDING":
pass
case "BLENDING PARAMETER":
pass
case "VELOCITIES":
pass
case "ACCELERATIONS":
pass
case "BASE":
pass
case "TOOL":
pass
case "IPO MODE":
pass
case "MOTION MODE":
pass
case "LOAD":
pass
case "LOAD A3":
pass
return datapack
"Перемещение"
class TWC_ConditionSplitter(ConditionSplitter): #FUNCTION/PROCEDURE: SW_RSP030TL01_SN - какое-то перемещение
def __init__(self): #
self._signals = [ # ИЛИ
"Closing", #
"Squeeze", #FUNCTION/PROCEDURE: SGL_MoveToPos - перемещение между точками
"Welding", #SIGNAL: BLENDING
"Relief",
"Oncoming"
]
def split(self, dataframe: pd.DataFrame) -> dict: "Смыкание и набор усилия"
events = self._find_events(dataframe, self._signals) #FUNCTION/PROCEDURE: SGM_MOVE_TO_FORCE - перемещение электрода движения робота
communication_sig = {'sent':events[""][""], 'received':events[""][""]} #ситара что-то делает -конец сигнала # ... ...
closing_interval = self._form_intervals(start=events["Closing"]["rise"], end=events["Closing"]["fall"]) #FUNCTION/PROCEDURE: SGM_MOVE_TO_FORCE - перемещение 0.5 мм роботом с движением электрода
squeeze_interval = self._form_intervals(start=events["Squeeze"]["rise"], end=events["Squeeze"]["fall"]) #... ...
relief_interval = self._form_intervals(start=events["Relief"]["rise"], end=events["Relief"]["fall"]) #FUNCTION/PROCEDURE: SGM_MOVE_TO_FORCE - остановка в позиции (может быть набор усилия?)
oncoming_interval = self._form_intervals(start=events["Oncoming"]["rise"], end=events["Oncoming"]["fall"])
conditions = {
"communication":communication_sig,
'closing':closing_interval,
'squeeze':squeeze_interval,
'relief':relief_interval,
'oncoming':oncoming_interval
}
return conditions
"Сварка"
#FUNCTION/PROCEDURE: SPOT - Начало сварочного процесса
#SIGNAL: START
#
#FUNCTION/PROCEDURE: SPOT - Конец сварочного процесса
#SIGNAL: END
class CommConditionSplitter(ConditionSplitter): "Снятие усилия и разъезд"
""" #FUNCTION/PROCEDURE: SGL_MoveToPos - Выход из контакта с точкой движением робота и электрода
Определяет промежуток, в который происходит взаимодействие между нодами. #SIGNAL: START
""" #
def split(self, node1: dict, node2: dict) -> pd.DataFrame:
n1_to_n2 = self._form_intervals(start=node1['sent'], end=node2['received'])
n2_to_n1 = self._form_intervals(start=node2['sent'], end=node1['received'])
return pd.concat([pd.DataFrame(n1_to_n2), pd.DataFrame(n2_to_n1)])
"Перемещение"
#FUNCTION/PROCEDURE: SW_RSP030TL01_SN - какое-то перемещение
#
# ИЛИ
#
#FUNCTION/PROCEDURE: SGL_MoveToPos - перемещение между точками
#SIGNAL: BLENDING
if __name__ == '__main__': if __name__ == '__main__':
roboreader = KukaDataParser() roboreader = KukaDataParser()
"""
path = os.path.abspath("trace_samples/teslaSP_VelTCP_KRCIpo.dat") path = os.path.abspath("trace_samples/teslaSP_VelTCP_KRCIpo.dat")
data = roboreader.parse(os.path.abspath(path)) data = roboreader.parse(os.path.abspath(path))
save = os.path.dirname(path) + "/sample.csv" save = os.path.dirname(path) + "/sample.csv"
data.to_csv(save) data.to_csv(save)"""
path = os.path.abspath("trace_samples/teslaSP_VelTCP_PROG.TXT")
txt_parser = TXT_Parser()
txt_parser.parse(path)
print(len(txt_parser._datapacks))