diff --git a/robowaiter/algos/navigator/__init__.py b/robowaiter/algos/navigator/__init__.py index 2802065..e69de29 100644 --- a/robowaiter/algos/navigator/__init__.py +++ b/robowaiter/algos/navigator/__init__.py @@ -1,3 +0,0 @@ -from . import navigate -from . import dstar_lite - diff --git a/robowaiter/algos/navigator/navigate.py b/robowaiter/algos/navigator/navigate.py index a9d37b4..b4b2c71 100644 --- a/robowaiter/algos/navigator/navigate.py +++ b/robowaiter/algos/navigator/navigate.py @@ -7,7 +7,6 @@ import pickle import matplotlib.pyplot as plt import numpy as np -from robowaiter.scene import scene from robowaiter.algos.navigator.dstar_lite import DStarLite, euclidean_distance @@ -94,6 +93,7 @@ class Navigator: if __name__ == '__main__': # 根据map计算并保存cost_map + from robowaiter.scene import scene file_name = 'map_4.pkl' if os.path.exists(file_name): diff --git a/robowaiter/behavior_lib/_base/Behavior.py b/robowaiter/behavior_lib/_base/Behavior.py index f066e77..710df9e 100644 --- a/robowaiter/behavior_lib/_base/Behavior.py +++ b/robowaiter/behavior_lib/_base/Behavior.py @@ -81,9 +81,10 @@ class Bahavior(ptree.behaviour.Behaviour): # let behavior node interact with the scene - def set_scene(self, scene): - self.scene = scene - self.robot = scene.robot + def set_scene(self, scene=None): + if scene: + self.scene = scene + self.robot = scene.robot def setup(self, **kwargs: Any) -> None: return super().setup(**kwargs) diff --git a/robowaiter/behavior_lib/_base/Selector.py b/robowaiter/behavior_lib/_base/Selector.py index 1c84639..1b61ed0 100644 --- a/robowaiter/behavior_lib/_base/Selector.py +++ b/robowaiter/behavior_lib/_base/Selector.py @@ -3,6 +3,7 @@ from typing import Any class Selector(ptree.composites.Selector): print_name = "Selector" + ins_name = "Selector" type = "Selector" def __init__(self,*args,**kwargs): diff --git a/robowaiter/behavior_lib/_base/Sequence.py b/robowaiter/behavior_lib/_base/Sequence.py index 702a0d9..bd1b75c 100644 --- a/robowaiter/behavior_lib/_base/Sequence.py +++ b/robowaiter/behavior_lib/_base/Sequence.py @@ -3,6 +3,7 @@ from typing import Any class Sequence(ptree.composites.Sequence): print_name = "Sequence" + ins_name = "Selector" type = "Sequence" def __init__(self,*args,**kwargs): diff --git a/robowaiter/behavior_lib/act/DealChat.py b/robowaiter/behavior_lib/act/DealChat.py index d5a3e27..4907517 100644 --- a/robowaiter/behavior_lib/act/DealChat.py +++ b/robowaiter/behavior_lib/act/DealChat.py @@ -1,7 +1,13 @@ import py_trees as ptree from robowaiter.behavior_lib._base.Act import Act -from robowaiter.llm_client.multi_rounds import ask_llm,new_history +from robowaiter.llm_client.multi_rounds import ask_llm, new_history +import random + + +# import spacy +# nlp = spacy.load('en_core_web_lg') + class DealChat(Act): def __init__(self): @@ -10,13 +16,14 @@ class DealChat(Act): self.function_success = False self.func_map = { "create_sub_task": self.create_sub_task, - "get_object_info": self.get_object_info, - "stop_serve": self.stop_serve + "stop_serve": self.stop_serve, + # "get_object_info": self.get_object_info, + # "find_location": self.find_location } def _update(self) -> ptree.common.Status: # if self.scene.status? - name,sentence = self.scene.state['chat_list'].pop(0) + name, sentence = self.scene.state['chat_list'].pop(0) if name == "Goal": self.create_sub_task(goal=sentence) @@ -39,14 +46,14 @@ class DealChat(Act): return ptree.common.Status.RUNNING - def create_sub_task(self,**args): + def create_sub_task(self, **args): try: goal = args['goal'] w = goal.split(")") goal_set = set() goal_set.add(w[0] + ")") - if len(w)>1: + if len(w) > 1: for x in w[1:]: if x != "": goal_set.add(x[1:] + ")") @@ -56,25 +63,73 @@ class DealChat(Act): self.scene.robot.expand_sub_task_tree(goal_set) - - def get_object_info(self,**args): - try: - obj = args['obj'] - - self.function_success = True - except: - obj = None - print("参数解析错误") - - near_object = "None" - if obj == "洗手间": - near_object = "大门" - - return near_object - - + # def get_object_info(self,**args): + # try: + # obj = args['obj'] + # + # self.function_success = True + # except: + # obj = None + # print("参数解析错误") + # + # near_object = "None" + # + # max_similarity = 0.02 + # similar_word = None + # + # # 场景中现有物品 + # cur_things = set() + # for item in self.scene.status.objects: + # cur_things.add(item.name) + # # obj与现有物品进行相似度匹配 + # query_token = nlp(obj) + # for w in cur_things: + # word_token = nlp(w) + # similarity = query_token.similarity(word_token) + # if similarity > max_similarity: + # max_similarity = similarity + # similar_word = w + # if similar_word: + # print("max_similarity:",max_similarity,"similar_word:",similar_word) + # + # if similar_word: # 存在同义词说明场景中存在该物品 + # near_object = random.choices(list(cur_things), k=5) # 返回场景中的5个物品 + # + # if obj == "洗手间": + # near_object = "Door" + # + # return near_object + # + # def find_location(self, **args): + # try: + # location = args['obj'] + # self.function_success = True + # except: + # obj = None + # print("参数解析错误") + # + # near_location = None + # # 用户咨询的地点 + # query_token = nlp(location) + # max_similarity = 0 + # similar_word = None + # # 到自己维护的地点列表中找同义词 + # for w in self.scene.all_loc_en: + # word_token = nlp(w) + # similarity = query_token.similarity(word_token) + # if similarity > max_similarity: + # max_similarity = similarity + # similar_word = w + # print("similarity:", max_similarity, "similar_word:", similar_word) + # # 存在同义词说明客户咨询的地点有效 + # if similar_word: + # mp = list(self.scene.loc_map_en[similar_word]) + # near_location = random.choice(mp) + # return near_location def stop_serve(self,**args): - return "好的" \ No newline at end of file + return "好的" + + diff --git a/robowaiter/behavior_lib/act/DealChatNLP.py b/robowaiter/behavior_lib/act/DealChatNLP.py new file mode 100644 index 0000000..e516f89 --- /dev/null +++ b/robowaiter/behavior_lib/act/DealChatNLP.py @@ -0,0 +1,135 @@ +import py_trees as ptree +from robowaiter.behavior_lib._base.Act import Act + +from robowaiter.llm_client.multi_rounds import ask_llm, new_history +import random + + +import spacy +nlp = spacy.load('en_core_web_lg') + + +class DealChat(Act): + def __init__(self): + super().__init__() + self.chat_history = "" + self.function_success = False + self.func_map = { + "create_sub_task": self.create_sub_task, + "stop_serve": self.stop_serve, + "get_object_info": self.get_object_info, + "find_location": self.find_location + } + + def _update(self) -> ptree.common.Status: + # if self.scene.status? + name, sentence = self.scene.state['chat_list'].pop(0) + + if name == "Goal": + self.create_sub_task(goal=sentence) + return ptree.common.Status.RUNNING + + if name not in self.scene.state["chat_history"]: + self.scene.state["chat_history"][name] = new_history() + + history = self.scene.state["chat_history"][name] + self.scene.state["attention"]["customer"] = name + self.scene.state["serve_state"] = { + "last_chat_time": self.scene.time, + } + + function_call, response = ask_llm(sentence,history,func_map=self.func_map) + + + self.scene.chat_bubble(response) # 机器人输出对话 + + return ptree.common.Status.RUNNING + + + def create_sub_task(self, **args): + try: + goal = args['goal'] + + w = goal.split(")") + goal_set = set() + goal_set.add(w[0] + ")") + if len(w) > 1: + for x in w[1:]: + if x != "": + goal_set.add(x[1:] + ")") + self.function_success = True + except: + print("参数解析错误") + + self.scene.robot.expand_sub_task_tree(goal_set) + + def get_object_info(self,**args): + try: + obj = args['obj'] + + self.function_success = True + except: + obj = None + print("参数解析错误") + + near_object = "None" + + max_similarity = 0.02 + similar_word = None + + # 场景中现有物品 + cur_things = set() + for item in self.scene.status.objects: + cur_things.add(item.name) + # obj与现有物品进行相似度匹配 + query_token = nlp(obj) + for w in cur_things: + word_token = nlp(w) + similarity = query_token.similarity(word_token) + if similarity > max_similarity: + max_similarity = similarity + similar_word = w + if similar_word: + print("max_similarity:",max_similarity,"similar_word:",similar_word) + + if similar_word: # 存在同义词说明场景中存在该物品 + near_object = random.choices(list(cur_things), k=5) # 返回场景中的5个物品 + + if obj == "洗手间": + near_object = "Door" + + return near_object + + def find_location(self, **args): + try: + location = args['obj'] + self.function_success = True + except: + obj = None + print("参数解析错误") + + near_location = None + # 用户咨询的地点 + query_token = nlp(location) + max_similarity = 0 + similar_word = None + # 到自己维护的地点列表中找同义词 + for w in self.scene.all_loc_en: + word_token = nlp(w) + similarity = query_token.similarity(word_token) + if similarity > max_similarity: + max_similarity = similarity + similar_word = w + print("similarity:", max_similarity, "similar_word:", similar_word) + # 存在同义词说明客户咨询的地点有效 + if similar_word: + mp = list(self.scene.loc_map_en[similar_word]) + near_location = random.choice(mp) + return near_location + + def stop_serve(self,**args): + + + return "好的" + + diff --git a/robowaiter/behavior_tree/ptml/ptmlCompiler.py b/robowaiter/behavior_tree/ptml/ptmlCompiler.py index 0be7cd5..ef21765 100644 --- a/robowaiter/behavior_tree/ptml/ptmlCompiler.py +++ b/robowaiter/behavior_tree/ptml/ptmlCompiler.py @@ -107,9 +107,12 @@ def format_trans_to_bracket(file_path: str) -> str: for i in range(level): ptml_new += '}' - import re - new_path = re.sub('\\\[a-zA-Z0-9_]*\.ptml', '/bracket_ptml.ptml', file_path) - with open(new_path, 'w+') as file: + file_name = os.path.basename(file_path).split(".")[0] + dir_path = os.path.dirname(file_path) + # import re + # new_path = re.sub('\\\[a-zA-Z0-9_]*\.ptml', '/bracket_ptml.ptml', file_path) + new_path = os.path.join(dir_path,file_name+"_bracket.ptml") + with open(new_path, 'w') as file: file.write(ptml_new) return new_path diff --git a/robowaiter/llm_client/find_obj_utils.py b/robowaiter/llm_client/find_obj_utils.py index 98f965d..fe134ac 100644 --- a/robowaiter/llm_client/find_obj_utils.py +++ b/robowaiter/llm_client/find_obj_utils.py @@ -30,9 +30,8 @@ all_obj = ['马克杯', '香蕉', '牙膏', '面包', '软饮料', '酸奶', 'AD all_loc = ['吧台', '餐桌', '沙发', '灶台', '大门', '灯开关', '空调开关', '橱柜', '卫生间', '窗户', '音响', '休闲区', '工作台', '服务台', '收银台', '墙角', '蛋糕柜', '充电处', '冰箱', '书架'] -all_loc_en = ['bar', 'Table', 'sofa', 'stove', 'Gate', 'light switch', 'airconditioner switch', 'cabinet', 'bathroom', 'window', - 'audio', 'lounge area', 'workstation', 'service counter', 'cashier counter', 'corner', - 'cake display', 'ChargingStations', 'refrigerator', 'bookshelf'] +all_loc_en = ['bar', 'Table', 'sofa', 'stove', 'Gate', 'light switch', 'airconditioner switch', 'cabinet', 'bathroom', 'window','audio', 'lounge area', + 'workstation', 'service counter', 'cashier counter', 'corner','cake display', 'ChargingStations', 'refrigerator', 'bookshelf'] loc_map_en = {'bar': {'工作台', '服务台', '收银台', '蛋糕柜'}, 'Table': {'大门', '休闲区', '墙角'}, diff --git a/robowaiter/llm_client/multi_rounds.py b/robowaiter/llm_client/multi_rounds.py index 81ca2d8..b0a539b 100644 --- a/robowaiter/llm_client/multi_rounds.py +++ b/robowaiter/llm_client/multi_rounds.py @@ -154,7 +154,7 @@ def ask_llm(question,history, func_map=None, retry=3): "你是机器人服务员,请把以下句子换一种表述方式对顾客说,但是意思不变,尽量简短:\n") else: reply = fix_questions_dict[question]["answer"] - result = single_round(f"你是机器人服务员,顾客想知道{question}, 你的具身场景查询返回的是{result},请把按照以下句子对顾客说,{reply}, 尽量简短。\n") + result = single_round(f"你是机器人服务员,顾客想知道{question}, 你的具身场景查询返回的是{result},把返回的英文名词翻译成中文,请把按照以下句子对顾客说,{reply}, 尽量简短。\n") message = {'role': 'assistant', 'content': result, 'name': None, 'function_call': None} diff --git a/robowaiter/robot/DefaultNLP.ptml b/robowaiter/robot/DefaultNLP.ptml new file mode 100644 index 0000000..64870a4 --- /dev/null +++ b/robowaiter/robot/DefaultNLP.ptml @@ -0,0 +1,32 @@ +selector +{ + sequence + { + cond CustomerChatting() + act DealChatNLP() + } + sequence + { + cond HasSubTask() + sequence + { + act SubTaskPlaceHolder() + } + } + sequence + { + cond FocusingCustomer() + act ServeCustomer() + } + sequence + { + cond NewCustomerComing() + selector + { + cond At(Robot,Bar) + act MoveTo(Bar) + } + act GreetCustomer() + } + +} \ No newline at end of file diff --git a/robowaiter/robot/robot.py b/robowaiter/robot/robot.py index f6e1909..a364d1c 100644 --- a/robowaiter/robot/robot.py +++ b/robowaiter/robot/robot.py @@ -35,7 +35,7 @@ class Robot(object): self.action_list = None - def set_scene(self,scene): + def set_scene(self,scene=None): self.scene = scene diff --git a/robowaiter/scene/scene.py b/robowaiter/scene/scene.py index 7cbc2e1..e2b230a 100644 --- a/robowaiter/scene/scene.py +++ b/robowaiter/scene/scene.py @@ -132,6 +132,25 @@ class Scene: with open(self.filename, 'rb') as file: self.map_file = pickle.load(file) + # tool register + self.all_loc_en = ['bar', 'Table', 'sofa', 'stove', 'Gate', 'light switch', 'airconditioner switch', 'cabinet', 'bathroom', 'window', 'audio', + 'lounge area', 'workstation', 'service counter', 'cashier counter', 'corner', 'cake display', 'ChargingStations', + 'refrigerator', 'bookshelf'] + + self.loc_map_en = {'bar': {'工作台', '服务台', '收银台', '蛋糕柜'}, 'Table': {'大门', '休闲区', '墙角'}, + 'sofa': {'餐桌', '窗户', '音响', '休闲区', '墙角', '书架'}, + 'stove': {'吧台', '橱柜', '工作台', '服务台', '收银台', '蛋糕柜', '冰箱'}, + 'Gate': {'吧台', '灯开关', '空调开关', '卫生间', '墙角'}, 'light switch': {'大门', '空调开关', '卫生间', '墙角'}, + 'airconditioner switch': {'大门', '灯开关', '卫生间', '墙角'}, + 'cabinet': {'灶台', '吧台', '工作台', '服务台', '收银台', '蛋糕柜', '充电处', '冰箱'}, 'bathroom': {'大门', '墙角'}, + 'window': {'餐桌', '沙发', '休闲区'}, 'audio': {'餐桌', '沙发', '休闲区', '墙角', '书架'}, + 'lounge area': {'沙发', '餐桌', '墙角', '书架', '音响'}, 'workstation': {'吧台', '服务台', '收银台'}, + 'service counter': {'吧台', '工作台', '收银台'}, 'cashier counter': {'吧台', '工作台', '服务台'}, + 'corner': {'卫生间', '沙发', '灯开关', '空调开关', '音响', '休闲区', '书架'}, + 'cake display': {'吧台', '橱柜', '服务台', '收银台', '冰箱'}, + 'ChargingStations': {'吧台', '餐桌', '沙发', '休闲区', '工作台', '服务台', '收银台', '墙角', '书架'}, + 'refrigerator': {'吧台', '服务台', '蛋糕柜'}, 'bookshelf': {'餐桌', '沙发', '窗户', '休闲区', '墙角'}} + def reset(self): # 基类reset,默认执行仿真器初始化操作 diff --git a/robowaiter/scene/tasks/GQA/GQA.py b/robowaiter/scene/tasks/GQA/GQA.py index 54b9063..cdd6e01 100644 --- a/robowaiter/scene/tasks/GQA/GQA.py +++ b/robowaiter/scene/tasks/GQA/GQA.py @@ -16,7 +16,7 @@ class SceneGQA(Scene): super().__init__(robot) # 在这里加入场景中发生的事件, (事件发生的时间,事件函数) self.new_event_list = [ - (3, self.customer_say, ("System","请问洗手间在哪里?")) + (3, self.customer_say, ("System","哪里有蛋糕")) ] def _reset(self): diff --git a/robowaiter/scene/tasks/GQA/GQA_NLP.py b/robowaiter/scene/tasks/GQA/GQA_NLP.py new file mode 100644 index 0000000..9cb6b7e --- /dev/null +++ b/robowaiter/scene/tasks/GQA/GQA_NLP.py @@ -0,0 +1,47 @@ +""" +具身多轮对话 GQA +点餐(order)的对话,咖啡厅服务员可以为客人(NPC)完成点餐基本对话 +场景对话(GQA)结合场景:询问卫生间、附近娱乐场所(数据来源自主定义) +开始条件:顾客NPC发出点餐指令 +结束条件:顾客NPC发出指令,表示不再需要服务 +""" + +# todo: 使用大模型进行对话,获得指令信息,适时结束对话 +# order = {...} + +from robowaiter.scene.scene import Scene + +class SceneGQA(Scene): + def __init__(self, robot): + super().__init__(robot) + # 在这里加入场景中发生的事件, (事件发生的时间,事件函数) + self.new_event_list = [ + (3, self.customer_say, ("System","哪里有蛋糕")) + ] + + def _reset(self): + # self.clean_walker() + # self.add_walkers([[50, 500,90]]) + pass + + # self.walker_bubble("洗手间在哪里") + # self.control_walker([self.walker_control_generator(0, False, 100, 755, 1900, 180)]) + + + def _run(self): + pass + + +if __name__ == '__main__': + import os + from robowaiter.robot.robot import Robot + from robowaiter.utils.basic import get_root_path + root_path = get_root_path() + ptml_path = os.path.join(root_path, 'robowaiter/robot/DefaultNLP.ptml') + + robot = Robot(ptml_path=ptml_path) + + # create task + task = SceneGQA(robot) + task.reset() + task.run() diff --git a/robowaiter/utils/bt/draw.py b/robowaiter/utils/bt/draw.py index f983e3a..8139bee 100644 --- a/robowaiter/utils/bt/draw.py +++ b/robowaiter/utils/bt/draw.py @@ -111,10 +111,10 @@ def dot_tree( if with_qualified_names: node_label += f"\n({utilities.get_fully_qualified_name(behaviour)})" ''' - if node_name == "Sequence": - node_name = ">" - if node_name == "Selector": - node_name = "?" + # if node_name == "Sequence": + # node_name = ">" + # if node_name == "Selector": + # node_name = "?" return node_name fontsize = 20 diff --git a/robowaiter/utils/draw_bt/Default.ptml b/robowaiter/utils/draw_bt/Default.ptml new file mode 100644 index 0000000..03745e6 --- /dev/null +++ b/robowaiter/utils/draw_bt/Default.ptml @@ -0,0 +1,17 @@ +selector + sequence + cond CustomerChatting() + act DealChat() + sequence + cond HasSubTask() + sequence + act SubTaskPlaceHolder() + sequence + cond FocusingCustomer() + act ServeCustomer() + sequence + cond NewCustomerComing() + selector + cond At(Robot,Bar) + act MoveTo(Bar) + act GreetCustomer() diff --git a/robowaiter/utils/draw_bt/Default_bracket.ptml b/robowaiter/utils/draw_bt/Default_bracket.ptml new file mode 100644 index 0000000..e18182b --- /dev/null +++ b/robowaiter/utils/draw_bt/Default_bracket.ptml @@ -0,0 +1,28 @@ +selector +{ + sequence +{ + cond CustomerChatting() + act DealChat() + +} sequence +{ + cond HasSubTask() + sequence +{ + act SubTaskPlaceHolder() + +} sequence + cond FocusingCustomer() + act ServeCustomer() + +} sequence +{ + cond NewCustomerComing() + selector +{ + cond At(Robot,Bar) + act MoveTo(Bar) + +} act GreetCustomer() +}} \ No newline at end of file diff --git a/robowaiter/utils/draw_bt/__init__.py b/robowaiter/utils/draw_bt/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/robowaiter/utils/draw_bt/draw_bt.py b/robowaiter/utils/draw_bt/draw_bt.py new file mode 100644 index 0000000..4cbb292 --- /dev/null +++ b/robowaiter/utils/draw_bt/draw_bt.py @@ -0,0 +1,21 @@ +# from robowaiter.scene.scene import Scene +# from robowaiter.behavior_tree.ptml.ptmlCompiler import load + +import os +from robowaiter.robot.robot import Robot +from robowaiter.utils.bt.draw import render_dot_tree +from robowaiter.utils.basic import get_root_path +from robowaiter.utils.bt.load import load_bt_from_ptml + +if __name__ == '__main__': + + # create robot + root_path = get_root_path() + ptml_path = os.path.join(root_path, 'robowaiter/utils/draw_bt/Default.ptml') + behavior_lib_path = os.path.join(root_path, 'robowaiter/behavior_lib') + bt = load_bt_from_ptml(None, ptml_path, behavior_lib_path) + + + + render_dot_tree(bt.root,name="test") + # build and tick diff --git a/robowaiter/utils/draw_bt/test.dot b/robowaiter/utils/draw_bt/test.dot new file mode 100644 index 0000000..bd79eac --- /dev/null +++ b/robowaiter/utils/draw_bt/test.dot @@ -0,0 +1,39 @@ +digraph pastafarianism { +ordering=out; +graph [fontname="times-roman"]; +node [fontname="times-roman"]; +edge [fontname="times-roman"]; +"a3ac082f-ad46-4cc9-86b4-3e76c3c564d3" [fillcolor=cyan, fontcolor=black, fontsize=20, height=0.01, label=Selector, shape=diamond, style=filled, width=0.01]; +"717a1290-56bc-41e1-9b4b-e6df93d40e64" [fillcolor=orange, fontcolor=black, fontsize=20, height=0.01, label=Sequence, shape=octagon, style=filled, width=0.01]; +"a3ac082f-ad46-4cc9-86b4-3e76c3c564d3" -> "717a1290-56bc-41e1-9b4b-e6df93d40e64"; +"b3236b13-d5f2-4643-ae7c-6f27bd4ab6f2" [fillcolor=yellow, fontcolor=black, fontsize=20, label="CustomerChatting()", shape=ellipse, style=filled]; +"717a1290-56bc-41e1-9b4b-e6df93d40e64" -> "b3236b13-d5f2-4643-ae7c-6f27bd4ab6f2"; +"28015225-b7a4-4f38-b26f-4dbe5eea4154" [fillcolor=lawngreen, fontcolor=black, fontsize=20, label="DealChat()", shape=box, style=filled]; +"717a1290-56bc-41e1-9b4b-e6df93d40e64" -> "28015225-b7a4-4f38-b26f-4dbe5eea4154"; +"ff83c742-a2ba-4aa5-8b3a-39ecd7c03b0e" [fillcolor=orange, fontcolor=black, fontsize=20, height=0.01, label=Sequence, shape=octagon, style=filled, width=0.01]; +"a3ac082f-ad46-4cc9-86b4-3e76c3c564d3" -> "ff83c742-a2ba-4aa5-8b3a-39ecd7c03b0e"; +"2f77f976-499c-4601-9d8c-86dd80d66dfa" [fillcolor=yellow, fontcolor=black, fontsize=20, label="HasSubTask()", shape=ellipse, style=filled]; +"ff83c742-a2ba-4aa5-8b3a-39ecd7c03b0e" -> "2f77f976-499c-4601-9d8c-86dd80d66dfa"; +"2428792c-3896-443d-8744-f5e286644fad" [fillcolor=orange, fontcolor=black, fontsize=20, height=0.01, label=Sequence, shape=octagon, style=filled, width=0.01]; +"ff83c742-a2ba-4aa5-8b3a-39ecd7c03b0e" -> "2428792c-3896-443d-8744-f5e286644fad"; +"4bb7a9c3-521b-408f-b403-1fd25d54b192" [fillcolor=lawngreen, fontcolor=black, fontsize=20, label="SubTaskPlaceHolder()", shape=box, style=filled]; +"2428792c-3896-443d-8744-f5e286644fad" -> "4bb7a9c3-521b-408f-b403-1fd25d54b192"; +"64b2362a-d99e-4e99-8772-ad1419e53a2e" [fillcolor=orange, fontcolor=black, fontsize=20, height=0.01, label=Sequence, shape=octagon, style=filled, width=0.01]; +"ff83c742-a2ba-4aa5-8b3a-39ecd7c03b0e" -> "64b2362a-d99e-4e99-8772-ad1419e53a2e"; +"fd7124ba-c9d1-4fde-8063-e8337d335121" [fillcolor=yellow, fontcolor=black, fontsize=20, label="FocusingCustomer()", shape=ellipse, style=filled]; +"64b2362a-d99e-4e99-8772-ad1419e53a2e" -> "fd7124ba-c9d1-4fde-8063-e8337d335121"; +"169ebec9-3645-4fbb-a533-5186a8e5967b" [fillcolor=lawngreen, fontcolor=black, fontsize=20, label="ServeCustomer()", shape=box, style=filled]; +"64b2362a-d99e-4e99-8772-ad1419e53a2e" -> "169ebec9-3645-4fbb-a533-5186a8e5967b"; +"bea12066-ecbd-49b0-8934-efcb2c38b5f5" [fillcolor=orange, fontcolor=black, fontsize=20, height=0.01, label=Sequence, shape=octagon, style=filled, width=0.01]; +"ff83c742-a2ba-4aa5-8b3a-39ecd7c03b0e" -> "bea12066-ecbd-49b0-8934-efcb2c38b5f5"; +"a847a0cc-c5af-4757-aa8c-8baef72788dc" [fillcolor=yellow, fontcolor=black, fontsize=20, label="NewCustomerComing()", shape=ellipse, style=filled]; +"bea12066-ecbd-49b0-8934-efcb2c38b5f5" -> "a847a0cc-c5af-4757-aa8c-8baef72788dc"; +"99354f05-1716-46b2-9151-d88eac0a5b27" [fillcolor=cyan, fontcolor=black, fontsize=20, height=0.01, label=Selector, shape=diamond, style=filled, width=0.01]; +"bea12066-ecbd-49b0-8934-efcb2c38b5f5" -> "99354f05-1716-46b2-9151-d88eac0a5b27"; +"19de10a3-7554-43a3-b892-34cb2e32ab9a" [fillcolor=yellow, fontcolor=black, fontsize=20, label="At(Robot,Bar)", shape=ellipse, style=filled]; +"99354f05-1716-46b2-9151-d88eac0a5b27" -> "19de10a3-7554-43a3-b892-34cb2e32ab9a"; +"4286d652-c4ef-4522-a7f1-b5c865dcc4c9" [fillcolor=lawngreen, fontcolor=black, fontsize=20, label="MoveTo(Bar)", shape=box, style=filled]; +"99354f05-1716-46b2-9151-d88eac0a5b27" -> "4286d652-c4ef-4522-a7f1-b5c865dcc4c9"; +"a3766a34-5152-4f82-8fba-8bf1f6b3830b" [fillcolor=lawngreen, fontcolor=black, fontsize=20, label="GreetCustomer()", shape=box, style=filled]; +"bea12066-ecbd-49b0-8934-efcb2c38b5f5" -> "a3766a34-5152-4f82-8fba-8bf1f6b3830b"; +} diff --git a/robowaiter/utils/draw_bt/test.png b/robowaiter/utils/draw_bt/test.png new file mode 100644 index 0000000..773238d Binary files /dev/null and b/robowaiter/utils/draw_bt/test.png differ diff --git a/robowaiter/utils/draw_bt/test.svg b/robowaiter/utils/draw_bt/test.svg new file mode 100644 index 0000000..2ed2acf --- /dev/null +++ b/robowaiter/utils/draw_bt/test.svg @@ -0,0 +1,211 @@ + + + + + + +pastafarianism + + + +a3ac082f-ad46-4cc9-86b4-3e76c3c564d3 + +Selector + + + +717a1290-56bc-41e1-9b4b-e6df93d40e64 + +Sequence + + + +a3ac082f-ad46-4cc9-86b4-3e76c3c564d3->717a1290-56bc-41e1-9b4b-e6df93d40e64 + + + + + +ff83c742-a2ba-4aa5-8b3a-39ecd7c03b0e + +Sequence + + + +a3ac082f-ad46-4cc9-86b4-3e76c3c564d3->ff83c742-a2ba-4aa5-8b3a-39ecd7c03b0e + + + + + +b3236b13-d5f2-4643-ae7c-6f27bd4ab6f2 + +CustomerChatting() + + + +717a1290-56bc-41e1-9b4b-e6df93d40e64->b3236b13-d5f2-4643-ae7c-6f27bd4ab6f2 + + + + + +28015225-b7a4-4f38-b26f-4dbe5eea4154 + +DealChat() + + + +717a1290-56bc-41e1-9b4b-e6df93d40e64->28015225-b7a4-4f38-b26f-4dbe5eea4154 + + + + + +2f77f976-499c-4601-9d8c-86dd80d66dfa + +HasSubTask() + + + +ff83c742-a2ba-4aa5-8b3a-39ecd7c03b0e->2f77f976-499c-4601-9d8c-86dd80d66dfa + + + + + +2428792c-3896-443d-8744-f5e286644fad + +Sequence + + + +ff83c742-a2ba-4aa5-8b3a-39ecd7c03b0e->2428792c-3896-443d-8744-f5e286644fad + + + + + +64b2362a-d99e-4e99-8772-ad1419e53a2e + +Sequence + + + +ff83c742-a2ba-4aa5-8b3a-39ecd7c03b0e->64b2362a-d99e-4e99-8772-ad1419e53a2e + + + + + +bea12066-ecbd-49b0-8934-efcb2c38b5f5 + +Sequence + + + +ff83c742-a2ba-4aa5-8b3a-39ecd7c03b0e->bea12066-ecbd-49b0-8934-efcb2c38b5f5 + + + + + +4bb7a9c3-521b-408f-b403-1fd25d54b192 + +SubTaskPlaceHolder() + + + +2428792c-3896-443d-8744-f5e286644fad->4bb7a9c3-521b-408f-b403-1fd25d54b192 + + + + + +fd7124ba-c9d1-4fde-8063-e8337d335121 + +FocusingCustomer() + + + +64b2362a-d99e-4e99-8772-ad1419e53a2e->fd7124ba-c9d1-4fde-8063-e8337d335121 + + + + + +169ebec9-3645-4fbb-a533-5186a8e5967b + +ServeCustomer() + + + +64b2362a-d99e-4e99-8772-ad1419e53a2e->169ebec9-3645-4fbb-a533-5186a8e5967b + + + + + +a847a0cc-c5af-4757-aa8c-8baef72788dc + +NewCustomerComing() + + + +bea12066-ecbd-49b0-8934-efcb2c38b5f5->a847a0cc-c5af-4757-aa8c-8baef72788dc + + + + + +99354f05-1716-46b2-9151-d88eac0a5b27 + +Selector + + + +bea12066-ecbd-49b0-8934-efcb2c38b5f5->99354f05-1716-46b2-9151-d88eac0a5b27 + + + + + +a3766a34-5152-4f82-8fba-8bf1f6b3830b + +GreetCustomer() + + + +bea12066-ecbd-49b0-8934-efcb2c38b5f5->a3766a34-5152-4f82-8fba-8bf1f6b3830b + + + + + +19de10a3-7554-43a3-b892-34cb2e32ab9a + +At(Robot,Bar) + + + +99354f05-1716-46b2-9151-d88eac0a5b27->19de10a3-7554-43a3-b892-34cb2e32ab9a + + + + + +4286d652-c4ef-4522-a7f1-b5c865dcc4c9 + +MoveTo(Bar) + + + +99354f05-1716-46b2-9151-d88eac0a5b27->4286d652-c4ef-4522-a7f1-b5c865dcc4c9 + + + + +