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

增加了整线批量测试
修改了现有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

@ -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