From fe1071287b82abcfc34fd29480000ad931aba288 Mon Sep 17 00:00:00 2001 From: hit_lu Date: Fri, 14 Nov 2025 11:33:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9F=BA=E7=A1=80=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=BB=93=E6=9E=84=E3=80=81=E5=85=AC=E7=94=A8=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E3=80=81=E6=8E=A5=E5=8F=A3=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/common.py | 51 +++++++++++++++++++++++++++ core/interface.py | 7 ++++ data/loader.py | 67 ++++++++++++++++++++++++++++++++++++ data/type.py | 88 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 213 insertions(+) create mode 100644 core/common.py create mode 100644 core/interface.py create mode 100644 data/loader.py create mode 100644 data/type.py diff --git a/core/common.py b/core/common.py new file mode 100644 index 0000000..b9c17d8 --- /dev/null +++ b/core/common.py @@ -0,0 +1,51 @@ +from functools import wraps, reduce +from collections import defaultdict +from tqdm import tqdm + +import os +import time +import math +import random +import copy +import argparse +# import joblib +import pickle +import warnings +import heapq +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import matplotlib +import traceback +import openpyxl +import itertools + + +matplotlib.use('TkAgg') + +# feeder_width = {'SM8': (7.25, 7.25), 'SM12': (7.00, 20.00), 'SM16': (7.00, 22.00), +# 'SM24': (7.00, 29.00), 'SM32': (7.00, 44.00), 'SME8': (7.25, 7.25), +# 'SME12': (7.00, 20.00), 'SME16': (7.00, 22.00), 'SME24': (7.00, 29.00), +# 'SME32': (7.00, 44.00), 'Tray Feeder': (7.25, 7.25)} +feeder_width = {'SM8': (7.25, 7.25), 'SM12': (7.25, 7.25), 'SM16': (7.25, 7.25), + 'SM24': (7.25, 7.25), 'SM32': (7.25, 7.25), 'SME8': (7.25, 7.25), + 'SME12': (7.25, 7.25), 'SME16': (7.25, 7.25), 'SME24': (7.25, 7.25), + 'SME32': (7.25, 7.25), 'Tray Feeder': (7.25, 7.25)} + +nozzle_limit = {'CN065': 100, 'CN040': 100, 'CN020': 100, 'CN400': 100, 'CN140': 100, 'CN220': 100, 'CN750': 100} + + +def timer_wrapper(func): + @wraps(func) + def measure_time(*args, **kwargs): + start_time = time.time() + result = func(*args, **kwargs) + hinter = True + for key, val in kwargs.items(): + if key == 'hinter': + hinter = val + if hinter: + print(f"function {func.__name__} running time : {time.time() - start_time:.3f} s") + return result + + return measure_time diff --git a/core/interface.py b/core/interface.py new file mode 100644 index 0000000..17e8e16 --- /dev/null +++ b/core/interface.py @@ -0,0 +1,7 @@ +# 用于提供对外接口 +from data.type import MachineConfig +from opt.smm.basis import * +from opt.smm.feeder_priority import FeederPriorityOpt +from opt.smm.cell_division import CellDivisionOpt +from opt.smm.hybrid_genetic import HybridGeneticOpt +from opt.smm.aggregation import Aggregation diff --git a/data/loader.py b/data/loader.py new file mode 100644 index 0000000..3b4ce95 --- /dev/null +++ b/data/loader.py @@ -0,0 +1,67 @@ +from core.common import * +from data.type import Point + + +def load_data(filename: str): + filename = 'file/' + filename + origin = Point(0, 0) + coordinate = '' + part_skiprows, part_rows, step_skiprows, step_rows = -1, -1, -1, -1 + + line_counter = 0 + with open(filename, 'r') as file: + while line := file.readline(): + if line == '[PART]\n': + part_skiprows = line_counter + 1 + elif line == '[STEP]\n': + step_skiprows = line_counter + 1 + elif line == '\n': + if part_skiprows != -1 and part_rows == -1: + part_rows = line_counter - part_skiprows + elif step_skiprows != -1 and step_rows == -1: + step_rows = line_counter - step_skiprows + + if line.startswith('Coordinate'): + coordinate = line.split('=')[1].strip() + elif line.startswith('Placement Origin'): + x, y = line.split('=')[1].strip().split(',') + origin.x, origin.y = float(x.strip()), float(y.strip()) + + line_counter += 1 + + if part_skiprows != -1 and part_rows == -1: + part_rows = line_counter - part_skiprows + if step_skiprows != -1 and step_rows == -1: + step_rows = line_counter - step_skiprows + + step_data = pd.DataFrame( + pd.read_csv(filepath_or_buffer=filename, skiprows=step_skiprows, nrows=step_rows, sep='\t', header=None)) + step_data.columns = ["ref", "x", "y", "z", "r", "part", "layer"] + + part_col = ["part", "fdr", "nz", "fdn"] + try: + if part_skiprows != -1: + part_data = pd.DataFrame(pd.read_csv(filepath_or_buffer=filename, sep='\t', header=None, + skiprows=part_skiprows, nrows=part_rows)) + part_data.columns = part_col + else: + part_data = pd.DataFrame(columns=part_col) + except: + part_data = pd.DataFrame(columns=part_col) + + for _, data in step_data.iterrows(): + if data.part not in part_data.part.values: + raise Exception("unregistered component: " + data.part) + + if coordinate == "UPPER RIGHT" or coordinate == "LOWER RIGHT": + data.x = -data.x + if coordinate == "UPPER LEFT" or coordinate == "UPPER RIGHT": + data.y = data.y + data.x, data.y = data.x + origin.x, data.y + origin.y + + return part_data, step_data + + +def load_config(filepath: str): + pass + diff --git a/data/type.py b/data/type.py new file mode 100644 index 0000000..49002da --- /dev/null +++ b/data/type.py @@ -0,0 +1,88 @@ + + +class Point: + def __init__(self, _x, _y, _r=0, _h=None): + self.x = _x + self.y = _y + self.r = _r + self.h = _h + + +class MachineConfig: + def __init__(self): + self.head_num = 6 + self.slot_num = 120 + self.slot_intv = 15 + self.head_intv = 30 + self.slotf1_pos = Point(-31.327, 44.) + self.slotr1_pos = Point(807., 810.545) + self.stopper_pos = Point(665.150, 124.738) + self.anc_pos = Point(336.457, 626.230) + + self.pick_time = .078 # ʰȡʱ + self.place_time = .051 # װʱ + self.nozzle_install_time = 0.9 # װʱ + self.nozzle_uninstall_time = 0.75 # жʱ + + +class OptResult: + def __init__(self): + self.part = [] + self.cycle = [] + self.slot = [] + self.point = [] + self.sequence = [] + + def __add__(self, other): + self.part.extend(other.part) + self.cycle.extend(other.cycle) + self.slot.extend(other.slot) + self.point.extend(other.point) + self.sequence.extend(other.sequence) + + return self + + +class OptInfo: + def __init__(self): + self.total_time = .0 # װʱ + self.total_points = 0 # װ + self.total_components = 0 # Ԫ + + self.pickup_time = .0 # ʰȡ˶ʱ + self.round_time = .0 # /˶ʱ + self.place_time = .0 # װ˶ʱ + self.operation_time = .0 # ʰȡ/װ/Ȼеʱ + + self.cycle_counter = 0 # + self.nozzle_change_counter = 0 # + self.anc_round_counter = 0 # ǰANC + self.pickup_counter = 0 # ʰȡ + + self.total_distance = .0 # ƶ· + self.place_distance = .0 # װƶ· + self.pickup_distance = .0 # ʰȡƶ· + + def print(self): + print('-Cycle counter: {}'.format(self.cycle_counter)) + + print(f'-Nozzle change counter: {self.nozzle_change_counter: d}') + print(f'-ANC round: {self.anc_round_counter: d}') + print(f'-Pick operation counter: {self.pickup_counter: d}') + print(f'-Pick time: {self.pickup_time: .3f}, Pick distance: {self.pickup_distance: .3f}') + print(f'-Place time: {self.place_time: .3f}, Place distance: {self.place_distance: .3f}') + print( + f'-Round time: {self.total_time - self.operation_time - self.pickup_time - self.place_time: .3f}, Round distance: ' + f'{self.total_distance - self.pickup_distance - self.place_distance: .3f}') + + print(f'-Round & place time per cycle: {(self.total_time - self.pickup_time - self.operation_time) * 1000.0 / (self.cycle_counter + 1e-10): .3f}, ', end='') + print(f'-Round & place distance per cycle: {(self.total_distance - self.pickup_distance) / (self.cycle_counter + 1e-10): .3f}') + + minutes, seconds = int(self.total_time // 60), int(self.total_time) % 60 + millisecond = int((self.total_time - minutes * 60 - seconds) * 60) + + print(f'-Operation time: {self.operation_time: .3f}, ', end='') + if minutes > 0: + print(f'Total time: {minutes: d} min {seconds} s {millisecond: 2d} ms ({self.total_time: .3f}s)') + else: + print(f'Total time: {seconds} s {millisecond :2d} ms ({self.total_time :.3f}s)')