2023-08-25 15:26:53 +03:00
import os
import FreeCAD as App
import FreeCADGui as Gui
import json
#1. Экспорт фрикадовских операций
2023-08-29 13:13:37 +03:00
2023-08-25 15:26:53 +03:00
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
2023-08-29 13:13:37 +03:00
2023-08-25 15:26:53 +03:00
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 )
2023-08-29 13:13:37 +03:00
2023-08-25 15:26:53 +03:00
#отсеиваем все действия
pddl_actions = [ ]
for part_operation in operations_data :
for tool_operation in tool_operations :
if tool_operation [ ' Label ' ] == part_operation [ ' Tool ' ] :
2023-08-29 13:13:37 +03:00
pddl_actions . append ( { ' Label ' : part_operation [ ' Part_label ' ] + ' _ ' + part_operation [ ' Operation_name ' ] + ' _ ' + tool_operation [ ' Label ' ] ,
2023-08-25 15:26:53 +03:00
' Partname ' : part_operation [ ' Part_label ' ] ,
' Conditions ' : tool_operation [ ' Conditions ' ] ,
' Duration ' : part_operation [ ' Duration ' ] ,
' Effects ' : tool_operation [ ' Effects ' ] ,
' Parameters ' : tool_operation [ ' Parameters ' ] ,
2023-08-29 13:13:37 +03:00
' Type ' : tool_operation [ ' Type ' ] ,
' Tool ' : tool_operation [ ' Label ' ]
} )
2023-08-25 15:26:53 +03:00
#здесь у нас появился список операций применительно к одному станку
#выполнив эту функцию для каждого станка, получим кучу операций для всего
return pddl_actions
2023-08-29 13:13:37 +03:00
2023-08-25 15:26:53 +03:00
#теперь нужно собрать все операции в один 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
#основной документ здесь - станок. Нужно поместить файл домена в папку с оборудованием
2023-08-29 13:13:37 +03:00
def domain_export ( tool , pddl_entities_list ) :
2023-08-25 15:26:53 +03:00
file_path = endmill . rsplit ( " / " , 1 ) [ 0 ] + ' /domain.pddl '
2023-08-29 13:13:37 +03:00
2023-08-25 15:26:53 +03:00
filename = ' fabrication '
2023-08-29 13:13:37 +03:00
2023-08-25 15:26:53 +03:00
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 ' ]
2023-08-29 13:13:37 +03:00
2023-08-25 15:26:53 +03:00
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 ' ]
2023-08-29 13:13:37 +03:00
2023-08-25 15:26:53 +03:00
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 ' ]
2023-08-29 13:13:37 +03:00
2023-08-25 15:26:53 +03:00
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 ' )
2023-08-29 13:13:37 +03:00
2023-08-25 15:26:53 +03:00
f . write ( ' ) \n ' )
f . write ( ' ) \n ' )
# длительные действия:
#выбираем словари, соответствующие действиям
durative_actions_list = [ d for d in pddl_entities_list if d . get ( " Type " ) == ' DurativeAction ' ]
2023-08-29 13:13:37 +03:00
2023-08-25 15:26:53 +03:00
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 ' )
2023-08-29 13:13:37 +03:00
2023-08-25 15:26:53 +03:00
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 = [ ]
2023-08-29 13:13:37 +03:00
2023-08-25 15:26:53 +03:00
operations_data = operationsInfoCollecting ( part )
pddl_actions = operationGenerator ( tool , operations_data )
2023-08-29 13:13:37 +03:00
pddl_non_actions = collectingNonActions ( tool )
pddl_entities_list = pddl_non_actions + pddl_actions
domain_export ( tool , pddl_entities_list )
2023-08-25 15:26:53 +03:00
2023-08-29 13:13:37 +03:00
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 = [ ]
2023-08-25 15:26:53 +03:00
2023-08-29 13:13:37 +03:00
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 готова"
# имеет пред "смена инструмента готова"
# остальное аналогично