2023-11-18 17:44:05 +08:00
|
|
|
|
import copy
|
2023-11-08 17:37:49 +08:00
|
|
|
|
import io
|
|
|
|
|
import contextlib
|
2023-11-13 14:53:00 +08:00
|
|
|
|
import os
|
|
|
|
|
import importlib.util
|
2023-10-25 10:34:24 +08:00
|
|
|
|
|
2023-11-09 16:07:02 +08:00
|
|
|
|
from robowaiter.utils.bt.load import load_bt_from_ptml,find_node_by_name,print_tree_from_root
|
|
|
|
|
from robowaiter.utils.bt.visitor import StatusVisitor
|
|
|
|
|
|
|
|
|
|
from robowaiter.behavior_tree.obtea.OptimalBTExpansionAlgorithm import Action # 调用最优行为树扩展算法
|
2023-11-09 08:47:57 +08:00
|
|
|
|
from robowaiter.behavior_tree.obtea.opt_bt_exp_main import BTOptExpInterface
|
|
|
|
|
|
|
|
|
|
from robowaiter.behavior_lib.act.DelSubTree import DelSubTree
|
|
|
|
|
from robowaiter.behavior_lib._base.Sequence import Sequence
|
2023-11-13 14:53:00 +08:00
|
|
|
|
from robowaiter.utils.bt.load import load_behavior_tree_lib
|
2024-01-04 22:51:33 +08:00
|
|
|
|
from robowaiter.behavior_lib._base.Behavior import Bahavior
|
2023-11-09 08:47:57 +08:00
|
|
|
|
|
2023-11-15 09:40:57 +08:00
|
|
|
|
from robowaiter.utils import get_root_path
|
|
|
|
|
root_path = get_root_path()
|
|
|
|
|
ptml_path = os.path.join(root_path, 'robowaiter/robot/Default.ptml')
|
|
|
|
|
behavior_lib_path = os.path.join(root_path, 'robowaiter/behavior_lib')
|
|
|
|
|
|
2023-12-12 20:13:13 +08:00
|
|
|
|
from robowaiter.utils.bt.draw import render_dot_tree
|
2023-11-15 09:40:57 +08:00
|
|
|
|
|
2023-10-25 10:34:24 +08:00
|
|
|
|
class Robot(object):
|
|
|
|
|
scene = None
|
2023-10-25 22:12:15 +08:00
|
|
|
|
response_frequency = 1
|
|
|
|
|
|
2023-11-15 09:40:57 +08:00
|
|
|
|
def __init__(self,ptml_path=ptml_path,behavior_lib_path=behavior_lib_path):
|
2023-10-25 10:34:24 +08:00
|
|
|
|
self.ptml_path = ptml_path
|
|
|
|
|
self.behavior_lib_path = behavior_lib_path
|
|
|
|
|
|
2023-10-25 22:12:15 +08:00
|
|
|
|
self.next_response_time = self.response_frequency
|
|
|
|
|
self.step_num = 0
|
2023-11-08 17:37:49 +08:00
|
|
|
|
self.last_tick_output = ""
|
2023-11-09 08:47:57 +08:00
|
|
|
|
self.action_list = None
|
2023-10-25 22:12:15 +08:00
|
|
|
|
|
2023-11-09 16:07:02 +08:00
|
|
|
|
|
2023-11-19 16:35:37 +08:00
|
|
|
|
def set_scene(self,scene=None):
|
2023-10-25 10:34:24 +08:00
|
|
|
|
self.scene = scene
|
|
|
|
|
|
2023-11-17 12:53:16 +08:00
|
|
|
|
|
2023-10-25 10:34:24 +08:00
|
|
|
|
def load_BT(self):
|
|
|
|
|
self.bt = load_bt_from_ptml(self.scene, self.ptml_path,self.behavior_lib_path)
|
2023-11-14 20:08:54 +08:00
|
|
|
|
sub_task_place_holder = find_node_by_name(self.bt.root,"SubTaskPlaceHolder()")
|
2023-11-08 17:37:49 +08:00
|
|
|
|
if sub_task_place_holder:
|
|
|
|
|
sub_task_seq = sub_task_place_holder.parent
|
|
|
|
|
sub_task_seq.children.pop()
|
|
|
|
|
self.scene.sub_task_seq = sub_task_seq
|
2023-11-09 16:07:02 +08:00
|
|
|
|
|
|
|
|
|
self.bt_visitor = StatusVisitor()
|
|
|
|
|
self.bt.visitors.append(self.bt_visitor)
|
|
|
|
|
|
2023-11-09 08:47:57 +08:00
|
|
|
|
|
|
|
|
|
def expand_sub_task_tree(self,goal):
|
|
|
|
|
if self.action_list is None:
|
2023-11-18 14:51:17 +08:00
|
|
|
|
print("\n\n--------------------")
|
2023-11-14 20:08:54 +08:00
|
|
|
|
print(f"首次运行行为树扩展算法")
|
|
|
|
|
self.action_list = self.collect_action_nodes()
|
|
|
|
|
print(f"共收集到{len(self.action_list)}个实例化动作:")
|
|
|
|
|
# for a in self.action_list:
|
|
|
|
|
# if "Turn" in a.name:
|
|
|
|
|
# print(a.name)
|
2023-11-13 15:05:21 +08:00
|
|
|
|
print("--------------------\n")
|
|
|
|
|
|
2023-11-16 21:37:18 +08:00
|
|
|
|
# 如果目标是下班,规划的时候就直接快捷导入?
|
2024-01-04 22:51:33 +08:00
|
|
|
|
# end_goal = {"Is(Floor,Clean)","Is(Table1,Clean)","Is(Chairs,Clean)","Is(AC,Off)","Is(HallLight,Off)","Is(TubeLight,Off)","Is(Curtain,Off)"}
|
|
|
|
|
# if goal & end_goal == goal:
|
|
|
|
|
# tmp_list = copy.deepcopy(self.action_list)
|
|
|
|
|
# self.action_list=[]
|
|
|
|
|
# self.action_list = [action for action in tmp_list if "Turn" in action.name or "Clean" in action.name]
|
|
|
|
|
|
|
|
|
|
# 这里对action做一个挑选,就是物品的挑选,只对环境有的物品+目标的物品进行挑选
|
|
|
|
|
##############################
|
|
|
|
|
# all_obj_ls = {'Coffee', 'Water', 'Dessert', 'Softdrink', 'BottledDrink', 'Yogurt', 'ADMilk', 'MilkDrink', 'Milk','VacuumCup',
|
|
|
|
|
# 'Chips', 'NFCJuice', 'Bernachon', 'SpringWater'}
|
|
|
|
|
# all_place_ls = {'Bar', 'Bar2', 'WaterTable', 'CoffeeTable', 'Table1', 'Table2', 'Table3','BrightTable6'}
|
|
|
|
|
all_obj_ls = Bahavior.all_object
|
|
|
|
|
all_place_ls = Bahavior.tables_for_placement
|
|
|
|
|
obj_need = set()
|
|
|
|
|
place_need=set()
|
|
|
|
|
for state_curr in self.scene.state["condition_set"]:
|
|
|
|
|
if 'Holding' in state_curr:
|
|
|
|
|
if 'Holding(Nothing)' in state_curr:
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
for obj in all_obj_ls:
|
|
|
|
|
if obj in state_curr:
|
|
|
|
|
obj_need.add(obj)
|
|
|
|
|
for g in goal:
|
|
|
|
|
obj_need_ls = [s1 for s1 in all_obj_ls if any(s1 in s2 for s2 in g)]
|
|
|
|
|
obj_need.update(obj_need_ls)
|
|
|
|
|
place_need_ls = [s1 for s1 in all_place_ls if any("On" in s2 and s1 in s2 for s2 in g)]
|
|
|
|
|
place_need.update(place_need_ls)
|
|
|
|
|
# for state in g:
|
|
|
|
|
# for obj in all_obj_ls:
|
|
|
|
|
# if obj in state:
|
|
|
|
|
# obj_need.add(obj)
|
|
|
|
|
obj_not_need = all_obj_ls-obj_need
|
|
|
|
|
place_not_need = all_place_ls-place_need
|
|
|
|
|
action_need_ls_tmp = [action for action in self.action_list if not any(('PutDown' in action.name and s in action.name ) for s in obj_not_need)]
|
|
|
|
|
action_need_ls = [action for action in action_need_ls_tmp if not any(('PutDown' in action.name and s in action.name) for s in place_not_need)]
|
|
|
|
|
##############################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
algo = BTOptExpInterface(action_need_ls, self.scene)
|
|
|
|
|
# algo = BTOptExpInterface(self.action_list,self.scene)
|
2023-11-09 08:47:57 +08:00
|
|
|
|
|
|
|
|
|
ptml_string = algo.process(goal)
|
|
|
|
|
|
|
|
|
|
file_name = "sub_task"
|
|
|
|
|
file_path = f'./{file_name}.ptml'
|
|
|
|
|
with open(file_path, 'w') as file:
|
|
|
|
|
file.write(ptml_string)
|
|
|
|
|
|
|
|
|
|
sub_task_bt = load_bt_from_ptml(self.scene, file_path,self.behavior_lib_path)
|
2023-12-12 20:13:13 +08:00
|
|
|
|
render_dot_tree(sub_task_bt.root, target_directory=self.scene.output_path, name="expanded_bt", png_only=False)
|
2023-11-09 08:47:57 +08:00
|
|
|
|
|
|
|
|
|
# 加入删除子树的节点
|
|
|
|
|
seq = Sequence(name="Sequence", memory=False)
|
2023-11-09 16:07:02 +08:00
|
|
|
|
seq.add_child(sub_task_bt.root)
|
2023-11-09 08:47:57 +08:00
|
|
|
|
del_sub_tree = DelSubTree()
|
|
|
|
|
del_sub_tree.set_scene(self.scene)
|
2023-11-09 16:07:02 +08:00
|
|
|
|
seq.add_child(del_sub_tree)
|
2023-11-09 08:47:57 +08:00
|
|
|
|
|
2023-11-14 17:31:13 +08:00
|
|
|
|
if self.scene.sub_task_seq:
|
|
|
|
|
self.scene.sub_task_seq.add_child(seq)
|
|
|
|
|
else:
|
|
|
|
|
print('Warning: have none sub task sequence')
|
|
|
|
|
self.scene.sub_task_seq = seq
|
2023-11-20 11:12:36 +08:00
|
|
|
|
# print("当前行为树为:")
|
|
|
|
|
# print_tree_from_root(self.bt.root)
|
|
|
|
|
print("行为树扩展完成!")
|
2023-11-08 16:20:02 +08:00
|
|
|
|
|
2023-11-22 17:58:18 +08:00
|
|
|
|
self.scene.draw_current_bt()
|
|
|
|
|
|
2023-11-13 14:53:00 +08:00
|
|
|
|
# 获取所有action的pre,add,del列表
|
2023-11-09 08:47:57 +08:00
|
|
|
|
def collect_action_nodes(self):
|
2023-11-13 14:53:00 +08:00
|
|
|
|
action_list = []
|
|
|
|
|
behavior_dict = load_behavior_tree_lib()
|
|
|
|
|
for cls in behavior_dict["act"].values():
|
|
|
|
|
if cls.can_be_expanded:
|
2023-11-14 20:08:54 +08:00
|
|
|
|
print(f"可扩展动作:{cls.__name__}, 存在{len(cls.valid_args)}个有效论域组合")
|
2023-11-13 14:53:00 +08:00
|
|
|
|
if cls.num_args == 0:
|
2023-11-13 15:05:21 +08:00
|
|
|
|
action_list.append(Action(name=cls.get_ins_name(),**cls.get_info()))
|
2023-11-13 14:53:00 +08:00
|
|
|
|
if cls.num_args == 1:
|
|
|
|
|
for arg in cls.valid_args:
|
2023-11-13 15:05:21 +08:00
|
|
|
|
action_list.append(Action(name=cls.get_ins_name(arg), **cls.get_info(arg)))
|
2023-11-13 14:53:00 +08:00
|
|
|
|
if cls.num_args > 1:
|
|
|
|
|
for args in cls.valid_args:
|
2023-11-13 15:05:21 +08:00
|
|
|
|
action_list.append(Action(name=cls.get_ins_name(*args),**cls.get_info(*args)))
|
2023-11-13 14:53:00 +08:00
|
|
|
|
|
2023-11-14 20:08:54 +08:00
|
|
|
|
# print(action_list)
|
2023-11-13 14:53:00 +08:00
|
|
|
|
# action_list = [
|
|
|
|
|
# Action(name='MakeCoffee', pre={'At(Robot,CoffeeMachine)'},
|
|
|
|
|
# add={'At(Coffee,Bar)'}, del_set=set(), cost=1),
|
|
|
|
|
# Action(name='MoveTo(Table)', pre={'At(Robot,Bar)'},
|
|
|
|
|
# add={'At(Robot,Table)'}, del_set=set(), cost=1),
|
|
|
|
|
# Action(name='ExploreEnv()', pre=set(),
|
|
|
|
|
# add={'EnvExplored()'}, del_set=set(), cost=1),
|
|
|
|
|
# ]
|
2023-11-09 08:47:57 +08:00
|
|
|
|
return action_list
|
2023-10-25 10:34:24 +08:00
|
|
|
|
|
2023-10-25 22:12:15 +08:00
|
|
|
|
def step(self):
|
|
|
|
|
if self.scene.time > self.next_response_time:
|
|
|
|
|
self.next_response_time += self.response_frequency
|
|
|
|
|
self.step_num += 1
|
|
|
|
|
|
2023-11-09 16:07:02 +08:00
|
|
|
|
self.bt.tick()
|
|
|
|
|
bt_output = self.bt_visitor.output_str
|
2023-11-08 17:37:49 +08:00
|
|
|
|
|
2023-11-09 16:07:02 +08:00
|
|
|
|
if bt_output != self.last_tick_output:
|
2023-11-08 17:37:49 +08:00
|
|
|
|
print(f"==== time:{self.scene.time:f}s ======")
|
|
|
|
|
|
2023-11-09 16:07:02 +08:00
|
|
|
|
print(bt_output)
|
2023-11-08 17:37:49 +08:00
|
|
|
|
|
|
|
|
|
print("\n")
|
2023-11-09 16:07:02 +08:00
|
|
|
|
self.last_tick_output = bt_output
|
2023-11-19 10:48:45 +08:00
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
return False
|
2023-10-25 22:12:15 +08:00
|
|
|
|
|
2023-10-25 10:34:24 +08:00
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
pass
|