增加行为树对比和测试

This commit is contained in:
Caiyishuai 2023-12-12 20:13:13 +08:00
parent 73a51b417d
commit a5978ff37a
12 changed files with 643 additions and 30 deletions

View File

@ -15,24 +15,17 @@ class Bahavior(ptree.behaviour.Behaviour):
scene = None
print_name_prefix = ""
tables_for_placement = {'Bar', 'Bar2', 'WaterTable', 'CoffeeTable', 'Table1', 'Table2', 'Table3',"BrightTable6"}
# all_object = {'Coffee', 'Water', 'Dessert', 'Softdrink', 'BottledDrink', 'Yogurt', 'ADMilk', 'MilkDrink', 'Milk',
# 'VacuumCup'}
all_object = {
'Coffee', 'Water', 'Dessert', 'Softdrink', 'BottledDrink', 'Yogurt', 'ADMilk', 'MilkDrink', 'Milk','VacuumCup',
'Chips', 'NFCJuice', 'Bernachon', 'ADMilk', 'SpringWater'}
# BrightTable5 = Table4
tables_for_guiding = {"QuietTable1","QuietTable2",
"BrightTable1","BrightTable2","BrightTable3","BrightTable4","BrightTable5","BrightTable6"
'CoffeeTable','WaterTable','Table1', 'Table2', 'Table3'}
# all_place = {'Bar', 'WaterTable', 'CoffeeTable'}
# all_object = {'Coffee', 'Water', 'Dessert', 'Softdrink', 'Yogurt'}
# all_object = {'Coffee', 'Water'}
# all_object = set()
# all_place=set()
# tables_for_placement = {'Bar', 'WaterTable', 'CoffeeTable'}
# all_object = {'Coffee', 'Water', 'Dessert', 'Softdrink', 'Yogurt'}
num_of_obj_on_place={
'Bar': 0, # (247.0, 520.0, 100.0)

View File

@ -15,7 +15,8 @@ class FreeHands(Act):
@classmethod
def get_info(cls):
info = {}
info["pre"]= set()
# info["pre"]= set()
info["pre"] ={f'Holding(Nothing)'}
info['add'] = {f'Holding(Nothing)'}
info['del_set'] = {f'Holding({obj})' for obj in cls.all_object}
info['cost'] = 0

View File

@ -0,0 +1,297 @@
import random
import numpy as np
import copy
import time
from robowaiter.behavior_tree.obtea.BehaviorTree import Leaf,ControlBT
from robowaiter.behavior_tree.obtea.OptimalBTExpansionAlgorithm import Action,generate_random_state,state_transition,conflict
# 本文所提出的完备规划算法
class BTalgorithm:
def __init__(self,verbose=False):
self.bt = None
self.nodes = []
self.traversed = []
self.conditions = []
self.conditions_index = []
self.verbose = verbose
# print (self.conditions_list[0])
def clear(self):
self.bt = None
self.nodes = []
self.traversed = []
self.conditions = []
self.conditions_index = []
# 运行规划算法从初始状态、目标状态和可用行动计算行为树self.bt
def run_algorithm(self, start, goal, actions):
# 初始行为树只包含目标条件
self.bt = ControlBT(type='cond')
g_node = Leaf(type='cond', content=goal,mincost=0)
self.bt.add_child([g_node])
self.conditions.append(goal)
self.nodes.append(g_node) # condition node list
# 尝试在初始状态执行行为树
val, obj = self.bt.tick(start)
canrun = False
if val == 'success' or val == 'running':
canrun = True
# 循环扩展,直到行为树能够在初始状态运行
while not canrun:
index = -1
for i in range(0, len(self.nodes)):
if self.nodes[i].content in self.traversed:
continue
else:
c_node = self.nodes[i]
index = i
break
if index == -1: # 树中结点扩展完毕,仍无法运行行为树,返回失败
print('Failure')
return False
# 根据所选择条件结点扩展子树
subtree = ControlBT(type='?')
subtree.add_child([copy.deepcopy(c_node)]) # 子树首先保留所扩展结点
c = c_node.content # 子树所扩展结点对应的条件一个文字的set
for i in range(0, len(actions)): # 选择符合条件的行动,
# print("have action")
if not c & ((actions[i].pre | actions[i].add) - actions[i].del_set) <= set():
# print ("pass add")
if (c - actions[i].del_set) == c:
# print("pass delete")
c_attr = (actions[i].pre | c) - actions[i].add
valid = True
# 这样剪枝存在错误性
if conflict(c_attr):
continue
for j in self.traversed: # 剪枝操作
if j <= c_attr:
valid = False
break
if valid:
# print("pass prune")
# 构建行动的顺序结构
sequence_structure = ControlBT(type='>')
c_attr_node = Leaf(type='cond', content=c_attr, mincost=0)
a_node = Leaf(type='act', content=actions[i], mincost=0)
sequence_structure.add_child([c_attr_node, a_node])
# 将顺序结构添加到子树
subtree.add_child([sequence_structure])
self.nodes.append(c_attr_node)
# 将原条件结点c_node替换为扩展后子树subtree
parent_of_c = c_node.parent
parent_of_c.children[0] = subtree
# 记录已扩展条件
self.traversed.append(c)
# 尝试在初始状态运行行为树
val, obj = self.bt.tick(start)
canrun = False
if val == 'success' or val == 'running':
canrun = True
return True
def print_solution(self):
print(len(self.nodes))
# for i in self.nodes:
# if isinstance(i,Node):
# print (i.content)
# else:
# print (i)
# 树的dfs
def dfs_ptml(self,parnode,is_root=False):
for child in parnode.children:
if isinstance(child, Leaf):
if child.type == 'cond':
if is_root and len(child.content) > 1:
# 把多个 cond 串起来
self.ptml_string += "sequence{\n"
self.ptml_string += "cond "
c_set_str = '\n cond '.join(map(str, child.content)) + "\n"
self.ptml_string += c_set_str
self.ptml_string += '}\n'
else:
self.ptml_string += "cond "
c_set_str = '\n cond '.join(map(str, child.content)) + "\n"
self.ptml_string += c_set_str
elif child.type == 'act':
if '(' not in child.content.name:
self.ptml_string += 'act ' + child.content.name + "()\n"
else:
self.ptml_string += 'act ' + child.content.name + "\n"
elif isinstance(child, ControlBT):
if child.type == '?':
self.ptml_string += "selector{\n"
self.dfs_ptml(parnode=child)
elif child.type == '>':
self.ptml_string += "sequence{\n"
self.dfs_ptml( parnode=child)
self.ptml_string += '}\n'
def get_ptml(self):
self.ptml_string = "selector{\n"
self.dfs_ptml(self.bt.children[0],is_root=True)
self.ptml_string += '}\n'
return self.ptml_string
def save_ptml_file(self,file_name):
self.ptml_string = "selector{\n"
self.dfs_ptml(self.bt.children[0])
self.ptml_string += '}\n'
with open(f'./{file_name}.ptml', 'w') as file:
file.write(self.ptml_string)
return self.ptml_string
# 所对比的基准算法,具体扩展细节有差异
if __name__ == '__main__':
random.seed(1)
# 设置生成规划问题集的超参数:文字数、解深度、迭代次数
literals_num = 10
depth = 10
iters = 10
total_tree_size = []
total_action_num = []
total_state_num = []
total_steps_num = []
# fail_count=0
# danger_count=0
success_count = 0
failure_count = 0
planning_time_total = 0.0
# 实验1000次
for count in range(0, 1000):
# 生成一个规划问题,包括随机的状态和行动,以及目标状态
states = []
actions = []
start = generate_random_state(literals_num)
state = start
states.append(state)
# print (state)
for i in range(0, depth):
a = Action()
a.generate_from_state(state, literals_num)
if not a in actions:
actions.append(a)
state = state_transition(state, a)
if state in states:
pass
else:
states.append(state)
# print(state)
goal = states[-1]
state = start
for i in range(0, iters):
a = Action()
a.generate_from_state(state, literals_num)
if not a in actions:
actions.append(a)
state = state_transition(state, a)
if state in states:
pass
else:
states.append(state)
state = random.sample(states, 1)[0]
# 选择测试本文算法btalgorithm或对比算法weakalgorithm
algo = BTalgorithm()
# algo = Weakalgorithm()
start_time = time.time()
if algo.run_algorithm(start, goal, list(actions)): # 运行算法规划后行为树为algo.bt
total_tree_size.append(algo.bt.count_size() - 1)
else:
print("error")
end_time = time.time()
planning_time_total += (end_time - start_time)
# 开始从初始状态运行行为树,测试
state = start
steps = 0
val, obj = algo.bt.tick(state) # tick行为树obj为所运行的行动
while val != 'success' and val != 'failure': # 运行直到行为树成功或失败
state = state_transition(state, obj)
val, obj = algo.bt.tick(state)
if (val == 'failure'):
print("bt fails at step", steps)
steps += 1
if (steps >= 500): # 至多运行500步
break
if not goal <= state: # 错误解,目标条件不在执行后状态满足
# print ("wrong solution",steps)
failure_count += 1
else: # 正确解,满足目标条件
# print ("right solution",steps)
success_count += 1
total_steps_num.append(steps)
algo.clear()
total_action_num.append(len(actions))
total_state_num.append(len(states))
print(success_count, failure_count) # 算法成功和失败次数
print(np.mean(total_tree_size), np.std(total_tree_size, ddof=1)) # 1000次测试树大小
print(np.mean(total_steps_num), np.std(total_steps_num, ddof=1))
print(np.mean(total_state_num)) # 1000次问题的平均状态数
print(np.mean(total_action_num)) # 1000次问题的平均行动数
print(planning_time_total, planning_time_total / 1000.0)
# print(total_state_num)
# casestudy begin 对应论文的case study包含三个行动的移动机械臂场景
actions = []
a = Action(name='movebtob')
a.pre = {1, 2}
a.add = {3}
a.del_set = {1, 4}
actions.append(a)
a = Action(name='moveatob')
a.pre = {1}
a.add = {5, 2}
a.del_set = {1, 6}
actions.append(a)
a = Action(name='moveatoa')
a.pre = {7}
a.add = {8, 2}
a.del_set = {7, 6}
actions.append(a)
start = {1, 7, 4, 6}
goal = {3}
algo = BTalgorithm()
algo.clear()
algo.run_algorithm(start, goal, list(actions))
state = start
steps = 0
val, obj = algo.bt.tick(state)
while val != 'success' and val != 'failure':
state = state_transition(state, obj)
print(obj.name)
val, obj = algo.bt.tick(state)
if (val == 'failure'):
print("bt fails at step", steps)
steps += 1
if not goal <= state:
print("wrong solution", steps)
else:
print("right solution", steps)
# algo.bt.print_nodes()
print(algo.bt.count_size() - 1)
algo.clear()
# case study end

View File

@ -20,6 +20,24 @@ class Action:
def __str__(self):
return self.name
# 从状态随机生成一个行动
def generate_from_state(self,state,num):
for i in range(0,num):
if i in state:
if random.random() >0.5:
self.pre.add(i)
if random.random() >0.5:
self.del_set.add(i)
continue
if random.random() > 0.5:
self.add.add(i)
continue
if random.random() >0.5:
self.del_set.add(i)
def print_action(self):
print (self.pre)
print(self.add)
print(self.del_set)
#生成随机状态
def generate_random_state(num):
@ -68,9 +86,9 @@ class OptBTExpAlgorithm:
self.conditions_index = []
#运行规划算法从初始状态、目标状态和可用行动计算行为树self.bt
def run_algorithm(self,goal,actions,scene):
self.scene = scene
# def run_algorithm(self,goal,actions,scene):
def run_algorithm(self, start, goal, actions):
# self.scene = scene
if self.verbose:
print("\n算法开始!")
@ -113,7 +131,6 @@ class OptBTExpAlgorithm:
min_cost = cond_anc_pair.cond_leaf.mincost
pair_node = copy.deepcopy(cond_anc_pair)
index = i
break
if self.verbose:
print("选择扩展条件结点:",pair_node.cond_leaf.content)
@ -141,7 +158,8 @@ class OptBTExpAlgorithm:
subtree.add_child([copy.deepcopy(sequence_structure)]) # subtree 是回不断变化的它的父亲是self.bt
self.expanded.append(copy.deepcopy(pair_node))
# 增加实时条件判断,满足条件就不再扩展
if c <= self.scene.state["condition_set"]:
# if c <= self.scene.state["condition_set"]:
if c <= start:
return True
else:
subtree.add_child([copy.deepcopy(pair_node.act_leaf)])
@ -158,6 +176,11 @@ class OptBTExpAlgorithm:
current_mincost = pair_node.cond_leaf.mincost # 当前的最短路径是多少
for i in range(0, len(actions)):
if actions[i].name == 'FreeHands()':
kk=1
if not c & ((actions[i].pre | actions[i].add) - actions[i].del_set) <= set():
if (c - actions[i].del_set) == c:
if self.verbose:

View File

@ -1,5 +1,6 @@
from robowaiter.behavior_tree.obtea.OptimalBTExpansionAlgorithm import Action,OptBTExpAlgorithm,state_transition # 调用最优行为树扩展算法
from robowaiter.behavior_tree.obtea.BTExpansionAlgorithm import BTalgorithm # 调用最优行为树扩展算法
from robowaiter.behavior_tree.obtea.examples import *
@ -23,6 +24,8 @@ class BTOptExpInterface:
self.has_processed = False
self.scene = scene
self.bt_algo_opt = self.scene.bt_algo_opt
def process(self, goal):
"""
@ -31,9 +34,15 @@ class BTOptExpInterface:
:return: A PTML string representing the outcome of the behavior tree.
"""
self.goal = goal
if self.bt_algo_opt:
self.algo = OptBTExpAlgorithm(verbose=False)
else:
self.algo = BTalgorithm(verbose=False)
self.algo.clear()
self.algo.run_algorithm(self.goal, self.actions,self.scene) # 调用算法得到行为树保存至 algo.bt
self.algo.run_algorithm(self.scene.state["condition_set"],self.goal, self.actions) # 调用算法得到行为树保存至 algo.bt
self.ptml_string = self.algo.get_ptml()
self.has_processed = True
# algo.print_solution() # print behavior tree

View File

@ -222,12 +222,6 @@ get_object_info
好的,我明白了,那么我们推荐您到大厅的桌子,那里的空间比较宽敞,环境也比较明亮,适合带着孩子一起用餐。
冰红茶
好的
create_sub_task
{"goal":"On(Yogurt,WaterTable)"}
水杯
好的
create_sub_task
@ -259,3 +253,8 @@ create_sub_task
好的
create_sub_task
{"goal":"On(Dessert,Bar)"}
打开空调并降低空调温度
好的,没问题
create_sub_task
{"goal":"Is(ACTemperature,Down)"}

View File

@ -19,7 +19,7 @@ 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')
from robowaiter.utils.bt.draw import render_dot_tree
class Robot(object):
scene = None
@ -79,6 +79,7 @@ class Robot(object):
file.write(ptml_string)
sub_task_bt = load_bt_from_ptml(self.scene, file_path,self.behavior_lib_path)
render_dot_tree(sub_task_bt.root, target_directory=self.scene.output_path, name="expanded_bt", png_only=False)
# 加入删除子树的节点
seq = Sequence(name="Sequence", memory=False)

View File

@ -0,0 +1,37 @@
digraph pastafarianism {
ordering=out;
graph [fontname="times-roman"];
node [fontname="times-roman"];
edge [fontname="times-roman"];
"87355232-8ad6-484e-b363-38536e737846" [fillcolor=cyan, fontcolor=black, fontsize=20, height=0.01, label=Selector, shape=diamond, style=filled, width=0.01];
"3f017683-7aa3-40d3-b2be-cc32784313a1" [fillcolor=yellow, fontcolor=black, fontsize=20, label="Is(ACTemperature,Down)", shape=ellipse, style=filled];
"87355232-8ad6-484e-b363-38536e737846" -> "3f017683-7aa3-40d3-b2be-cc32784313a1";
"b900e9cb-c0a8-4e8d-8a9b-d871012abefb" [fillcolor=orange, fontcolor=black, fontsize=20, height=0.01, label=Sequence, shape=octagon, style=filled, width=0.01];
"87355232-8ad6-484e-b363-38536e737846" -> "b900e9cb-c0a8-4e8d-8a9b-d871012abefb";
"10ef3ff4-7acb-4991-9e63-6e489c3ef22d" [fillcolor=yellow, fontcolor=black, fontsize=20, label="Holding(Nothing)", shape=ellipse, style=filled];
"b900e9cb-c0a8-4e8d-8a9b-d871012abefb" -> "10ef3ff4-7acb-4991-9e63-6e489c3ef22d";
"a3869371-404d-4085-932b-232e188fb133" [fillcolor=yellow, fontcolor=black, fontsize=20, label="Is(AC,On)", shape=ellipse, style=filled];
"b900e9cb-c0a8-4e8d-8a9b-d871012abefb" -> "a3869371-404d-4085-932b-232e188fb133";
"3a5cbe8f-7672-4a34-91d1-87502aed457c" [fillcolor=lawngreen, fontcolor=black, fontsize=20, label="Turn(ACTemperature,Down)", shape=box, style=filled];
"b900e9cb-c0a8-4e8d-8a9b-d871012abefb" -> "3a5cbe8f-7672-4a34-91d1-87502aed457c";
"b64db1a4-d79f-47b4-99db-f184b38d1361" [fillcolor=orange, fontcolor=black, fontsize=20, height=0.01, label=Sequence, shape=octagon, style=filled, width=0.01];
"87355232-8ad6-484e-b363-38536e737846" -> "b64db1a4-d79f-47b4-99db-f184b38d1361";
"c6eca6dd-9fca-4bd3-b054-9b43fe02613a" [fillcolor=yellow, fontcolor=black, fontsize=20, label="Is(AC,On)", shape=ellipse, style=filled];
"b64db1a4-d79f-47b4-99db-f184b38d1361" -> "c6eca6dd-9fca-4bd3-b054-9b43fe02613a";
"df04f6f4-d471-4519-ab9e-5d5bd8dfbd4c" [fillcolor=lawngreen, fontcolor=black, fontsize=20, label="FreeHands()", shape=box, style=filled];
"b64db1a4-d79f-47b4-99db-f184b38d1361" -> "df04f6f4-d471-4519-ab9e-5d5bd8dfbd4c";
"8108bcba-dbeb-4784-8f1f-eb9ede4ffb0e" [fillcolor=orange, fontcolor=black, fontsize=20, height=0.01, label=Sequence, shape=octagon, style=filled, width=0.01];
"87355232-8ad6-484e-b363-38536e737846" -> "8108bcba-dbeb-4784-8f1f-eb9ede4ffb0e";
"82a23405-c3c6-47dc-bf7b-0636e3efe52c" [fillcolor=yellow, fontcolor=black, fontsize=20, label="Holding(Nothing)", shape=ellipse, style=filled];
"8108bcba-dbeb-4784-8f1f-eb9ede4ffb0e" -> "82a23405-c3c6-47dc-bf7b-0636e3efe52c";
"010d42ee-18b3-4a0e-9be1-eab67afaca60" [fillcolor=yellow, fontcolor=black, fontsize=20, label="Is(AC,Off)", shape=ellipse, style=filled];
"8108bcba-dbeb-4784-8f1f-eb9ede4ffb0e" -> "010d42ee-18b3-4a0e-9be1-eab67afaca60";
"90cdf2ff-98b0-4454-803b-feee5f5475bf" [fillcolor=lawngreen, fontcolor=black, fontsize=20, label="Turn(AC,On)", shape=box, style=filled];
"8108bcba-dbeb-4784-8f1f-eb9ede4ffb0e" -> "90cdf2ff-98b0-4454-803b-feee5f5475bf";
"e65ce322-edaa-4677-ab68-4795e57648da" [fillcolor=orange, fontcolor=black, fontsize=20, height=0.01, label=Sequence, shape=octagon, style=filled, width=0.01];
"87355232-8ad6-484e-b363-38536e737846" -> "e65ce322-edaa-4677-ab68-4795e57648da";
"7d0c1403-c5d9-4bcd-a0db-f3e527a3be93" [fillcolor=yellow, fontcolor=black, fontsize=20, label="Is(AC,Off)", shape=ellipse, style=filled];
"e65ce322-edaa-4677-ab68-4795e57648da" -> "7d0c1403-c5d9-4bcd-a0db-f3e527a3be93";
"931d4ea6-c661-4ea8-9016-2d4e17d30b19" [fillcolor=lawngreen, fontcolor=black, fontsize=20, label="FreeHands()", shape=box, style=filled];
"e65ce322-edaa-4677-ab68-4795e57648da" -> "931d4ea6-c661-4ea8-9016-2d4e17d30b19";
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

View File

@ -0,0 +1,199 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 9.0.0 (20230911.1827)
-->
<!-- Title: pastafarianism Pages: 1 -->
<svg width="1818pt" height="235pt"
viewBox="0.00 0.00 1817.82 234.53" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 230.53)">
<title>pastafarianism</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-230.53 1813.82,-230.53 1813.82,4 -4,4"/>
<!-- 87355232&#45;8ad6&#45;484e&#45;b363&#45;38536e737846 -->
<g id="node1" class="node">
<title>87355232&#45;8ad6&#45;484e&#45;b363&#45;38536e737846</title>
<polygon fill="cyan" stroke="black" points="825.2,-226.53 741.7,-195.28 825.2,-164.03 908.7,-195.28 825.2,-226.53"/>
<text text-anchor="middle" x="825.2" y="-187.9" font-family="Times New Roman,serif" font-size="20.00">Selector</text>
</g>
<!-- 3f017683&#45;7aa3&#45;40d3&#45;b2be&#45;cc32784313a1 -->
<g id="node2" class="node">
<title>3f017683&#45;7aa3&#45;40d3&#45;b2be&#45;cc32784313a1</title>
<ellipse fill="yellow" stroke="black" cx="282.2" cy="-104.11" rx="161.93" ry="22.1"/>
<text text-anchor="middle" x="282.2" y="-96.74" font-family="Times New Roman,serif" font-size="20.00">Is(ACTemperature,Down)</text>
</g>
<!-- 87355232&#45;8ad6&#45;484e&#45;b363&#45;38536e737846&#45;&gt;3f017683&#45;7aa3&#45;40d3&#45;b2be&#45;cc32784313a1 -->
<g id="edge1" class="edge">
<title>87355232&#45;8ad6&#45;484e&#45;b363&#45;38536e737846&#45;&gt;3f017683&#45;7aa3&#45;40d3&#45;b2be&#45;cc32784313a1</title>
<path fill="none" stroke="black" d="M768.11,-184.91C679.84,-170.41 508.52,-142.28 394.73,-123.59"/>
<polygon fill="black" stroke="black" points="395.49,-120.17 385.05,-122 394.35,-127.08 395.49,-120.17"/>
</g>
<!-- b900e9cb&#45;c0a8&#45;4e8d&#45;8a9b&#45;d871012abefb -->
<g id="node3" class="node">
<title>b900e9cb&#45;c0a8&#45;4e8d&#45;8a9b&#45;d871012abefb</title>
<polygon fill="orange" stroke="black" points="606.72,-94.2 606.72,-114.02 564.24,-128.03 504.16,-128.03 461.68,-114.02 461.68,-94.2 504.16,-80.19 564.24,-80.19 606.72,-94.2"/>
<text text-anchor="middle" x="534.2" y="-96.74" font-family="Times New Roman,serif" font-size="20.00">Sequence</text>
</g>
<!-- 87355232&#45;8ad6&#45;484e&#45;b363&#45;38536e737846&#45;&gt;b900e9cb&#45;c0a8&#45;4e8d&#45;8a9b&#45;d871012abefb -->
<g id="edge2" class="edge">
<title>87355232&#45;8ad6&#45;484e&#45;b363&#45;38536e737846&#45;&gt;b900e9cb&#45;c0a8&#45;4e8d&#45;8a9b&#45;d871012abefb</title>
<path fill="none" stroke="black" d="M780.05,-180.44C731.03,-165.43 652.4,-141.33 597.29,-124.44"/>
<polygon fill="black" stroke="black" points="598.63,-121.19 588.04,-121.61 596.58,-127.89 598.63,-121.19"/>
</g>
<!-- b64db1a4&#45;d79f&#45;47b4&#45;99db&#45;f184b38d1361 -->
<g id="node7" class="node">
<title>b64db1a4&#45;d79f&#45;47b4&#45;99db&#45;f184b38d1361</title>
<polygon fill="orange" stroke="black" points="897.72,-94.2 897.72,-114.02 855.24,-128.03 795.16,-128.03 752.68,-114.02 752.68,-94.2 795.16,-80.19 855.24,-80.19 897.72,-94.2"/>
<text text-anchor="middle" x="825.2" y="-96.74" font-family="Times New Roman,serif" font-size="20.00">Sequence</text>
</g>
<!-- 87355232&#45;8ad6&#45;484e&#45;b363&#45;38536e737846&#45;&gt;b64db1a4&#45;d79f&#45;47b4&#45;99db&#45;f184b38d1361 -->
<g id="edge6" class="edge">
<title>87355232&#45;8ad6&#45;484e&#45;b363&#45;38536e737846&#45;&gt;b64db1a4&#45;d79f&#45;47b4&#45;99db&#45;f184b38d1361</title>
<path fill="none" stroke="black" d="M825.2,-163.59C825.2,-155.97 825.2,-147.74 825.2,-139.93"/>
<polygon fill="black" stroke="black" points="828.7,-140.04 825.2,-130.04 821.7,-140.04 828.7,-140.04"/>
</g>
<!-- 8108bcba&#45;dbeb&#45;4784&#45;8f1f&#45;eb9ede4ffb0e -->
<g id="node10" class="node">
<title>8108bcba&#45;dbeb&#45;4784&#45;8f1f&#45;eb9ede4ffb0e</title>
<polygon fill="orange" stroke="black" points="1264.72,-94.2 1264.72,-114.02 1222.24,-128.03 1162.16,-128.03 1119.68,-114.02 1119.68,-94.2 1162.16,-80.19 1222.24,-80.19 1264.72,-94.2"/>
<text text-anchor="middle" x="1192.2" y="-96.74" font-family="Times New Roman,serif" font-size="20.00">Sequence</text>
</g>
<!-- 87355232&#45;8ad6&#45;484e&#45;b363&#45;38536e737846&#45;&gt;8108bcba&#45;dbeb&#45;4784&#45;8f1f&#45;eb9ede4ffb0e -->
<g id="edge9" class="edge">
<title>87355232&#45;8ad6&#45;484e&#45;b363&#45;38536e737846&#45;&gt;8108bcba&#45;dbeb&#45;4784&#45;8f1f&#45;eb9ede4ffb0e</title>
<path fill="none" stroke="black" d="M874.69,-182.25C938.8,-166.68 1050.9,-139.44 1123.3,-121.85"/>
<polygon fill="black" stroke="black" points="1123.77,-125.34 1132.66,-119.58 1122.11,-118.54 1123.77,-125.34"/>
</g>
<!-- e65ce322&#45;edaa&#45;4677&#45;ab68&#45;4795e57648da -->
<g id="node14" class="node">
<title>e65ce322&#45;edaa&#45;4677&#45;ab68&#45;4795e57648da</title>
<polygon fill="orange" stroke="black" points="1674.72,-94.2 1674.72,-114.02 1632.24,-128.03 1572.16,-128.03 1529.68,-114.02 1529.68,-94.2 1572.16,-80.19 1632.24,-80.19 1674.72,-94.2"/>
<text text-anchor="middle" x="1602.2" y="-96.74" font-family="Times New Roman,serif" font-size="20.00">Sequence</text>
</g>
<!-- 87355232&#45;8ad6&#45;484e&#45;b363&#45;38536e737846&#45;&gt;e65ce322&#45;edaa&#45;4677&#45;ab68&#45;4795e57648da -->
<g id="edge13" class="edge">
<title>87355232&#45;8ad6&#45;484e&#45;b363&#45;38536e737846&#45;&gt;e65ce322&#45;edaa&#45;4677&#45;ab68&#45;4795e57648da</title>
<path fill="none" stroke="black" d="M888.12,-187.06C1027.4,-171.08 1361.75,-132.71 1518.47,-114.72"/>
<polygon fill="black" stroke="black" points="1518.4,-118.25 1527.94,-113.63 1517.61,-111.3 1518.4,-118.25"/>
</g>
<!-- 10ef3ff4&#45;7acb&#45;4991&#45;9e63&#45;6e489c3ef22d -->
<g id="node4" class="node">
<title>10ef3ff4&#45;7acb&#45;4991&#45;9e63&#45;6e489c3ef22d</title>
<ellipse fill="yellow" stroke="black" cx="114.2" cy="-22.1" rx="114.2" ry="22.1"/>
<text text-anchor="middle" x="114.2" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">Holding(Nothing)</text>
</g>
<!-- b900e9cb&#45;c0a8&#45;4e8d&#45;8a9b&#45;d871012abefb&#45;&gt;10ef3ff4&#45;7acb&#45;4991&#45;9e63&#45;6e489c3ef22d -->
<g id="edge3" class="edge">
<title>b900e9cb&#45;c0a8&#45;4e8d&#45;8a9b&#45;d871012abefb&#45;&gt;10ef3ff4&#45;7acb&#45;4991&#45;9e63&#45;6e489c3ef22d</title>
<path fill="none" stroke="black" d="M481.26,-87.23C471.95,-84.69 462.32,-82.24 453.2,-80.19 358.23,-58.91 333.16,-60.42 237.2,-44.19 228.06,-42.65 218.55,-41.03 209.03,-39.41"/>
<polygon fill="black" stroke="black" points="209.82,-35.99 199.38,-37.76 208.65,-42.89 209.82,-35.99"/>
</g>
<!-- a3869371&#45;404d&#45;4085&#45;932b&#45;232e188fb133 -->
<g id="node5" class="node">
<title>a3869371&#45;404d&#45;4085&#45;932b&#45;232e188fb133</title>
<ellipse fill="yellow" stroke="black" cx="317.2" cy="-22.1" rx="71.24" ry="22.1"/>
<text text-anchor="middle" x="317.2" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">Is(AC,On)</text>
</g>
<!-- b900e9cb&#45;c0a8&#45;4e8d&#45;8a9b&#45;d871012abefb&#45;&gt;a3869371&#45;404d&#45;4085&#45;932b&#45;232e188fb133 -->
<g id="edge4" class="edge">
<title>b900e9cb&#45;c0a8&#45;4e8d&#45;8a9b&#45;d871012abefb&#45;&gt;a3869371&#45;404d&#45;4085&#45;932b&#45;232e188fb133</title>
<path fill="none" stroke="black" d="M486.58,-85.55C453,-73.17 407.91,-56.55 372.7,-43.56"/>
<polygon fill="black" stroke="black" points="374.13,-40.36 363.53,-40.18 371.71,-46.93 374.13,-40.36"/>
</g>
<!-- 3a5cbe8f&#45;7672&#45;4a34&#45;91d1&#45;87502aed457c -->
<g id="node6" class="node">
<title>3a5cbe8f&#45;7672&#45;4a34&#45;91d1&#45;87502aed457c</title>
<polygon fill="lawngreen" stroke="black" points="661.82,-40.1 406.57,-40.1 406.57,-4.1 661.82,-4.1 661.82,-40.1"/>
<text text-anchor="middle" x="534.2" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">Turn(ACTemperature,Down)</text>
</g>
<!-- b900e9cb&#45;c0a8&#45;4e8d&#45;8a9b&#45;d871012abefb&#45;&gt;3a5cbe8f&#45;7672&#45;4a34&#45;91d1&#45;87502aed457c -->
<g id="edge5" class="edge">
<title>b900e9cb&#45;c0a8&#45;4e8d&#45;8a9b&#45;d871012abefb&#45;&gt;3a5cbe8f&#45;7672&#45;4a34&#45;91d1&#45;87502aed457c</title>
<path fill="none" stroke="black" d="M534.2,-79.97C534.2,-71.24 534.2,-61.2 534.2,-52.01"/>
<polygon fill="black" stroke="black" points="537.7,-52.11 534.2,-42.11 530.7,-52.11 537.7,-52.11"/>
</g>
<!-- c6eca6dd&#45;9fca&#45;4bd3&#45;b054&#45;9b43fe02613a -->
<g id="node8" class="node">
<title>c6eca6dd&#45;9fca&#45;4bd3&#45;b054&#45;9b43fe02613a</title>
<ellipse fill="yellow" stroke="black" cx="751.2" cy="-22.1" rx="71.24" ry="22.1"/>
<text text-anchor="middle" x="751.2" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">Is(AC,On)</text>
</g>
<!-- b64db1a4&#45;d79f&#45;47b4&#45;99db&#45;f184b38d1361&#45;&gt;c6eca6dd&#45;9fca&#45;4bd3&#45;b054&#45;9b43fe02613a -->
<g id="edge7" class="edge">
<title>b64db1a4&#45;d79f&#45;47b4&#45;99db&#45;f184b38d1361&#45;&gt;c6eca6dd&#45;9fca&#45;4bd3&#45;b054&#45;9b43fe02613a</title>
<path fill="none" stroke="black" d="M803.79,-79.97C795.77,-71.29 786.55,-61.33 778.1,-52.18"/>
<polygon fill="black" stroke="black" points="780.67,-49.81 771.31,-44.85 775.53,-54.56 780.67,-49.81"/>
</g>
<!-- df04f6f4&#45;d471&#45;4519&#45;ab9e&#45;5d5bd8dfbd4c -->
<g id="node9" class="node">
<title>df04f6f4&#45;d471&#45;4519&#45;ab9e&#45;5d5bd8dfbd4c</title>
<polygon fill="lawngreen" stroke="black" points="957.82,-40.1 840.57,-40.1 840.57,-4.1 957.82,-4.1 957.82,-40.1"/>
<text text-anchor="middle" x="899.2" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">FreeHands()</text>
</g>
<!-- b64db1a4&#45;d79f&#45;47b4&#45;99db&#45;f184b38d1361&#45;&gt;df04f6f4&#45;d471&#45;4519&#45;ab9e&#45;5d5bd8dfbd4c -->
<g id="edge8" class="edge">
<title>b64db1a4&#45;d79f&#45;47b4&#45;99db&#45;f184b38d1361&#45;&gt;df04f6f4&#45;d471&#45;4519&#45;ab9e&#45;5d5bd8dfbd4c</title>
<path fill="none" stroke="black" d="M846.6,-79.97C855.58,-70.26 866.06,-58.93 875.29,-48.94"/>
<polygon fill="black" stroke="black" points="877.77,-51.42 881.99,-41.71 872.63,-46.67 877.77,-51.42"/>
</g>
<!-- 82a23405&#45;c3c6&#45;47dc&#45;bf7b&#45;0636e3efe52c -->
<g id="node11" class="node">
<title>82a23405&#45;c3c6&#45;47dc&#45;bf7b&#45;0636e3efe52c</title>
<ellipse fill="yellow" stroke="black" cx="1090.2" cy="-22.1" rx="114.2" ry="22.1"/>
<text text-anchor="middle" x="1090.2" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">Holding(Nothing)</text>
</g>
<!-- 8108bcba&#45;dbeb&#45;4784&#45;8f1f&#45;eb9ede4ffb0e&#45;&gt;82a23405&#45;c3c6&#45;47dc&#45;bf7b&#45;0636e3efe52c -->
<g id="edge10" class="edge">
<title>8108bcba&#45;dbeb&#45;4784&#45;8f1f&#45;eb9ede4ffb0e&#45;&gt;82a23405&#45;c3c6&#45;47dc&#45;bf7b&#45;0636e3efe52c</title>
<path fill="none" stroke="black" d="M1162.42,-79.75C1150.89,-70.71 1137.61,-60.29 1125.6,-50.87"/>
<polygon fill="black" stroke="black" points="1127.93,-48.25 1117.9,-44.83 1123.61,-53.76 1127.93,-48.25"/>
</g>
<!-- 010d42ee&#45;18b3&#45;4a0e&#45;9be1&#45;eab67afaca60 -->
<g id="node12" class="node">
<title>010d42ee&#45;18b3&#45;4a0e&#45;9be1&#45;eab67afaca60</title>
<ellipse fill="yellow" stroke="black" cx="1294.2" cy="-22.1" rx="72.3" ry="22.1"/>
<text text-anchor="middle" x="1294.2" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">Is(AC,Off)</text>
</g>
<!-- 8108bcba&#45;dbeb&#45;4784&#45;8f1f&#45;eb9ede4ffb0e&#45;&gt;010d42ee&#45;18b3&#45;4a0e&#45;9be1&#45;eab67afaca60 -->
<g id="edge11" class="edge">
<title>8108bcba&#45;dbeb&#45;4784&#45;8f1f&#45;eb9ede4ffb0e&#45;&gt;010d42ee&#45;18b3&#45;4a0e&#45;9be1&#45;eab67afaca60</title>
<path fill="none" stroke="black" d="M1221.97,-79.75C1233.78,-70.49 1247.44,-59.78 1259.68,-50.18"/>
<polygon fill="black" stroke="black" points="1261.8,-52.96 1267.51,-44.03 1257.48,-47.45 1261.8,-52.96"/>
</g>
<!-- 90cdf2ff&#45;98b0&#45;4454&#45;803b&#45;feee5f5475bf -->
<g id="node13" class="node">
<title>90cdf2ff&#45;98b0&#45;4454&#45;803b&#45;feee5f5475bf</title>
<polygon fill="lawngreen" stroke="black" points="1511.7,-40.1 1384.7,-40.1 1384.7,-4.1 1511.7,-4.1 1511.7,-40.1"/>
<text text-anchor="middle" x="1448.2" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">Turn(AC,On)</text>
</g>
<!-- 8108bcba&#45;dbeb&#45;4784&#45;8f1f&#45;eb9ede4ffb0e&#45;&gt;90cdf2ff&#45;98b0&#45;4454&#45;803b&#45;feee5f5475bf -->
<g id="edge12" class="edge">
<title>8108bcba&#45;dbeb&#45;4784&#45;8f1f&#45;eb9ede4ffb0e&#45;&gt;90cdf2ff&#45;98b0&#45;4454&#45;803b&#45;feee5f5475bf</title>
<path fill="none" stroke="black" d="M1244,-86.92C1283.65,-74.53 1338.64,-57.34 1381.56,-43.93"/>
<polygon fill="black" stroke="black" points="1382.53,-47.29 1391.03,-40.96 1380.44,-40.61 1382.53,-47.29"/>
</g>
<!-- 7d0c1403&#45;c5d9&#45;4bcd&#45;a0db&#45;f3e527a3be93 -->
<g id="node15" class="node">
<title>7d0c1403&#45;c5d9&#45;4bcd&#45;a0db&#45;f3e527a3be93</title>
<ellipse fill="yellow" stroke="black" cx="1602.2" cy="-22.1" rx="72.3" ry="22.1"/>
<text text-anchor="middle" x="1602.2" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">Is(AC,Off)</text>
</g>
<!-- e65ce322&#45;edaa&#45;4677&#45;ab68&#45;4795e57648da&#45;&gt;7d0c1403&#45;c5d9&#45;4bcd&#45;a0db&#45;f3e527a3be93 -->
<g id="edge14" class="edge">
<title>e65ce322&#45;edaa&#45;4677&#45;ab68&#45;4795e57648da&#45;&gt;7d0c1403&#45;c5d9&#45;4bcd&#45;a0db&#45;f3e527a3be93</title>
<path fill="none" stroke="black" d="M1602.2,-79.97C1602.2,-72.46 1602.2,-63.99 1602.2,-55.92"/>
<polygon fill="black" stroke="black" points="1605.7,-56.06 1602.2,-46.06 1598.7,-56.06 1605.7,-56.06"/>
</g>
<!-- 931d4ea6&#45;c661&#45;4ea8&#45;9016&#45;2d4e17d30b19 -->
<g id="node16" class="node">
<title>931d4ea6&#45;c661&#45;4ea8&#45;9016&#45;2d4e17d30b19</title>
<polygon fill="lawngreen" stroke="black" points="1809.82,-40.1 1692.57,-40.1 1692.57,-4.1 1809.82,-4.1 1809.82,-40.1"/>
<text text-anchor="middle" x="1751.2" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">FreeHands()</text>
</g>
<!-- e65ce322&#45;edaa&#45;4677&#45;ab68&#45;4795e57648da&#45;&gt;931d4ea6&#45;c661&#45;4ea8&#45;9016&#45;2d4e17d30b19 -->
<g id="edge15" class="edge">
<title>e65ce322&#45;edaa&#45;4677&#45;ab68&#45;4795e57648da&#45;&gt;931d4ea6&#45;c661&#45;4ea8&#45;9016&#45;2d4e17d30b19</title>
<path fill="none" stroke="black" d="M1640.57,-82.51C1661.56,-71.23 1687.6,-57.25 1709.14,-45.68"/>
<polygon fill="black" stroke="black" points="1710.51,-48.92 1717.67,-41.1 1707.2,-42.75 1710.51,-48.92"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -215,12 +215,14 @@ class Scene:
"sub_goal_list": [], # 子目标列表
"status": None, # 仿真器中的观测信息,见下方详细解释
"condition_set": {'At(Robot,Bar)', 'Is(AC,Off)',
'Holding(Nothing)', 'Exist(Yogurt)', 'Exist(BottledDrink)',
'Exist(Softdrink)',
'Exist(Yogurt)', 'Exist(BottledDrink)','Exist(Softdrink)',
# 'On(Yogurt,Bar)','On(BottledDrink,Bar)',
# 'Exist(Softdrink)', 'On(Softdrink,Table1)',
'Exist(Chips)', 'Exist(NFCJuice)', 'Exist(Bernachon)', 'Exist(ADMilk)', 'Exist(SpringWater)',
# 'Holding(Nothing)',
'Holding(Coffee)',
'Exist(VacuumCup)', 'On(VacuumCup,Table2)',
'Is(HallLight,Off)', 'Is(TubeLight,On)', 'Is(Curtain,On)',
'Is(Table1,Dirty)', 'Is(Floor,Dirty)', 'Is(Chairs,Dirty)'},
@ -264,7 +266,7 @@ class Scene:
# 是否展示UI
self.show_ui = False
# 图像分割
self.take_picture = True
self.take_picture = False
self.map_ratio = 5
self.map_map = np.zeros((math.ceil(950 / self.map_ratio), math.ceil(1850 / self.map_ratio)))
self.db = DBSCAN(eps=self.map_ratio, min_samples=int(self.map_ratio / 2))
@ -272,6 +274,8 @@ class Scene:
self.is_nav_walk = False
self.bt_algo_opt = True
file_name = os.path.join(root_path,'robowaiter/algos/navigator/map_5.pkl')
if os.path.exists(file_name):
with open(file_name, 'rb') as file:
@ -451,6 +455,7 @@ class Scene:
print(f'event: {t}, {func.__name__}')
self.signal_event_list.pop(0)
self.last_event_time = self.time
print("==== *args ======:",*args)
func(*args)
def deal_event(self):
@ -474,6 +479,7 @@ class Scene:
def set_goal(self, goal):
g = eval("{'" + goal + "'}")
print("====== g =======:",g)
def set_sub_task():
self.state['chat_list'].append(("Goal", g))

View File

@ -0,0 +1,48 @@
"""
人提出请求机器人完成任务
1. 做咖啡固定动画接收到做咖啡指令走到咖啡机拿杯子操作咖啡机取杯子送到客人桌子上
2. 倒水
3. 夹点心
具体描述设计一套点单规则如菜单包含咖啡点心等按照规则拟造随机的订单在收到订单后通过大模型让机器人输出合理的备餐计划并尝试在模拟环境中按照这个规划实现任务
"""
import time
# todo: 接收点单信息,大模型生成任务规划
from robowaiter.scene.scene import Scene
class SceneOT(Scene):
def __init__(self, robot):
super().__init__(robot)
# 在这里加入场景中发生的事件
# self.event_list = [
# # (3, self.set_goal("On(VacuumCup,Bar)"))
# (3, self.set_goal("On(Yogurt,Bar)"))
# ]
self.signal_event_list =[
# (3, self.set_goal,("On(Yogurt,Bar)",)),
# (3, self.customer_say, ("System", "把盒装冰红茶放到水桌")),
(3, self.customer_say, ("System", "打开空调并降低空调温度")),
]
def _reset(self):
scene = self.add_walkers([[0, 0], [250, 1200], [-55, 750], [70, -200]])
pass
def _run(self):
pass
if __name__ == '__main__':
import os
from robowaiter.robot.robot import Robot
robot = Robot()
# create task
task = SceneOT(robot)
task.reset()
task.run()