Files
smt-optimizer/base_optimizer/result_analysis.py
hit-lu 37f4e5b02c 整线优化第一版论文定稿工程
增加了整线批量测试
修改了现有min-max模型路径
修改了遗传算法整体框架
估计器增加异常数据剔除
封装优化结果类
修改供料器扫描算法中重复吸嘴组的判定
2024-06-26 09:44:08 +08:00

600 lines
28 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from base_optimizer.optimizer_common import *
def convert_pcbdata_to_result(pcb_data, component_data):
opt_res = OptResult()
assigned_part = [-1 for _ in range(max_head_index)]
assigned_slot = [-1 for _ in range(max_head_index)]
assigned_point = [-1 for _ in range(max_head_index)]
assigned_sequence = []
point_num = len(pcb_data) # total mount points num
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 len(opt_res.component_assign) != 0 and opt_res.component_assign[-1] == assigned_part:
opt_res.cycle_assign[-1] += 1
else:
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拾取顺序相反
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)]
assigned_point = [-1 for _ in range(max_head_index)]
assigned_sequence = []
if point_cnt == point_num:
break
slot = pcb_data.loc[point_cnt, 'fdr'].split(' ')[0]
if slot == 'A':
slot, part = 0, pcb_data.loc[point_cnt].part
else:
slot, part = int(slot[1:]), pcb_data.loc[point_cnt].fdr.split(' ', 1)[1]
head = pcb_data.loc[point_cnt].hd - 1
part_index = component_data[component_data.part == part].index.tolist()[0]
assigned_part[head] = part_index
assigned_slot[head] = slot
assigned_point[head] = point_cnt
assigned_sequence.append(head)
return opt_res
# 绘制各周期从供料器周期拾取的元件位置
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(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 optimizer_result.feeder_slot_assign[cycle]:
if slot > 0:
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 optimizer_result.feeder_slot_assign[cycle]:
if slot > 0:
feeder_part[slot] += optimizer_result.cycle_assign[cycle]
plt.legend()
plt.show()
def placement_route_schematic(pcb_data, optimizer_result, cycle=-1):
plt.figure('cycle {}'.format(cycle + 1))
pos_x, pos_y = [], []
for i in range(len(pcb_data)):
pos_x.append(pcb_data.loc[i]['x'] + stopper_pos[0])
pos_y.append(pcb_data.loc[i]['y'] + stopper_pos[1])
# 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 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)
mount_pos.append([pos_x[index] - head * head_interval, pos_y[index]])
plt.plot(mount_pos[-1][0], mount_pos[-1][1], marker='^', color='red', markerfacecolor='white')
# plt.text(mount_pos[-1][0], mount_pos[-1][1], '%d' % index, size=8)
# 绘制贴装路径
for i in range(len(mount_pos) - 1):
plt.plot([mount_pos[i][0], mount_pos[i + 1][0]], [mount_pos[i][1], mount_pos[i + 1][1]], color='blue',
linewidth=1)
draw_x, draw_y = [], []
for c in range(cycle, len(optimizer_result.placement_assign)):
for h in range(max_head_index):
i = optimizer_result.placement_assign[c][h]
if i == -1:
continue
draw_x.append(pcb_data.loc[i]['x'] + stopper_pos[0])
draw_y.append(pcb_data.loc[i]['y'] + stopper_pos[1])
# plt.text(draw_x[-1], draw_y[-1] - 5, '%d' % i, ha='center', va='bottom', size=10)
plt.scatter(draw_x, draw_y, s=8)
# 绘制供料器位置布局
for slot in range(max_slot_index // 2):
plt.scatter(slotf1_pos[0] + slot_interval * slot, slotf1_pos[1], marker='x', s=12, color='green')
plt.text(slotf1_pos[0] + slot_interval * slot, slotf1_pos[1] - 50, slot + 1, ha='center', va='bottom', size=8)
feeder_part, feeder_counter = {}, {}
placement_cycle = 0
for cycle_, components in enumerate(optimizer_result.component_assign):
for head, component in enumerate(components):
if component == -1:
continue
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] += 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,
part + ': ' + str(feeder_counter[slot]), ha='center', size=7, rotation=90)
plt.plot([slotf1_pos[0] - slot_interval / 2, slotf1_pos[0] + slot_interval * (max_slot_index // 2 - 1 + 0.5)],
[slotf1_pos[1] + 10, slotf1_pos[1] + 10], color = 'black')
plt.plot([slotf1_pos[0] - slot_interval / 2, slotf1_pos[0] + slot_interval * (max_slot_index // 2 - 1 + 0.5)],
[slotf1_pos[1] - 40, slotf1_pos[1] - 40], color = 'black')
for counter in range(max_slot_index // 2 + 1):
pos = slotf1_pos[0] + (counter - 0.5) * slot_interval
plt.plot([pos, pos], [slotf1_pos[1] + 10, slotf1_pos[1] - 40], color='black', linewidth=1)
# 绘制拾取路径
pick_slot = []
cycle_group = 0
while sum(optimizer_result.cycle_assign[0: cycle_group + 1]) < cycle:
cycle_group += 1
for head, slot in enumerate(optimizer_result.feeder_slot_assign[cycle_group]):
if slot == -1:
continue
pick_slot.append(slot - head * interval_ratio)
pick_slot = list(set(pick_slot))
pick_slot = sorted(pick_slot)
next_cycle_group = 0
next_pick_slot = max_slot_index
while sum(optimizer_result.cycle_assign[0: next_cycle_group + 1]) < cycle + 1:
next_cycle_group += 1
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)
# 前往PCB贴装
plt.plot([mount_pos[-1][0], slotf1_pos[0] + slot_interval * (pick_slot[-1] - 1)], [mount_pos[-1][1], slotf1_pos[1]],
color='blue', linewidth=1)
# 基座移动路径
plt.plot([slotf1_pos[0] + slot_interval * (pick_slot[0] - 1), slotf1_pos[0] + slot_interval * (pick_slot[-1] - 1)],
[slotf1_pos[1], slotf1_pos[1]], color='blue', linewidth=1)
# 返回基座取料
plt.plot([mount_pos[0][0], slotf1_pos[0] + slot_interval * (next_pick_slot - 1)], [mount_pos[0][1], slotf1_pos[1]],
color='blue', linewidth=1)
plt.show()
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)
pos_x, pos_y = [], []
for i in range(len(pcb_data)):
pos_x.append(pcb_data.loc[i]['x'] + stopper_pos[0])
pos_y.append(pcb_data.loc[i]['y'] + stopper_pos[1])
# plt.text(pcb_data.loc[i]['x'], pcb_data.loc[i]['y'] + 0.1, '%d' % i, ha='center', va = 'bottom', size = 8)
with tqdm(total=100) as pbar:
pbar.set_description('save figure')
for cycle in range(len(optimizer_result.placement_assign)):
plt.figure(cycle)
mount_pos = []
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)
mount_pos.append([pos_x[index] - head * head_interval, pos_y[index]])
plt.plot(mount_pos[-1][0], mount_pos[-1][1], marker='^', color='red', markerfacecolor='white')
# 绘制贴装路径
for i in range(len(mount_pos) - 1):
plt.plot([mount_pos[i][0], mount_pos[i + 1][0]], [mount_pos[i][1], mount_pos[i + 1][1]], color='blue',
linewidth=1)
draw_x, draw_y = [], []
for c in range(cycle, len(optimizer_result.placement_assign)):
for h in range(max_head_index):
i = optimizer_result.placement_assign[c][h]
if i == -1:
continue
draw_x.append(pcb_data.loc[i]['x'] + stopper_pos[0])
draw_y.append(pcb_data.loc[i]['y'] + stopper_pos[1])
# plt.text(draw_x[-1], draw_y[-1] - 5, '%d' % i, ha='center', va='bottom', size=10)
plt.scatter(pos_x, pos_y, s=8)
# 绘制供料器位置布局
for slot in range(max_slot_index // 2):
plt.scatter(slotf1_pos[0] + slot_interval * slot, slotf1_pos[1], marker='x', s=12, color='green')
plt.text(slotf1_pos[0] + slot_interval * slot, slotf1_pos[1] - 50, slot + 1, ha='center', va='bottom', size=8)
feeder_part, feeder_counter = {}, {}
placement_cycle = 0
for cycle_, components in enumerate(optimizer_result.component_assign):
for head, component in enumerate(components):
if component == -1:
continue
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] += 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,
part + ': ' + str(feeder_counter[slot]), ha='center', size=7, rotation=90)
plt.plot(
[slotf1_pos[0] - slot_interval / 2, slotf1_pos[0] + slot_interval * (max_slot_index // 2 - 1 + 0.5)],
[slotf1_pos[1] + 10, slotf1_pos[1] + 10], color='black')
plt.plot(
[slotf1_pos[0] - slot_interval / 2, slotf1_pos[0] + slot_interval * (max_slot_index // 2 - 1 + 0.5)],
[slotf1_pos[1] - 40, slotf1_pos[1] - 40], color='black')
for counter in range(max_slot_index // 2 + 1):
pos = slotf1_pos[0] + (counter - 0.5) * slot_interval
plt.plot([pos, pos], [slotf1_pos[1] + 10, slotf1_pos[1] - 40], color='black', linewidth=1)
# 绘制拾取路径
pick_slot = []
cycle_group = 0
while sum(optimizer_result.cycle_assign[0: cycle_group + 1]) < cycle:
cycle_group += 1
for head, slot in enumerate(optimizer_result.feeder_slot_assign[cycle_group]):
if slot == -1:
continue
pick_slot.append(slot - head * interval_ratio)
pick_slot = list(set(pick_slot))
pick_slot = sorted(pick_slot)
plt.plot([mount_pos[0][0], slotf1_pos[0] + slot_interval * (pick_slot[0] - 1)],
[mount_pos[0][1], slotf1_pos[1]], color='blue', linewidth=1)
plt.plot([mount_pos[-1][0], slotf1_pos[0] + slot_interval * (pick_slot[-1] - 1)],
[mount_pos[-1][1], slotf1_pos[1]], color='blue', linewidth=1)
plt.plot([slotf1_pos[0] + slot_interval * (pick_slot[0] - 1),
slotf1_pos[0] + slot_interval * (pick_slot[-1] - 1)], [slotf1_pos[1], slotf1_pos[1]],
color='blue', linewidth=1)
plt.savefig(path + '/cycle_{}'.format(cycle + 1))
plt.close(cycle)
pbar.update(100 / len(optimizer_result.placement_assign))
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['CN020'] = list(range(15, 26, 2))
anc_list['CN140'] = list(range(26, 37, 2))
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(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 optimizer_result.head_sequence[cycle]:
index_ = optimizer_result.placement_assign[cycle][head]
if index_ == -1:
continue
head_indexes[head] = index_
placement_index.append(index_)
output_data.loc[index_, 'cs'] = 1 if cycle_start else 0
output_data.loc[index_, 'cy'] = cycle + 1
output_data.loc[index_, 'hd'] = head + 1
cycle_start = False
# 供料器信息
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)
output_data.loc[index_, 'fdr'] = fdr + ' ' + component_data.loc[
optimizer_result.component_assign[cycle_set][head], 'part']
# ANC信息
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]
if nozzle == '':
continue
if nozzle != assigned_nozzle[head]:
# 已分配有吸嘴,卸载原吸嘴
if assigned_nozzle[head] != '':
anc_list[assigned_nozzle[head]].append(assigned_anc_hole[head])
anc_list[assigned_nozzle[head]] = sorted(anc_list[assigned_nozzle[head]])
# 安装新的吸嘴
assigned_nozzle[head] = nozzle
try:
assigned_anc_hole[head] = anc_list[nozzle][0]
except IndexError:
info = 'the number of nozzle for [' + nozzle + '] exceeds the quantity limit'
raise IndexError(info)
anc_list[nozzle].pop(0)
output_data.loc[head_indexes[head], 'nz'] = '1-' + str(assigned_anc_hole[head]) + ' ' + nozzle
output_data = output_data.reindex(placement_index)
output_data = output_data.reset_index(drop=True)
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)
output_data.to_excel(file_path + '.xlsx', sheet_name='tb1', float_format='%.3f', na_rep='')
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(optimizer_result.component_assign):
nozzle_assign_row = len(nozzle_assign)
nozzle_assign.loc[nozzle_assign_row, 'cycle'] = optimizer_result.cycle_assign[cycle]
for head in range(max_head_index):
index = optimizer_result.component_assign[cycle][head]
if index == -1:
nozzle_assign.loc[nozzle_assign_row, 'H{}'.format(head + 1)] = ''
else:
nozzle = component_data.loc[index]['nz']
nozzle_assign.loc[nozzle_assign_row, 'H{}'.format(head + 1)] = nozzle
for head in range(max_head_index):
if nozzle_assign_row == 0 or nozzle_assign.loc[nozzle_assign_row - 1, 'H{}'.format(head + 1)] != \
nozzle_assign.loc[nozzle_assign_row, 'H{}'.format(head + 1)]:
break
else:
nozzle_assign.loc[nozzle_assign_row - 1, 'cycle'] += nozzle_assign.loc[nozzle_assign_row, 'cycle']
nozzle_assign.drop([len(nozzle_assign) - 1], inplace=True)
print(nozzle_assign)
print('')
if component_hinter:
columns = ['H{}'.format(i + 1) for i in range(max_head_index)] + ['cycle']
component_assign = pd.DataFrame(columns=columns)
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 = optimizer_result.component_assign[cycle][head]
if index == -1:
component_assign.loc[cycle, 'H{}'.format(head + 1)] = ''
else:
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)
print('')
if feeder_hinter:
columns = ['H{}'.format(i + 1) for i in range(max_head_index)] + ['cycle']
feedr_assign = pd.DataFrame(columns=columns)
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 = optimizer_result.feeder_slot_assign[cycle][head]
if slot == -1:
feedr_assign.loc[cycle, 'H{}'.format(head + 1)] = 'A'
else:
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, optimizer_result, hinter=False):
# === 优化结果参数 ===
info = OptInfo()
# === 校验 ===
info.total_points = 0
for cycle, components in enumerate(optimizer_result.component_assign):
for head, component in enumerate(components):
if component == -1:
continue
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 optimizer_result.placement_assign:
total_points = info.total_points
for placements in optimizer_result.placement_assign:
for placement in placements:
if placement == -1:
continue
total_points -= 1
if total_points != 0:
warnings.warn(
'the optimization result of component assignment result and placement result are not consistent. ',
UserWarning)
return OptInfo()
feeder_arrangement = defaultdict(set)
for cycle, feeder_slots in enumerate(optimizer_result.feeder_slot_assign):
for head, slot in enumerate(feeder_slots):
if slot == -1:
continue
feeder_arrangement[optimizer_result.component_assign[cycle][head]].add(slot)
info.total_components = len(feeder_arrangement.keys())
for part, data in component_data.iterrows():
if part in feeder_arrangement.keys() and data.fdn < len(feeder_arrangement[part]):
info = 'the number of arranged feeder of [' + data['part'] + '] exceeds the quantity limit'
warnings.warn(info, UserWarning)
return 0.
cur_pos, next_pos = anc_marker_pos, [0, 0] # 贴装头当前位置
# 初始化首个周期的吸嘴装配信息
nozzle_assigned = ['Empty' for _ in range(max_head_index)]
for head in range(max_head_index):
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(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 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[optimizer_result.component_assign[cycle_set][head]]['nz']
if nozzle != nozzle_assigned[head]:
if nozzle_assigned[head] != 'Empty':
nozzle_put_counter += 1
nozzle_pick_counter += 1
nozzle_assigned[head] = nozzle
# ANC处进行吸嘴更换
if nozzle_pick_counter + nozzle_put_counter > 0:
next_pos = anc_marker_pos
move_time = max(axis_moving_time(cur_pos[0] - next_pos[0], 0),
axis_moving_time(cur_pos[1] - next_pos[1], 1))
info.round_time += move_time
info.anc_round_counter += 1
info.total_distance += max(abs(cur_pos[0] - next_pos[0]), abs(cur_pos[1] - next_pos[1]))
cur_pos = next_pos
pick_slot = list(set(pick_slot))
pick_slot = sorted(pick_slot, reverse=True)
# 拾取路径(自右向左)
for idx, slot in enumerate(pick_slot):
if slot < max_slot_index // 2:
next_pos = [slotf1_pos[0] + slot_interval * (slot - 1), slotf1_pos[1]]
else:
next_pos = [slotr1_pos[0] - slot_interval * (max_slot_index - slot - 1), slotr1_pos[1]]
info.operation_time += t_pick
info.pickup_counter += 1
move_time = max(axis_moving_time(cur_pos[0] - next_pos[0], 0),
axis_moving_time(cur_pos[1] - next_pos[1], 1))
if idx == 0:
info.round_time += move_time
else:
info.pickup_time += move_time
info.total_distance += max(abs(cur_pos[0] - next_pos[0]), abs(cur_pos[1] - next_pos[1]))
if slot != pick_slot[0]:
info.pickup_distance += max(abs(cur_pos[0] - next_pos[0]), abs(cur_pos[1] - next_pos[1]))
cur_pos = next_pos
# 固定相机检测
# for head in range(max_head_index):
# if optimizer_result.component_assign[cycle_set][head] == -1:
# continue
# 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),
# axis_moving_time(cur_pos[1] - next_pos[1], 1))
# info.round_time += move_time
#
# info.total_distance += max(abs(cur_pos[0] - next_pos[0]), abs(cur_pos[1] - next_pos[1]))
# info.operation_time += t_fix_camera_check
# cur_pos = next_pos
# 贴装路径
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],
pcb_data.iloc[index]['y'] + stopper_pos[1]])
mount_angle.append(pcb_data.iloc[index]['r'])
# 单独计算贴装路径
for cntPoints in range(len(mount_pos) - 1):
info.place_distance += max(abs(mount_pos[cntPoints][0] - mount_pos[cntPoints + 1][0]),
abs(mount_pos[cntPoints][1] - mount_pos[cntPoints + 1][1]))
# 考虑R轴预旋转补偿同轴角度转动带来的额外贴装用时
info.operation_time += head_rotary_time(mount_angle[0]) # 补偿角度转动带来的额外贴装用时
info.operation_time += t_nozzle_put * nozzle_put_counter + t_nozzle_pick * nozzle_pick_counter
for idx, pos in enumerate(mount_pos):
info.operation_time += t_place
move_time = max(axis_moving_time(cur_pos[0] - pos[0], 0), axis_moving_time(cur_pos[1] - pos[1], 1))
if idx == 0:
info.round_time += move_time
else:
info.place_time += move_time
info.total_distance += max(abs(cur_pos[0] - pos[0]), abs(cur_pos[1] - pos[1]))
cur_pos = pos
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
info.cycle_counter = sum(optimizer_result.cycle_assign)
if hinter:
optimization_assign_result(component_data, pcb_data, optimizer_result, nozzle_hinter=False,
component_hinter=False, feeder_hinter=False)
info.print()
return info