整线优化第一版论文定稿工程

增加了整线批量测试
修改了现有min-max模型路径
修改了遗传算法整体框架
估计器增加异常数据剔除
封装优化结果类
修改供料器扫描算法中重复吸嘴组的判定
This commit is contained in:
2024-06-26 09:44:08 +08:00
parent cbeba48da0
commit 37f4e5b02c
14 changed files with 749 additions and 669 deletions

View File

@ -11,6 +11,7 @@ import math
import random
import copy
import torch
import torch.nn
import argparse
import joblib
import pickle
@ -20,6 +21,7 @@ import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
import traceback
matplotlib.use('TkAgg')
@ -64,6 +66,18 @@ t_fix_camera_check = 0.12 # 固定相机检测时间
# 时间参数(整线相关)
T_pp, T_tr, T_nc, T_pl = 2, 5, 25, 0
# 时间参数 (数据拟合获得)
Fit_cy, Fit_nz, Fit_pu, Fit_pl, Fit_mv = 0.326, 0.8694, 0.159, 0.041, 0.001
class OptResult:
def __init__(self, cp_assign=None, cycle_assign=None, slot_assign=None, place_assign=None, sequence_assign=None):
self.component_assign = [] if cp_assign is None else cp_assign
self.cycle_assign = [] if cycle_assign is None else cycle_assign
self.feeder_slot_assign = [] if slot_assign is None else slot_assign
self.placement_assign = [] if place_assign is None else place_assign
self.head_sequence = [] if sequence_assign is None else sequence_assign
class OptInfo:
def __init__(self):
@ -93,6 +107,22 @@ class OptInfo:
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.place_time - self.place_time: .3f}, Place distance: '
f'{self.total_distance - self.pickup_distance - self.place_distance: .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)')
def metric(self):
return Fit_cy * self.cycle_counter + Fit_nz * self.nozzle_change_counter + Fit_pu * self.pickup_counter + \
Fit_pl * self.total_points + Fit_mv * self.pickup_distance
def axis_moving_time(distance, axis=0):
@ -438,6 +468,8 @@ def greedy_placement_route_generation(component_data, pcb_data, component_result
for cycle_set in range(len(component_result)):
floor_cycle, ceil_cycle = sum(cycle_result[:cycle_set]), sum(cycle_result[:(cycle_set + 1)])
for cycle in range(floor_cycle, ceil_cycle):
if sum(component_result[cycle_set]) == -max_head_index:
continue
# search_dir = 1 - search_dir
assigned_placement = [-1] * max_head_index
max_pos = [max(mount_point_pos[component_index], key=lambda x: x[0]) for component_index in
@ -936,7 +968,7 @@ def constraint_swap_mutation(component_points, individual, machine_number):
for points in component_points.values():
if component_index == 0:
while True:
index1, index2 = random.sample(range(points + machine_number - 2), 2)
index1, index2 = random.sample(range(points + machine_number - 1), 2)
if offspring[idx + index1] != offspring[idx + index2]:
break
@ -1050,11 +1082,13 @@ def convert_line_assigment(pcb_data, component_data, assignment_result):
placement_points = []
partial_pcb_data, partial_component_data = defaultdict(pd.DataFrame), defaultdict(pd.DataFrame)
for machine_index in range(machine_number):
partial_pcb_data[machine_index] = pd.DataFrame(columns=pcb_data.columns)
if pcb_data is not None:
partial_pcb_data[machine_index] = pd.DataFrame(columns=pcb_data.columns)
partial_component_data[machine_index] = component_data.copy(deep=True)
placement_points.append(sum(assignment_result[machine_index]))
assert sum(placement_points) == len(pcb_data)
if pcb_data is not None:
assert sum(placement_points) == len(pcb_data)
# === averagely assign available feeder ===
for part_index, data in component_data.iterrows():
@ -1062,7 +1096,11 @@ def convert_line_assigment(pcb_data, component_data, assignment_result):
feeder_points = [assignment_result[machine_index][part_index] for machine_index in range(machine_number)]
for machine_index in range(machine_number):
partial_component_data[machine_index].loc[part_index, 'points'] = 0
if pcb_data is None:
partial_component_data[machine_index].loc[part_index, 'points'] = assignment_result[machine_index][
part_index]
else:
partial_component_data[machine_index].loc[part_index, 'points'] = 0
for machine_index in range(machine_number):
if feeder_points[machine_index] == 0:
@ -1084,80 +1122,81 @@ def convert_line_assigment(pcb_data, component_data, assignment_result):
partial_component_data[machine_index].loc[part_index].fdn > feeder_points[
assign_machine] / partial_component_data[assign_machine].loc[part_index].fdn:
assign_machine = machine_index
partial_component_data[assign_machine].loc[part_index, 'fdn'] += 1
feeder_limit -= 1
assert assign_machine is not None
partial_component_data[assign_machine].loc[part_index, 'fdn'] += 1
feeder_limit -= 1
for machine_index in range(machine_number):
if feeder_points[machine_index] > 0:
assert partial_component_data[machine_index].loc[part_index].fdn > 0
# === assign placements ===
part2idx = defaultdict(int)
for idx, data in component_data.iterrows():
part2idx[data.part] = idx
if pcb_data is not None:
part2idx = defaultdict(int)
for idx, data in component_data.iterrows():
part2idx[data.part] = idx
machine_average_pos = [[0, 0] for _ in range(machine_number)]
machine_step_counter = [0 for _ in range(machine_number)]
part_pcb_data = defaultdict(list)
for _, data in pcb_data.iterrows():
part_pcb_data[part2idx[data.part]].append(data)
machine_average_pos = [[0, 0] for _ in range(machine_number)]
machine_step_counter = [0 for _ in range(machine_number)]
part_pcb_data = defaultdict(list)
for _, data in pcb_data.iterrows():
part_pcb_data[part2idx[data.part]].append(data)
multiple_component_index = []
for part_index in range(len(component_data)):
machine_assign_set = []
for machine_index in range(machine_number):
if assignment_result[machine_index][part_index]:
machine_assign_set.append(machine_index)
if len(machine_assign_set) == 1:
for data in part_pcb_data[part_index]:
machine_index = machine_assign_set[0]
machine_average_pos[machine_index][0] += data.x
machine_average_pos[machine_index][1] += data.y
machine_step_counter[machine_index] += 1
partial_component_data[machine_index].loc[part_index, 'points'] += 1
partial_pcb_data[machine_index] = pd.concat([partial_pcb_data[machine_index], pd.DataFrame(data).T])
elif len(machine_assign_set) > 1:
multiple_component_index.append(part_index)
for machine_index in range(machine_number):
if machine_step_counter[machine_index] == 0:
continue
machine_average_pos[machine_index][0] /= machine_step_counter[machine_index]
machine_average_pos[machine_index][1] /= machine_step_counter[machine_index]
for part_index in multiple_component_index:
for data in part_pcb_data[part_index]:
idx = -1
min_dist = None
multiple_component_index = []
for part_index in range(len(component_data)):
machine_assign_set = []
for machine_index in range(machine_number):
if partial_component_data[machine_index].loc[part_index, 'points'] >= \
assignment_result[machine_index][part_index]:
continue
dist = (data.x - machine_average_pos[machine_index][0]) ** 2 + (
data.y - machine_average_pos[machine_index][1]) ** 2
if min_dist is None or dist < min_dist:
min_dist, idx = dist, machine_index
if assignment_result[machine_index][part_index]:
machine_assign_set.append(machine_index)
assert idx >= 0
machine_step_counter[idx] += 1
machine_average_pos[idx][0] += (1 - 1 / machine_step_counter[idx]) * machine_average_pos[idx][0] + data.x / \
machine_step_counter[idx]
machine_average_pos[idx][1] += (1 - 1 / machine_step_counter[idx]) * machine_average_pos[idx][1] + data.y / \
machine_step_counter[idx]
if len(machine_assign_set) == 1:
for data in part_pcb_data[part_index]:
machine_index = machine_assign_set[0]
partial_component_data[idx].loc[part_index, 'points'] += 1
partial_pcb_data[idx] = pd.concat([partial_pcb_data[idx], pd.DataFrame(data).T])
machine_average_pos[machine_index][0] += data.x
machine_average_pos[machine_index][1] += data.y
for machine_index in range(machine_number):
partial_component_data[machine_index] = partial_component_data[machine_index][
partial_component_data[machine_index]['points'] != 0].reset_index(drop=True)
machine_step_counter[machine_index] += 1
partial_component_data[machine_index].loc[part_index, 'points'] += 1
partial_pcb_data[machine_index] = pd.concat([partial_pcb_data[machine_index], pd.DataFrame(data).T])
elif len(machine_assign_set) > 1:
multiple_component_index.append(part_index)
for machine_index in range(machine_number):
if machine_step_counter[machine_index] == 0:
continue
machine_average_pos[machine_index][0] /= machine_step_counter[machine_index]
machine_average_pos[machine_index][1] /= machine_step_counter[machine_index]
for part_index in multiple_component_index:
for data in part_pcb_data[part_index]:
idx = -1
min_dist = None
for machine_index in range(machine_number):
if partial_component_data[machine_index].loc[part_index, 'points'] >= \
assignment_result[machine_index][part_index]:
continue
dist = (data.x - machine_average_pos[machine_index][0]) ** 2 + (
data.y - machine_average_pos[machine_index][1]) ** 2
if min_dist is None or dist < min_dist:
min_dist, idx = dist, machine_index
assert idx >= 0
machine_step_counter[idx] += 1
machine_average_pos[idx][0] += (1 - 1 / machine_step_counter[idx]) * machine_average_pos[idx][0] \
+ data.x / machine_step_counter[idx]
machine_average_pos[idx][1] += (1 - 1 / machine_step_counter[idx]) * machine_average_pos[idx][1] \
+ data.y / machine_step_counter[idx]
partial_component_data[idx].loc[part_index, 'points'] += 1
partial_pcb_data[idx] = pd.concat([partial_pcb_data[idx], pd.DataFrame(data).T])
for machine_index in range(machine_number):
partial_component_data[machine_index] = partial_component_data[machine_index][
partial_component_data[machine_index]['points'] != 0].reset_index(drop=True)
return partial_pcb_data, partial_component_data