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

344 lines
14 KiB
Python
Raw Normal View History

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 готова"
# имеет пред "смена инструмента готова"
# остальное аналогично