整线优化第一版论文定稿工程
增加了整线批量测试 修改了现有min-max模型路径 修改了遗传算法整体框架 估计器增加异常数据剔除 封装优化结果类 修改供料器扫描算法中重复吸嘴组的判定
This commit is contained in:
@ -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
|
||||
|
||||
|
@ -10,33 +10,33 @@ from base_optimizer.smopt_mathmodel import *
|
||||
from base_optimizer.result_analysis import *
|
||||
|
||||
|
||||
def base_optimizer(machine_index, pcb_data, component_data, feeder_data=None, method='', hinter=False):
|
||||
def base_optimizer(machine_index, pcb_data, component_data, feeder_data, params, hinter=False):
|
||||
|
||||
if method == 'cell-division': # 基于元胞分裂的遗传算法
|
||||
if params.machine_optimizer == 'cell-division': # 基于元胞分裂的遗传算法
|
||||
component_result, cycle_result, feeder_slot_result = optimizer_celldivision(pcb_data, component_data)
|
||||
placement_result, head_sequence = greedy_placement_route_generation(component_data, pcb_data, component_result,
|
||||
cycle_result, feeder_slot_result)
|
||||
elif method == 'feeder-scan': # 基于基座扫描的供料器优先算法
|
||||
elif params.machine_optimizer == 'feeder-scan': # 基于基座扫描的供料器优先算法
|
||||
component_result, cycle_result, feeder_slot_result = feeder_priority_assignment(component_data, pcb_data)
|
||||
placement_result, head_sequence = greedy_placement_route_generation(component_data, pcb_data, component_result,
|
||||
cycle_result, feeder_slot_result)
|
||||
# placement_result, head_sequence = beam_search_for_route_generation(component_data, pcb_data, component_result,
|
||||
# cycle_result, feeder_slot_result)
|
||||
|
||||
elif method == 'hybrid-genetic': # 基于拾取组的混合遗传算法
|
||||
elif params.machine_optimizer == 'hybrid-genetic': # 基于拾取组的混合遗传算法
|
||||
component_result, cycle_result, feeder_slot_result, placement_result, head_sequence = optimizer_hybrid_genetic(
|
||||
pcb_data, component_data, hinter=hinter)
|
||||
|
||||
elif method == 'aggregation': # 基于batch-level的整数规划 + 启发式算法
|
||||
elif params.machine_optimizer == 'aggregation': # 基于batch-level的整数规划 + 启发式算法
|
||||
component_result, cycle_result, feeder_slot_result, placement_result, head_sequence = optimizer_aggregation(
|
||||
component_data, pcb_data)
|
||||
elif method == 'genetic-scanning':
|
||||
elif params.machine_optimizer == 'genetic-scanning':
|
||||
component_result, cycle_result, feeder_slot_result, placement_result, head_sequence = optimizer_genetic_scanning(
|
||||
component_data, pcb_data, hinter=hinter)
|
||||
elif method == 'mip-model':
|
||||
elif params.machine_optimizer == 'mip-model':
|
||||
component_result, cycle_result, feeder_slot_result, placement_result, head_sequence = optimizer_mathmodel(
|
||||
component_data, pcb_data, hinter=hinter)
|
||||
elif method == "two-phase":
|
||||
elif params.machine_optimizer == "two-phase":
|
||||
component_result, feeder_slot_result, cycle_result = gurobi_optimizer(pcb_data, component_data, feeder_data,
|
||||
initial=True, partition=True,
|
||||
reduction=True, hinter=hinter)
|
||||
@ -44,17 +44,21 @@ def base_optimizer(machine_index, pcb_data, component_data, feeder_data=None, me
|
||||
placement_result, head_sequence = scan_based_placement_route_generation(component_data, pcb_data,
|
||||
component_result, cycle_result)
|
||||
else:
|
||||
raise 'machine optimizer method ' + method + ' is not existed'
|
||||
raise 'machine optimizer method ' + params.method + ' is not existed'
|
||||
|
||||
print('----- Placement machine ' + str(machine_index) + ' ----- ')
|
||||
opt_res = OptResult(component_result, cycle_result, feeder_slot_result, placement_result, head_sequence)
|
||||
# 估算贴装用时
|
||||
info = placement_info_evaluation(component_data, pcb_data, component_result, cycle_result, feeder_slot_result,
|
||||
placement_result, head_sequence, hinter=False)
|
||||
info = placement_info_evaluation(component_data, pcb_data, opt_res, hinter=False)
|
||||
if hinter:
|
||||
optimization_assign_result(component_data, pcb_data, component_result, cycle_result, feeder_slot_result,
|
||||
nozzle_hinter=True, component_hinter=True, feeder_hinter=True)
|
||||
optimization_assign_result(component_data, pcb_data, opt_res, nozzle_hinter=True, component_hinter=True,
|
||||
feeder_hinter=True)
|
||||
info.print()
|
||||
print('------------------------------ ')
|
||||
|
||||
print('------------------------------ ')
|
||||
if params.save:
|
||||
output_optimize_result(
|
||||
f'result/{params.filename[:-4]}-{params.line_optimizer}-M0{machine_index} {params.save_suffix}',
|
||||
component_data, pcb_data, opt_res)
|
||||
|
||||
return info
|
||||
|
@ -2,8 +2,7 @@ from base_optimizer.optimizer_common import *
|
||||
|
||||
|
||||
def convert_pcbdata_to_result(pcb_data, component_data):
|
||||
component_result, cycle_result, feeder_slot_result = [], [], []
|
||||
placement_result, head_sequence_result = [], []
|
||||
opt_res = OptResult()
|
||||
|
||||
assigned_part = [-1 for _ in range(max_head_index)]
|
||||
assigned_slot = [-1 for _ in range(max_head_index)]
|
||||
@ -14,19 +13,19 @@ def convert_pcbdata_to_result(pcb_data, component_data):
|
||||
for point_cnt in range(point_num + 1):
|
||||
|
||||
cycle_start = 1 if point_cnt == point_num else pcb_data.loc[point_cnt, 'cs']
|
||||
if (cycle_start and point_cnt != 0) or -1 not in assigned_part:
|
||||
if (cycle_start and point_cnt != 0) or -1 not in assigned_part:
|
||||
|
||||
if len(component_result) != 0 and component_result[-1] == assigned_part:
|
||||
cycle_result[-1] += 1
|
||||
if len(opt_res.component_assign) != 0 and opt_res.component_assign[-1] == assigned_part:
|
||||
opt_res.cycle_assign[-1] += 1
|
||||
else:
|
||||
component_result.append(assigned_part)
|
||||
feeder_slot_result.append(assigned_slot)
|
||||
cycle_result.append(1)
|
||||
opt_res.component_assign.append(assigned_part)
|
||||
opt_res.feeder_slot_assign.append(assigned_slot)
|
||||
opt_res.cycle_assign.append(1)
|
||||
|
||||
# assigned_sequence = list(reversed(assigned_sequence)) # Samsung拾取顺序相反
|
||||
|
||||
placement_result.append(assigned_point)
|
||||
head_sequence_result.append(assigned_sequence)
|
||||
opt_res.placement_assign.append(assigned_point)
|
||||
opt_res.head_sequence.append(assigned_sequence)
|
||||
|
||||
assigned_part = [-1 for _ in range(max_head_index)]
|
||||
assigned_slot = [-1 for _ in range(max_head_index)]
|
||||
@ -50,36 +49,35 @@ def convert_pcbdata_to_result(pcb_data, component_data):
|
||||
assigned_point[head] = point_cnt
|
||||
assigned_sequence.append(head)
|
||||
|
||||
return component_result, cycle_result, feeder_slot_result, placement_result, head_sequence_result
|
||||
return opt_res
|
||||
|
||||
|
||||
# 绘制各周期从供料器周期拾取的元件位置
|
||||
def pickup_cycle_schematic(feeder_slot_result, cycle_result):
|
||||
def pickup_cycle_schematic(optimizer_result):
|
||||
plt.rcParams['font.sans-serif'] = ['KaiTi'] # 指定默认字体
|
||||
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
|
||||
# data
|
||||
bar_width = .7
|
||||
feeder_part = np.zeros(int(max_slot_index / 2), dtype=np.int)
|
||||
for cycle in range(len(feeder_slot_result)):
|
||||
for cycle in range(len(optimizer_result.feeder_slot_assign)):
|
||||
label_str = '周期' + str(cycle + 1)
|
||||
cur_feeder_part = np.zeros(int(max_slot_index / 2), dtype=np.int)
|
||||
for slot in feeder_slot_result[cycle]:
|
||||
for slot in optimizer_result.feeder_slot_assign[cycle]:
|
||||
if slot > 0:
|
||||
cur_feeder_part[slot] += cycle_result[cycle]
|
||||
cur_feeder_part[slot] += optimizer_result.cycle_assign[cycle]
|
||||
|
||||
plt.bar(np.arange(max_slot_index / 2), cur_feeder_part, bar_width, edgecolor='black', bottom=feeder_part,
|
||||
label=label_str)
|
||||
|
||||
for slot in feeder_slot_result[cycle]:
|
||||
for slot in optimizer_result.feeder_slot_assign[cycle]:
|
||||
if slot > 0:
|
||||
feeder_part[slot] += cycle_result[cycle]
|
||||
feeder_part[slot] += optimizer_result.cycle_assign[cycle]
|
||||
|
||||
plt.legend()
|
||||
plt.show()
|
||||
|
||||
|
||||
def placement_route_schematic(pcb_data, component_result, cycle_result, feeder_slot_result, placement_result,
|
||||
head_sequence, cycle=-1):
|
||||
def placement_route_schematic(pcb_data, optimizer_result, cycle=-1):
|
||||
|
||||
plt.figure('cycle {}'.format(cycle + 1))
|
||||
pos_x, pos_y = [], []
|
||||
@ -89,8 +87,8 @@ def placement_route_schematic(pcb_data, component_result, cycle_result, feeder_s
|
||||
# plt.text(pcb_data.loc[i]['x'], pcb_data.loc[i]['y'] + 0.1, '%d' % i, ha='center', va = 'bottom', size = 8)
|
||||
|
||||
mount_pos = []
|
||||
for head in head_sequence[cycle]:
|
||||
index = placement_result[cycle][head]
|
||||
for head in optimizer_result.head_sequence[cycle]:
|
||||
index = optimizer_result.placement_assign[cycle][head]
|
||||
plt.text(pos_x[index], pos_y[index] + 0.1, 'HD%d' % (head + 1), ha='center', va='bottom', size=10)
|
||||
plt.plot([pos_x[index], pos_x[index] - head * head_interval], [pos_y[index], pos_y[index]], linestyle='-.',
|
||||
color='black', linewidth=1)
|
||||
@ -105,9 +103,9 @@ def placement_route_schematic(pcb_data, component_result, cycle_result, feeder_s
|
||||
linewidth=1)
|
||||
|
||||
draw_x, draw_y = [], []
|
||||
for c in range(cycle, len(placement_result)):
|
||||
for c in range(cycle, len(optimizer_result.placement_assign)):
|
||||
for h in range(max_head_index):
|
||||
i = placement_result[c][h]
|
||||
i = optimizer_result.placement_assign[c][h]
|
||||
if i == -1:
|
||||
continue
|
||||
draw_x.append(pcb_data.loc[i]['x'] + stopper_pos[0])
|
||||
@ -124,18 +122,18 @@ def placement_route_schematic(pcb_data, component_result, cycle_result, feeder_s
|
||||
|
||||
feeder_part, feeder_counter = {}, {}
|
||||
placement_cycle = 0
|
||||
for cycle_, components in enumerate(component_result):
|
||||
for cycle_, components in enumerate(optimizer_result.component_assign):
|
||||
for head, component in enumerate(components):
|
||||
if component == -1:
|
||||
continue
|
||||
placement = placement_result[placement_cycle][head]
|
||||
slot = feeder_slot_result[cycle_][head]
|
||||
placement = optimizer_result.placement_assign[placement_cycle][head]
|
||||
slot = optimizer_result.feeder_slot_assign[cycle_][head]
|
||||
feeder_part[slot] = pcb_data.loc[placement]['part']
|
||||
if slot not in feeder_counter.keys():
|
||||
feeder_counter[slot] = 0
|
||||
|
||||
feeder_counter[slot] += cycle_result[cycle_]
|
||||
placement_cycle += cycle_result[cycle_]
|
||||
feeder_counter[slot] += optimizer_result.cycle_assign[cycle_]
|
||||
placement_cycle += optimizer_result.cycle_assign[cycle_]
|
||||
|
||||
for slot, part in feeder_part.items():
|
||||
plt.text(slotf1_pos[0] + slot_interval * (slot - 1), slotf1_pos[1] + 15,
|
||||
@ -153,9 +151,9 @@ def placement_route_schematic(pcb_data, component_result, cycle_result, feeder_s
|
||||
# 绘制拾取路径
|
||||
pick_slot = []
|
||||
cycle_group = 0
|
||||
while sum(cycle_result[0: cycle_group + 1]) < cycle:
|
||||
while sum(optimizer_result.cycle_assign[0: cycle_group + 1]) < cycle:
|
||||
cycle_group += 1
|
||||
for head, slot in enumerate(feeder_slot_result[cycle_group]):
|
||||
for head, slot in enumerate(optimizer_result.feeder_slot_assign[cycle_group]):
|
||||
if slot == -1:
|
||||
continue
|
||||
pick_slot.append(slot - head * interval_ratio)
|
||||
@ -164,10 +162,10 @@ def placement_route_schematic(pcb_data, component_result, cycle_result, feeder_s
|
||||
|
||||
next_cycle_group = 0
|
||||
next_pick_slot = max_slot_index
|
||||
while sum(cycle_result[0: next_cycle_group + 1]) < cycle + 1:
|
||||
while sum(optimizer_result.cycle_assign[0: next_cycle_group + 1]) < cycle + 1:
|
||||
next_cycle_group += 1
|
||||
if next_cycle_group < len(feeder_slot_result):
|
||||
for head, slot in enumerate(feeder_slot_result[cycle_group]):
|
||||
if next_cycle_group < len(optimizer_result.feeder_slot_assign):
|
||||
for head, slot in enumerate(optimizer_result.feeder_slot_assign[cycle_group]):
|
||||
if slot == -1:
|
||||
continue
|
||||
next_pick_slot = min(next_pick_slot, slot - head * interval_ratio)
|
||||
@ -185,8 +183,7 @@ def placement_route_schematic(pcb_data, component_result, cycle_result, feeder_s
|
||||
plt.show()
|
||||
|
||||
|
||||
def save_placement_route_figure(file_name, pcb_data, component_result, cycle_result, feeder_slot_result,
|
||||
placement_result, head_sequence):
|
||||
def save_placement_route_figure(file_name, pcb_data, optimizer_result):
|
||||
path = 'result/' + file_name[:file_name.find('.')]
|
||||
if not os.path.exists(path):
|
||||
os.mkdir(path)
|
||||
@ -199,12 +196,12 @@ def save_placement_route_figure(file_name, pcb_data, component_result, cycle_res
|
||||
|
||||
with tqdm(total=100) as pbar:
|
||||
pbar.set_description('save figure')
|
||||
for cycle in range(len(placement_result)):
|
||||
for cycle in range(len(optimizer_result.placement_assign)):
|
||||
plt.figure(cycle)
|
||||
|
||||
mount_pos = []
|
||||
for head in head_sequence[cycle]:
|
||||
index = placement_result[cycle][head]
|
||||
for head in optimizer_result.head_sequence[cycle]:
|
||||
index = optimizer_result.placement_assign[cycle][head]
|
||||
plt.text(pos_x[index], pos_y[index] + 0.1, 'HD%d' % (head + 1), ha='center', va='bottom', size=10)
|
||||
plt.plot([pos_x[index], pos_x[index] - head * head_interval], [pos_y[index], pos_y[index]],
|
||||
linestyle='-.', color='black', linewidth=1)
|
||||
@ -217,9 +214,9 @@ def save_placement_route_figure(file_name, pcb_data, component_result, cycle_res
|
||||
linewidth=1)
|
||||
|
||||
draw_x, draw_y = [], []
|
||||
for c in range(cycle, len(placement_result)):
|
||||
for c in range(cycle, len(optimizer_result.placement_assign)):
|
||||
for h in range(max_head_index):
|
||||
i = placement_result[c][h]
|
||||
i = optimizer_result.placement_assign[c][h]
|
||||
if i == -1:
|
||||
continue
|
||||
draw_x.append(pcb_data.loc[i]['x'] + stopper_pos[0])
|
||||
@ -235,18 +232,18 @@ def save_placement_route_figure(file_name, pcb_data, component_result, cycle_res
|
||||
|
||||
feeder_part, feeder_counter = {}, {}
|
||||
placement_cycle = 0
|
||||
for cycle_, components in enumerate(component_result):
|
||||
for cycle_, components in enumerate(optimizer_result.component_assign):
|
||||
for head, component in enumerate(components):
|
||||
if component == -1:
|
||||
continue
|
||||
placement = placement_result[placement_cycle][head]
|
||||
slot = feeder_slot_result[cycle_][head]
|
||||
placement = optimizer_result.placement_assign[placement_cycle][head]
|
||||
slot = optimizer_result.feeder_slot_assign[cycle_][head]
|
||||
feeder_part[slot] = pcb_data.loc[placement]['part']
|
||||
if slot not in feeder_counter.keys():
|
||||
feeder_counter[slot] = 0
|
||||
|
||||
feeder_counter[slot] += cycle_result[cycle_]
|
||||
placement_cycle += cycle_result[cycle_]
|
||||
feeder_counter[slot] += optimizer_result.cycle_assign[cycle_]
|
||||
placement_cycle += optimizer_result.cycle_assign[cycle_]
|
||||
|
||||
for slot, part in feeder_part.items():
|
||||
plt.text(slotf1_pos[0] + slot_interval * (slot - 1), slotf1_pos[1] + 15,
|
||||
@ -266,9 +263,9 @@ def save_placement_route_figure(file_name, pcb_data, component_result, cycle_res
|
||||
# 绘制拾取路径
|
||||
pick_slot = []
|
||||
cycle_group = 0
|
||||
while sum(cycle_result[0: cycle_group + 1]) < cycle:
|
||||
while sum(optimizer_result.cycle_assign[0: cycle_group + 1]) < cycle:
|
||||
cycle_group += 1
|
||||
for head, slot in enumerate(feeder_slot_result[cycle_group]):
|
||||
for head, slot in enumerate(optimizer_result.feeder_slot_assign[cycle_group]):
|
||||
if slot == -1:
|
||||
continue
|
||||
pick_slot.append(slot - head * interval_ratio)
|
||||
@ -286,46 +283,31 @@ def save_placement_route_figure(file_name, pcb_data, component_result, cycle_res
|
||||
plt.savefig(path + '/cycle_{}'.format(cycle + 1))
|
||||
|
||||
plt.close(cycle)
|
||||
pbar.update(100 / len(placement_result))
|
||||
pbar.update(100 / len(optimizer_result.placement_assign))
|
||||
|
||||
|
||||
def output_optimize_result(file_name, method, component_data, pcb_data, feeder_data, component_result, cycle_result,
|
||||
feeder_slot_result, placement_result, head_sequence):
|
||||
assert len(component_result) == len(feeder_slot_result)
|
||||
if feeder_data is None:
|
||||
warning_info = 'file: ' + file_name + ' optimize result is not existed!'
|
||||
warnings.warn(warning_info, UserWarning)
|
||||
return
|
||||
def output_optimize_result(file_path, component_data, pcb_data, optimizer_result):
|
||||
assert len(optimizer_result.component_assign) == len(optimizer_result.feeder_slot_assign)
|
||||
|
||||
output_data = pcb_data.copy(deep=True)
|
||||
|
||||
# 默认ANC参数
|
||||
anc_list = defaultdict(list)
|
||||
anc_list['CN065'] = list(range(14, 25, 2))
|
||||
anc_list['CN220'] = list(range(15, 26, 2))
|
||||
anc_list['CN020'] = list(range(15, 26, 2))
|
||||
anc_list['CN140'] = list(range(26, 37, 2))
|
||||
anc_list['CN400'] = list(range(27, 38, 2))
|
||||
|
||||
# 更新供料器组参数
|
||||
for cycle_set in range(len(cycle_result)):
|
||||
for head, component in enumerate(component_result[cycle_set]):
|
||||
if component == -1:
|
||||
continue
|
||||
if feeder_data[feeder_data['slot'] == feeder_slot_result[cycle_set][head]].index.empty:
|
||||
part = component_data.loc[component]['part']
|
||||
feeder_data.loc[len(feeder_data.index)] = [feeder_slot_result[cycle_set][head], part, 0]
|
||||
feeder_data.sort_values('slot', inplace=True, ascending=True, ignore_index=True)
|
||||
anc_list['CN040'] = list(range(27, 38, 2))
|
||||
|
||||
placement_index = []
|
||||
assigned_nozzle, assigned_anc_hole = ['' for _ in range(max_head_index)], [-1 for _ in range(max_head_index)]
|
||||
for cycle_set in range(len(cycle_result)):
|
||||
floor_cycle, ceil_cycle = sum(cycle_result[:cycle_set]), sum(cycle_result[:(cycle_set + 1)])
|
||||
for cycle_set in range(len(optimizer_result.cycle_assign)):
|
||||
floor_cycle, ceil_cycle = sum(optimizer_result.cycle_assign[:cycle_set]), sum(optimizer_result.cycle_assign[:(cycle_set + 1)])
|
||||
for cycle in range(floor_cycle, ceil_cycle):
|
||||
cycle_start = True
|
||||
cycle_nozzle = ['' for _ in range(max_head_index)]
|
||||
head_indexes = [-1 for _ in range(max_head_index)]
|
||||
for head in head_sequence[cycle]:
|
||||
index_ = placement_result[cycle][head]
|
||||
for head in optimizer_result.head_sequence[cycle]:
|
||||
index_ = optimizer_result.placement_assign[cycle][head]
|
||||
if index_ == -1:
|
||||
continue
|
||||
head_indexes[head] = index_
|
||||
@ -338,14 +320,14 @@ def output_optimize_result(file_name, method, component_data, pcb_data, feeder_d
|
||||
cycle_start = False
|
||||
|
||||
# 供料器信息
|
||||
slot = feeder_slot_result[cycle_set][head]
|
||||
slot = optimizer_result.feeder_slot_assign[cycle_set][head]
|
||||
fdr = 'F' + str(slot) if slot < max_slot_index // 2 else 'R' + str(slot - max_slot_index // 2)
|
||||
feeder_index = feeder_data[feeder_data['slot'] == slot].index.tolist()[0]
|
||||
|
||||
output_data.loc[index_, 'fdr'] = fdr + ' ' + feeder_data.loc[feeder_index, 'part']
|
||||
output_data.loc[index_, 'fdr'] = fdr + ' ' + component_data.loc[
|
||||
optimizer_result.component_assign[cycle_set][head], 'part']
|
||||
|
||||
# ANC信息
|
||||
cycle_nozzle[head] = component_data.loc[component_result[cycle_set][head], 'nz']
|
||||
cycle_nozzle[head] = component_data.loc[optimizer_result.component_assign[cycle_set][head], 'nz']
|
||||
|
||||
for head in range(max_head_index):
|
||||
nozzle = cycle_nozzle[head]
|
||||
@ -373,26 +355,25 @@ def output_optimize_result(file_name, method, component_data, pcb_data, feeder_d
|
||||
if 'desc' not in output_data.columns:
|
||||
column_index = int(np.where(output_data.columns.values.reshape(-1) == 'part')[0][0])
|
||||
output_data.insert(loc=column_index + 1, column='desc', value='')
|
||||
file_dir = file_path[:file_path.rfind('/') + 1]
|
||||
if not os.path.exists(file_dir):
|
||||
os.makedirs(file_dir)
|
||||
|
||||
if not os.path.exists('result/' + method):
|
||||
os.makedirs('result/' + method)
|
||||
|
||||
file_name = method + '/' + file_name.split('.')[0] + '.xlsx'
|
||||
output_data.to_excel('result/' + file_name, sheet_name='tb1', float_format='%.3f', na_rep='')
|
||||
output_data.to_excel(file_path + '.xlsx', sheet_name='tb1', float_format='%.3f', na_rep='')
|
||||
|
||||
|
||||
def optimization_assign_result(component_data, pcb_data, component_result, cycle_result, feeder_slot_result,
|
||||
nozzle_hinter=False, component_hinter=False, feeder_hinter=False):
|
||||
def optimization_assign_result(component_data, pcb_data, optimizer_result, nozzle_hinter=False, component_hinter=False,
|
||||
feeder_hinter=False):
|
||||
if nozzle_hinter:
|
||||
columns = ['H{}'.format(i + 1) for i in range(max_head_index)] + ['cycle']
|
||||
|
||||
nozzle_assign = pd.DataFrame(columns=columns)
|
||||
for cycle, components in enumerate(component_result):
|
||||
for cycle, components in enumerate(optimizer_result.component_assign):
|
||||
nozzle_assign_row = len(nozzle_assign)
|
||||
nozzle_assign.loc[nozzle_assign_row, 'cycle'] = cycle_result[cycle]
|
||||
nozzle_assign.loc[nozzle_assign_row, 'cycle'] = optimizer_result.cycle_assign[cycle]
|
||||
|
||||
for head in range(max_head_index):
|
||||
index = component_result[cycle][head]
|
||||
index = optimizer_result.component_assign[cycle][head]
|
||||
if index == -1:
|
||||
nozzle_assign.loc[nozzle_assign_row, 'H{}'.format(head + 1)] = ''
|
||||
else:
|
||||
@ -414,15 +395,14 @@ def optimization_assign_result(component_data, pcb_data, component_result, cycle
|
||||
columns = ['H{}'.format(i + 1) for i in range(max_head_index)] + ['cycle']
|
||||
|
||||
component_assign = pd.DataFrame(columns=columns)
|
||||
for cycle, components in enumerate(component_result):
|
||||
component_assign.loc[cycle, 'cycle'] = cycle_result[cycle]
|
||||
for cycle, components in enumerate(optimizer_result.component_assign):
|
||||
component_assign.loc[cycle, 'cycle'] = optimizer_result.cycle_assign[cycle]
|
||||
for head in range(max_head_index):
|
||||
index = component_result[cycle][head]
|
||||
index = optimizer_result.component_assign[cycle][head]
|
||||
if index == -1:
|
||||
component_assign.loc[cycle, 'H{}'.format(head + 1)] = ''
|
||||
else:
|
||||
part = component_data.loc[index]['part']
|
||||
component_assign.loc[cycle, 'H{}'.format(head + 1)] = part
|
||||
component_assign.loc[cycle, 'H{}'.format(head + 1)] = component_data.loc[index]['part']
|
||||
# component_assign.loc[cycle, 'H{}'.format(head + 1)] = 'C' + str(index)
|
||||
|
||||
print(component_assign)
|
||||
@ -432,41 +412,43 @@ def optimization_assign_result(component_data, pcb_data, component_result, cycle
|
||||
columns = ['H{}'.format(i + 1) for i in range(max_head_index)] + ['cycle']
|
||||
|
||||
feedr_assign = pd.DataFrame(columns=columns)
|
||||
for cycle, components in enumerate(feeder_slot_result):
|
||||
feedr_assign.loc[cycle, 'cycle'] = cycle_result[cycle]
|
||||
for cycle, components in enumerate(optimizer_result.feeder_slot_assign):
|
||||
feedr_assign.loc[cycle, 'cycle'] = optimizer_result.cycle_assign[cycle]
|
||||
for head in range(max_head_index):
|
||||
slot = feeder_slot_result[cycle][head]
|
||||
slot = optimizer_result.feeder_slot_assign[cycle][head]
|
||||
if slot == -1:
|
||||
feedr_assign.loc[cycle, 'H{}'.format(head + 1)] = 'A'
|
||||
else:
|
||||
feedr_assign.loc[cycle, 'H{}'.format(head + 1)] = 'F{}'.format(
|
||||
slot) if slot <= max_slot_index // 2 else 'R{}'.format(slot - max_head_index)
|
||||
try:
|
||||
feedr_assign.loc[cycle, 'H{}'.format(head + 1)] = 'F{}'.format(
|
||||
slot) if slot <= max_slot_index // 2 else 'R{}'.format(slot - max_head_index)
|
||||
except:
|
||||
print('')
|
||||
|
||||
print(feedr_assign)
|
||||
print('')
|
||||
|
||||
|
||||
def placement_info_evaluation(component_data, pcb_data, component_result, cycle_result, feeder_slot_result,
|
||||
placement_result=None, head_sequence=None, hinter=False):
|
||||
def placement_info_evaluation(component_data, pcb_data, optimizer_result, hinter=False):
|
||||
# === 优化结果参数 ===
|
||||
info = OptInfo()
|
||||
|
||||
# === 校验 ===
|
||||
info.total_points = 0
|
||||
for cycle, components in enumerate(component_result):
|
||||
for cycle, components in enumerate(optimizer_result.component_assign):
|
||||
for head, component in enumerate(components):
|
||||
if component == -1:
|
||||
continue
|
||||
info.total_points += cycle_result[cycle]
|
||||
info.total_points += optimizer_result.cycle_assign[cycle]
|
||||
|
||||
if info.total_points != len(pcb_data):
|
||||
warning_info = 'the number of placement points is not match with the PCB data. '
|
||||
warnings.warn(warning_info, UserWarning)
|
||||
return OptInfo()
|
||||
|
||||
if placement_result:
|
||||
if optimizer_result.placement_assign:
|
||||
total_points = info.total_points
|
||||
for placements in placement_result:
|
||||
for placements in optimizer_result.placement_assign:
|
||||
for placement in placements:
|
||||
if placement == -1:
|
||||
continue
|
||||
@ -479,11 +461,11 @@ def placement_info_evaluation(component_data, pcb_data, component_result, cycle_
|
||||
return OptInfo()
|
||||
|
||||
feeder_arrangement = defaultdict(set)
|
||||
for cycle, feeder_slots in enumerate(feeder_slot_result):
|
||||
for cycle, feeder_slots in enumerate(optimizer_result.feeder_slot_assign):
|
||||
for head, slot in enumerate(feeder_slots):
|
||||
if slot == -1:
|
||||
continue
|
||||
feeder_arrangement[component_result[cycle][head]].add(slot)
|
||||
feeder_arrangement[optimizer_result.component_assign[cycle][head]].add(slot)
|
||||
|
||||
info.total_components = len(feeder_arrangement.keys())
|
||||
for part, data in component_data.iterrows():
|
||||
@ -497,24 +479,26 @@ def placement_info_evaluation(component_data, pcb_data, component_result, cycle_
|
||||
# 初始化首个周期的吸嘴装配信息
|
||||
nozzle_assigned = ['Empty' for _ in range(max_head_index)]
|
||||
for head in range(max_head_index):
|
||||
for cycle in range(len(component_result)):
|
||||
idx = component_result[cycle][head]
|
||||
for cycle in range(len(optimizer_result.component_assign)):
|
||||
idx = optimizer_result.component_assign[cycle][head]
|
||||
if idx == -1:
|
||||
continue
|
||||
else:
|
||||
nozzle_assigned[head] = component_data.loc[idx]['nz']
|
||||
|
||||
for cycle_set, _ in enumerate(component_result):
|
||||
floor_cycle, ceil_cycle = sum(cycle_result[:cycle_set]), sum(cycle_result[:(cycle_set + 1)])
|
||||
for cycle_set, _ in enumerate(optimizer_result.component_assign):
|
||||
floor_cycle, ceil_cycle = sum(optimizer_result.cycle_assign[:cycle_set]), sum(optimizer_result.cycle_assign[:(cycle_set + 1)])
|
||||
for cycle in range(floor_cycle, ceil_cycle):
|
||||
if sum(optimizer_result.component_assign[cycle_set]) == -max_head_index:
|
||||
continue
|
||||
pick_slot, mount_pos, mount_angle = [], [], []
|
||||
nozzle_pick_counter, nozzle_put_counter = 0, 0 # 吸嘴更换次数统计(拾取/放置分别算一次)
|
||||
for head in range(max_head_index):
|
||||
if feeder_slot_result[cycle_set][head] != -1:
|
||||
pick_slot.append(feeder_slot_result[cycle_set][head] - interval_ratio * head)
|
||||
if component_result[cycle_set][head] == -1:
|
||||
if optimizer_result.feeder_slot_assign[cycle_set][head] != -1:
|
||||
pick_slot.append(optimizer_result.feeder_slot_assign[cycle_set][head] - interval_ratio * head)
|
||||
if optimizer_result.component_assign[cycle_set][head] == -1:
|
||||
continue
|
||||
nozzle = component_data.loc[component_result[cycle_set][head]]['nz']
|
||||
nozzle = component_data.loc[optimizer_result.component_assign[cycle_set][head]]['nz']
|
||||
if nozzle != nozzle_assigned[head]:
|
||||
if nozzle_assigned[head] != 'Empty':
|
||||
nozzle_put_counter += 1
|
||||
@ -557,9 +541,9 @@ def placement_info_evaluation(component_data, pcb_data, component_result, cycle_
|
||||
|
||||
# 固定相机检测
|
||||
# for head in range(max_head_index):
|
||||
# if component_result[cycle_set][head] == -1:
|
||||
# if optimizer_result.component_assign[cycle_set][head] == -1:
|
||||
# continue
|
||||
# camera = component_data.loc[component_result[cycle_set][head]]['camera']
|
||||
# camera = component_data.loc[optimizer_result.component_assign[cycle_set][head]]['camera']
|
||||
# if camera == '固定相机':
|
||||
# next_pos = [fix_camera_pos[0] - head * head_interval, fix_camera_pos[1]]
|
||||
# move_time = max(axis_moving_time(cur_pos[0] - next_pos[0], 0),
|
||||
@ -571,9 +555,9 @@ def placement_info_evaluation(component_data, pcb_data, component_result, cycle_
|
||||
# cur_pos = next_pos
|
||||
|
||||
# 贴装路径
|
||||
if placement_result and head_sequence:
|
||||
for head in head_sequence[cycle]:
|
||||
index = placement_result[cycle][head]
|
||||
if optimizer_result.placement_assign and optimizer_result.head_sequence:
|
||||
for head in optimizer_result.head_sequence[cycle]:
|
||||
index = optimizer_result.placement_assign[cycle][head]
|
||||
if index == -1:
|
||||
continue
|
||||
mount_pos.append([pcb_data.iloc[index]['x'] - head * head_interval + stopper_pos[0],
|
||||
@ -602,31 +586,11 @@ def placement_info_evaluation(component_data, pcb_data, component_result, cycle_
|
||||
info.nozzle_change_counter += nozzle_put_counter + nozzle_pick_counter
|
||||
|
||||
info.total_time = info.pickup_time + info.round_time + info.place_time + info.operation_time
|
||||
minutes, seconds = int(info.total_time // 60), int(info.total_time) % 60
|
||||
millisecond = int((info.total_time - minutes * 60 - seconds) * 60)
|
||||
info.cycle_counter = sum(cycle_result)
|
||||
info.cycle_counter = sum(optimizer_result.cycle_assign)
|
||||
if hinter:
|
||||
optimization_assign_result(component_data, pcb_data, component_result, cycle_result, feeder_slot_result,
|
||||
nozzle_hinter=False, component_hinter=False, feeder_hinter=False)
|
||||
|
||||
print('-Cycle counter: {}'.format(info.cycle_counter))
|
||||
print('-Nozzle change counter: {}'.format(info.nozzle_change_counter // 2))
|
||||
print('-Pick operation counter: {}'.format(info.pickup_counter))
|
||||
|
||||
print('-Expected mounting tour length: {} mm'.format(info.place_distance))
|
||||
print('-Expected picking tour length: {} mm'.format(info.pickup_distance))
|
||||
print('-Expected total tour length: {} mm'.format(info.total_distance))
|
||||
|
||||
print('-Expected total moving time: {} s with pick: {}, round: {}, place = {}'.format(
|
||||
info.pickup_time + info.round_time + info.place_time, info.pickup_time, info.round_time,
|
||||
info.place_time))
|
||||
print('-Expected total operation time: {} s'.format(info.operation_time))
|
||||
|
||||
if minutes > 0:
|
||||
print('-Mounting time estimation: {:d} min {} s {:2d} ms ({:.3f}s)'.format(minutes, seconds, millisecond,
|
||||
info.total_time))
|
||||
else:
|
||||
print('-Mounting time estimation: {} s {:2d} ms ({:.3f}s)'.format(seconds, millisecond, info.total_time))
|
||||
optimization_assign_result(component_data, pcb_data, optimizer_result, nozzle_hinter=False,
|
||||
component_hinter=False, feeder_hinter=False)
|
||||
info.print()
|
||||
|
||||
return info
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import math
|
||||
from functools import reduce
|
||||
|
||||
from base_optimizer.optimizer_common import *
|
||||
from base_optimizer.result_analysis import placement_info_evaluation
|
||||
@ -17,9 +18,8 @@ def feeder_priority_assignment(component_data, pcb_data, hinter=True):
|
||||
feeder_allocate(component_data, pcb_data, feeder_data, nozzle_pattern, figure=False)
|
||||
# 第3步:扫描供料器基座,确定元件拾取的先后顺序
|
||||
component_assign, cycle_assign, feeder_slot_assign = feeder_base_scan(component_data, pcb_data, feeder_data)
|
||||
|
||||
info = placement_info_evaluation(component_data, pcb_data, component_assign, cycle_assign,
|
||||
feeder_slot_assign, None, None, hinter=False)
|
||||
info = placement_info_evaluation(component_data, pcb_data, OptResult(component_assign, cycle_assign,
|
||||
feeder_slot_assign), hinter=False)
|
||||
|
||||
val = 0.356 * info.cycle_counter + 0.949 * info.nozzle_change_counter + 0.159 * info.pickup_counter \
|
||||
+ 0.002 * info.pickup_distance
|
||||
@ -66,7 +66,11 @@ def feeder_nozzle_pattern(component_data):
|
||||
assert max_cycle_nozzle is not None
|
||||
nozzle_heads[max_cycle_nozzle] += 1
|
||||
|
||||
num_permu = reduce(lambda x, y: x * y, range(1, len(nozzle_indices.keys()) + 1))
|
||||
num_permu = num_permu // 2 if len(nozzle_indices.keys()) > 3 else num_permu
|
||||
for permu in itertools.permutations(nozzle_indices.keys()):
|
||||
if (num_permu := num_permu - 1) < 0:
|
||||
break
|
||||
nozzle_pattern_list.append([])
|
||||
for idx in permu:
|
||||
for _ in range(nozzle_heads[nozzle_indices[idx]]):
|
||||
@ -93,8 +97,7 @@ def feeder_nozzle_pattern(component_data):
|
||||
idx += 1
|
||||
|
||||
nozzle_points.pop(min_points_nozzle)
|
||||
# nozzle_pattern_list = []
|
||||
# nozzle_pattern_list.append(['CN220', 'CN220', 'CN065', 'CN065', 'CN140', 'CN140'])
|
||||
|
||||
return nozzle_pattern_list
|
||||
|
||||
|
||||
@ -339,19 +342,20 @@ def feeder_allocate(component_data, pcb_data, feeder_data, nozzle_pattern, figur
|
||||
assign_part_stack.pop(0)
|
||||
assign_part_stack_points.pop(0)
|
||||
|
||||
nozzle_change_counter, average_slot = 0, []
|
||||
nozzle_change_counter = 0
|
||||
average_slot, average_head = [], []
|
||||
for head, feeder_ in enumerate(feeder_assign):
|
||||
if feeder_ < 0:
|
||||
continue
|
||||
average_slot.append((feeder_center_pos[feeder_] - slotf1_pos[0]) / slot_interval + 1)
|
||||
|
||||
average_head.append(head)
|
||||
if nozzle_pattern and component_data.loc[feeder_].nz != nozzle_pattern[head]:
|
||||
nozzle_change_counter += 1
|
||||
|
||||
if len(average_slot) == 0:
|
||||
continue
|
||||
|
||||
average_slot = sum(average_slot) / len(average_slot)
|
||||
average_slot = sum(average_slot) / len(average_slot) - sum(average_head) / len(average_head) * interval_ratio
|
||||
assign_value = 0
|
||||
feeder_assign_points_cpy = feeder_assign_points.copy()
|
||||
while True:
|
||||
@ -777,6 +781,8 @@ def feeder_base_scan(component_data, pcb_data, feeder_data):
|
||||
|
||||
if cycle_nozzle == nozzle_mode[nozzle_insert_cycle]:
|
||||
nozzle_mode_cycle[nozzle_insert_cycle] += 1
|
||||
elif nozzle_insert_cycle + 1 < len(nozzle_mode) and cycle_nozzle == nozzle_mode[nozzle_insert_cycle + 1]:
|
||||
nozzle_mode_cycle[nozzle_insert_cycle + 1] += 1
|
||||
else:
|
||||
nozzle_mode.insert(nozzle_insert_cycle + 1, cycle_nozzle)
|
||||
nozzle_mode_cycle.insert(nozzle_insert_cycle + 1, 1)
|
||||
|
@ -295,10 +295,7 @@ def gurobi_optimizer(pcb_data, component_data, feeder_data, reduction=True, part
|
||||
|
||||
mdl.addConstrs(
|
||||
2 * d[l, h] == quicksum(d_plus[j, h, l] for j in range(J)) + quicksum(d_minus[j, h, l] for j in range(J)) for l
|
||||
in range(L - 1) for h in range(max_head_index))
|
||||
|
||||
mdl.addConstrs(2 * d[L - 1, h] == quicksum(d_plus[j, h, L - 1] for j in range(J)) + quicksum(
|
||||
d_minus[j, h, L - 1] for j in range(J)) for h in range(max_head_index))
|
||||
in range(L) for h in range(max_head_index))
|
||||
|
||||
mdl.addConstrs(NC[h] == quicksum(d[l, h] for l in range(L)) for h in range(max_head_index))
|
||||
|
||||
|
Reference in New Issue
Block a user