framework/cg/freecad/Frames/pddl/path2pddl.py

343 lines
14 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.

import os
import FreeCAD as App
import FreeCADGui as Gui
import json
#1. Экспорт фрикадовских операций
printer = '/home/mark-voltov/GitProjects/framework/cg/freecad/Frames/pddl/Printer.FCStd'
endmill = '/home/mark-voltov/GitProjects/framework/cg/freecad/Frames/pddl/MillingMachine.FCStd'
part1 = '/home/mark-voltov/GitProjects/framework/cg/freecad/Frames/pddl/PartDesignExample.FCStd'
#потенциально, можно здесь полностью задавать все описание сцены
toolslist = [printer, endmill]
partlist = [part1]
part = App.open(part1)
tool = App.open(endmill)
def pathCheck(part):
checker = False
for obj in part.Objects:
if hasattr(obj, 'TypeId') and obj.TypeId == 'Path::FeaturePython':
if obj.Label == 'Job':
checker = True
return checker
operations_data = []
#нужно дополнить фиксированием принадлежности к телу
def is_entity_in_folder(part, entity, folder_name):
# Поиск папки с заданным именем
folder = None
for obj in part.Objects:
if obj.isDerivedFrom("App::DocumentObjectGroup") and obj.Label == folder_name:
folder = obj
break
# Если папка не найдена, вернуть False
if not folder:
return False
# Проверка наличия сущности внутри папки
return entity in folder.Group
#выделяем те сущности, которые являются операциями
def operationsInfoCollecting(part):
if pathCheck(part):
for obj in part.Objects:
if is_entity_in_folder(part, obj, 'Operations'):
operations_data.append({'Part_label': part.Label,
'Operation_name': obj.Label,
'Tool': obj.ToolController.Label,
'Duration': obj.CycleTime})
else:
print('Операции не были обнаружены')
return operations_data
# Словарь для группировки операций по станкам
machines_operations = {}
def toolOperationCollector(tool):
#соберем отдельно список pddl-операций из файла станка и будем работать с ним отдельно
tool_operations = []
for obj in tool.Objects:
if hasattr(obj, 'PDDL') and hasattr(obj, 'Type') and obj.Type == 'DurativeAction':
tool_operations.append({'Label': obj.Label,
'Conditions': obj.Conditions,
'Duration': 0,
'Effects': obj.Effects,
'Parameters': obj.Parameters,
'Type': obj.Type
})
return tool_operations
def operationGenerator(tool, operations_data):
tool_operations = toolOperationCollector(tool)
#отсеиваем все действия
pddl_actions = []
for part_operation in operations_data:
for tool_operation in tool_operations:
if tool_operation['Label'] == part_operation['Tool']:
pddl_actions.append({'Label': part_operation['Part_label'] + '_' + part_operation['Operation_name'] + '_' + tool_operation['Label'],
'Partname': part_operation['Part_label'],
'Conditions': tool_operation['Conditions'],
'Duration': part_operation['Duration'],
'Effects': tool_operation['Effects'],
'Parameters': tool_operation['Parameters'],
'Type': tool_operation['Type'],
'Tool': tool_operation['Label']
})
#здесь у нас появился список операций применительно к одному станку
#выполнив эту функцию для каждого станка, получим кучу операций для всего
return pddl_actions
#теперь нужно собрать все операции в один pddl
#нужно извлечь все действия и все не-действия, первое идет из tool_operations, второе - нужно отбирать из станков напрямую
def collectingNonActions(tool):
tool_non_operations = []
for obj in tool.Objects:
if hasattr(obj, 'PDDL') and hasattr(obj,'Type') and obj.Type != 'DurativeAction':
tool_non_operations.append(export_object_properties(obj))
return tool_non_operations
def export_object_properties(obj):
obj_dict = {}
# Получение всех свойств объекта
properties = obj.PropertiesList
for prop_name in properties:
prop = obj.getPropertyByName(prop_name)
obj_dict[prop_name] = prop
return obj_dict
#у нас есть словари с действиями и недействиями
#собираем их в pddl
def time_in_sec(time_str):
# Разделяем часы, минуты и секунды
hours, minutes, seconds = map(int, time_str.split(":"))
# Переводим в секунды
time_in_seconds = (hours * 3600) + (minutes * 60) + seconds
return time_in_seconds
#основной документ здесь - станок. Нужно поместить файл домена в папку с оборудованием
def domain_export(tool, pddl_entities_list):
file_path = endmill.rsplit("/", 1)[0] + '/domain.pddl'
filename = 'fabrication'
with open(file_path, 'w') as f:
f.write('(define (domain '+ filename +')\n \n')
f.write('(:requirements :strips :typing :fluents :durative-actions)\n')
# Типы обьектов
#выбираем словари, которые соответствуют типу types
types_list = [d for d in pddl_entities_list if d.get("Type") == 'Types']
f.write('(:types \n')
for obj in types_list:
for type in obj['Types']:
f.write(' ' + str(type) + ' \n')
f.write(')\n')
# предикаты
#выбираем словари, соответствующие предикатам
f.write(' (:predicates\n')
predicates_list = [d for d in pddl_entities_list if d.get("Type") == 'Predicate']
for obj in predicates_list:
f.write(' ('+ obj['Label'])
for params in obj['Parameters']:
f.write(' ' + params)
f.write(')\n')
f.write(' )\n')
# функции
f.write(' (:functions\n')
f.write(' )\n')
#действия:
#выбираем словари, соответствующие действиям
actions_list = [d for d in pddl_entities_list if d.get("Type") == 'Action']
for obj in actions_list:
f.write('(:action ' + obj['Label'] + '\n')
f.write(' :parameters (')
for params in obj['Parameters']:
f.write('' + params + ' ')
f.write(')\n')
f.write(' :condition (and \n')
for condition in obj['Conditions']:
f.write(' (' + condition + ') \n')
f.write(' )\n')
f.write(' :effect (and \n')
for effect in obj['Effects']:
f.write(' (' + effect + ') \n')
f.write(')\n')
f.write(' )\n')
# длительные действия:
#выбираем словари, соответствующие действиям
durative_actions_list = [d for d in pddl_entities_list if d.get("Type") == 'DurativeAction']
for obj in durative_actions_list:
f.write('(:durative-action ' + obj['Label'] + '\n')
f.write(' :parameters (')
for params in obj['Parameters']:
f.write(' ' + params )
f.write(' )\n')
f.write(' :duration ( = ?duration '+ str(time_in_sec(str(obj['Duration']))) +')\n')
f.write(' :condition (and \n')
for condition in obj['Conditions']:
f.write(' (' + condition + ') \n')
f.write(' )\n')
f.write(' :effect (and \n')
for effect in obj['Effects']:
f.write(' (' + effect + ') \n')
f.write(')\n')
f.write(' )\n')
f.write(' )\n')
tool_non_operations = []
operations_data = operationsInfoCollecting(part)
pddl_actions = operationGenerator(tool, operations_data)
pddl_non_actions = collectingNonActions(tool)
pddl_entities_list = pddl_non_actions + pddl_actions
domain_export(tool, pddl_entities_list)
def problem_export(partlist):
pass
def predicate_generator():
#как определять операции? по тегам, означающим действие и/или подготовку
#нужно выделить порядок
#как выделить порядок операций для детали?
#операции импортируются по порядку сверху вниз.
#можно создавать переходы по следующим признакам:
#операция создает условие "operation_name_done", следующая операция требует условия "operation_name_n-1_done"
#операция при начале делает условие "not operation_name_done"
#если операция требует изменения инструмента, то должна выполняться операция по замене инструмента
#
for n in range(pddl_actions):
if pddl_actions[n+1]['Tool'] == pddl_actions[n]['Tool']:
#замена инструмента не требуется
pddl_actions[n+1]['Conditions'].append(pddl_actions[n]["Label"] + '_done')
else:
#включается операция по замене инструмента
pddl_actions[n+1]['Conditions'].append( pddl_actions[n]["Label"] + '_done')
pddl_actions[n+1]['Conditions'].append('change_' + pddl_actions[n]['Tool'] + 'to' + pddl_actions[n+1]['Tool'] + '_done' ) #сюда нужно воткнуть операцию по замене
#нужно создать операцию, которая произведет эту замену.
aux_pddl_actions = []
def auxActionsGenerator(pddl_action_1, pddl_action_2):
aux_pddl_actions.append({{'Label': 'change_tool' + pddl_action_1['Tool'] + 'to' + pddl_action_2['Tool'],
'Partname': part_operation['Part_label'],
'Conditions': tool_operation['Conditions'],
'Duration': part_operation['Duration'],
'Effects': tool_operation['Effects'],
'Parameters': tool_operation['Parameters'],
'Type': tool_operation['Type'],
'Tool': tool_operation['Label']
}
})
#генерируется pddl-домен относительно нормально
#нужно увязать последовательность операций с пред и пост условиями, создавая предикаты автоматически
#problem можно создавать на основе операции сборки. Генератор последовательности сборки выдает основную информацию
#для сборки нужно, чтобы все операции подготовки детали были выполнены
# какие могут быть ситуации?
# ряд последовательных операций
# если станок один:
# если операции на одном виде инструментов:
# то операция1 имеет пред "операция0 готова"
# создает пред "операция1 готова"
# операция2 имеет пред "операция1 готова"
# создает пред "операция2 готова"
# если операция на разных видах инструментов:
# то операция1 имеет пред "операция0 готова"
# создает пред "операция1 готова"
# создает пред "смена инструмента не готова"
# операция смены имеет пред "операция1 готова"
# имеет пред "смена инструмента не готова"
# создает пред "смена инструмента готова"
# операция2 имеет пред "операция1 готова"
# имеет пред "смена инструмента готова"
# остальное аналогично