重构代码,将tasks移到外层

This commit is contained in:
ChenXL97 2023-11-21 09:06:50 +08:00
parent 0b8ca87c08
commit 6183649218
94 changed files with 131 additions and 3218 deletions

View File

@ -14,45 +14,29 @@ pip install -e .
### 快速入门
1. 安装UE及Harix插件打开默认项目并运行
2. 运行 run_robowaiter.py 文件即可实现机器人控制端与仿真器的交互
2. 运行 tasks 文件夹下的任意场景即可实现机器人控制端与仿真器的交互
# 运行流程介绍
run_robowaiter.py 入口文件如下:
```python
import os
from robowaiter import Robot, task_map
# 代码框架介绍
TASK_NAME = 'GQA'
# create robot
project_path = "./robowaiter"
ptml_path = os.path.join(project_path, 'robot/Default.ptml')
behavior_lib_path = os.path.join(project_path, 'behavior_lib')
robot = Robot(ptml_path,behavior_lib_path)
# create task
task = task_map[TASK_NAME](robot)
task.reset()
task.run()
```
## Robot
Robot是机器人类包括从ptml加载行为树的方法以及执行行为树的方法等
## task_map
task_map是任务字典通过任务缩写来返回相应的场景类
## tasks
tasks文件夹中存放的场景定义及运行代码。
| 缩写 | 任务 |
|----|---------|
| AEM | 主动探索和记忆 |
| GQA | 具身多轮对话 |
| VLN | 视觉语言导航 |
| VLM | 视觉语言操作 |
| OT | 复杂开放任务 |
| AT | 自主任务 |
| 缩写 | 任务 |
|---------------------|-------------|
| AEM | 主动探索和记忆 |
| GQA | 具身多轮对话 |
| VLN | 视觉语言导航 |
| VLM | 视觉语言操作 |
| OT | 复杂开放任务 |
| AT | 自主任务 |
| CafeDailyOperations | 整体展示:咖啡厅的一天 |
| Interact | 命令行自由交互 |
## Scene

View File

@ -103,7 +103,7 @@ class Bahavior(ptree.behaviour.Behaviour):
# let behavior node interact with the scene
# let behavior node Interact with the scene
def set_scene(self, scene=None):
if scene:
self.scene = scene

View File

@ -9,7 +9,7 @@ ok, 有需要您再找我。
做一杯咖啡
好的,我马上做咖啡
create_sub_task
{"goal":"On(Coffee,CoffeeTable)"}00
{"goal":"On(Coffee,CoffeeTable)"}
不用了。
好的,您有需要再跟我说

View File

@ -306,9 +306,7 @@ class Scene:
return set_sub_task
def new_set_goal(self, goal):
g = eval("{'" + goal + "'}")
self.state['chat_list'].append(("Goal", g))
def new_set_goal(self,goal):
self.state['chat_list'].append(("Goal",goal))

View File

@ -1,106 +0,0 @@
"""
视觉语言导航
识别顾客NPC靠近打招呼对话领位导航到适合人数的空闲餐桌
开始条件监测到顾客靠近
结束条件完成领位语音请问您想喝点什么并等待下一步指令
"""
import os
import pickle
import time
import random
import matplotlib.pyplot as plt
import numpy as np
from robowaiter.scene.scene import Scene,init_world # TODO: 文件名改成Scene.py
from robowaiter.scene.scene import Scene
from robowaiter.utils import get_root_path
from robowaiter.algos.navigator.navigate import Navigator
from robowaiter.algos.navigator import test
class SceneVLN(Scene):
def __init__(self, robot):
super().__init__(robot)
# 在这里加入场景中发生的事件, (事件发生的时间,事件函数)
self.event_list = [
(5, self.create_chat_event("测试VLN前往2号桌")),
]
def _reset(self):
root_path = get_root_path()
file_name = os.path.join(root_path,'robowaiter/algos/navigator/map_5.pkl')
with open(file_name, 'rb') as file:
map = pickle.load(file)
self.state['map']['2d'] = map
self.state['map']['obj_pos']['Table'] = np.array((-100, 700))
def _run(self):
file_name = '../../algos/navigator/map_5.pkl'
if os.path.exists(file_name):
with open(file_name, 'rb') as file:
map = pickle.load(file)
# self.init_world(1, 11)
# scene = self.status
navigator = Navigator(scene=self, area_range=[-350, 600, -400, 1450], map=map)
'''场景1: 无行人环境 robot到达指定目标'''
# goal = np.array((-100, 700))
'''场景2: 静止行人环境 robot到达指定目标'''
# scene.clean_walker()
# scene.add_walker(50, 300, 0)
# scene.add_walker(-50, 500, 0)
# goal = np.array((-100, 700))
'''场景3: 移动行人环境 robot到达指定目标'''
self.walk_to(100, 0, -90, dis_limit=10)
self.clean_walker()
self.add_walkers([[50, 300], [-50, 500], [0, 700]])
# scene.add_walker(50, 300, 0)
# scene.add_walker(-50, 500, 0)
# scene.add_walker(0, 700, 0)
self.control_walker(
[self.walker_control_generator(walkerID=0, autowalk=False, speed=50, X=-50, Y=600, Yaw=0)])
self.control_walker(
[self.walker_control_generator(walkerID=1, autowalk=False, speed=50, X=100, Y=150, Yaw=0)])
self.control_walker([self.walker_control_generator(walkerID=2, autowalk=False, speed=50, X=0, Y=0, Yaw=0)])
# goal = (-100, 700)
# goal = (-300)
# goal = (340.0, 900.0)
# goal = (240.0, 1000.0)
# goal = (340.0, 900.0)
goal = (240.0, 1160.0)
'''场景4: 行人自由移动 robot到达指定目标'''
# # TODO: autowalk=True仿真器会闪退 ???
# scene.clean_walker()
# scene.add_walker(50, 300, 0)
# scene.add_walker(-50, 500, 0)
# scene.control_walker([scene.walker_control_generator(walkerID=0, autowalk=True, speed=20, X=0, Y=0, Yaw=0)])
# scene.control_walker([scene.walker_control_generator(walkerID=1, autowalk=True, speed=20, X=0, Y=0, Yaw=0)])
# time.sleep(5)
# goal = np.array((-100, 700))
navigator.navigate(goal, animation=False)
self.clean_walker()
print(self.status.collision) # TODO: 不显示碰撞信息 ???
pass
if __name__ == '__main__':
import os
from robowaiter.robot.robot import Robot
robot = Robot()
# create task
task = SceneVLN(robot)
task.reset()
task.run()

View File

@ -1,17 +1,10 @@
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()
sequence{
cond Holding(Nothing)
sequence{
cond Is(Curtain,Off)
act Turn(Curtain,On)
}
sequence{
cond Is(AC,Off)
act Turn(AC,On)
}}

View File

@ -2,27 +2,28 @@ selector
{
sequence
{
cond CustomerChatting()
cond Chatting()
act DealChat()
} sequence
} sequence
{
cond HasSubTask()
sequence
{
act SubTaskPlaceHolder()
} sequence
} } sequence
{
cond FocusingCustomer()
act ServeCustomer()
} sequence
} sequence
{
cond NewCustomerComing()
cond NewCustomer()
selector
{
cond At(Robot,Bar)
act MoveTo(Bar)
} act GreetCustomer()
}}
} act GreetCustomer()
} sequence
{
cond AnomalyDetected()
act ResolveAnomaly()
}}

View File

@ -3,37 +3,19 @@ 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";
"c9a8671e-b0b8-4587-a4de-a094fd678334" [fillcolor=orange, fontcolor=black, fontsize=20, height=0.01, label=Selector, shape=octagon, style=filled, width=0.01];
"bc597ff6-b3cb-4573-9dea-944fdb38d045" [fillcolor=yellow, fontcolor=black, fontsize=20, label="Holding(Nothing)", shape=ellipse, style=filled];
"c9a8671e-b0b8-4587-a4de-a094fd678334" -> "bc597ff6-b3cb-4573-9dea-944fdb38d045";
"a8e26121-f5cc-4ba5-b98e-86bd84de06d6" [fillcolor=orange, fontcolor=black, fontsize=20, height=0.01, label=Sequence, shape=octagon, style=filled, width=0.01];
"c9a8671e-b0b8-4587-a4de-a094fd678334" -> "a8e26121-f5cc-4ba5-b98e-86bd84de06d6";
"676d8bda-2c30-44a5-bca2-ade68761403a" [fillcolor=yellow, fontcolor=black, fontsize=20, label="Is(Curtain,Off)", shape=ellipse, style=filled];
"a8e26121-f5cc-4ba5-b98e-86bd84de06d6" -> "676d8bda-2c30-44a5-bca2-ade68761403a";
"c3d096cf-f848-46a3-9497-5398614798e8" [fillcolor=lawngreen, fontcolor=black, fontsize=20, label="Turn(Curtain,On)", shape=box, style=filled];
"a8e26121-f5cc-4ba5-b98e-86bd84de06d6" -> "c3d096cf-f848-46a3-9497-5398614798e8";
"400b4104-ff96-4d64-89b2-49dc6e4e3cbd" [fillcolor=orange, fontcolor=black, fontsize=20, height=0.01, label=Sequence, shape=octagon, style=filled, width=0.01];
"c9a8671e-b0b8-4587-a4de-a094fd678334" -> "400b4104-ff96-4d64-89b2-49dc6e4e3cbd";
"3fc48afc-1cef-45f5-826d-2571d7979a2f" [fillcolor=yellow, fontcolor=black, fontsize=20, label="Is(AC,Off)", shape=ellipse, style=filled];
"400b4104-ff96-4d64-89b2-49dc6e4e3cbd" -> "3fc48afc-1cef-45f5-826d-2571d7979a2f";
"47af4df0-8811-45a5-95e2-f0fc9458ddfd" [fillcolor=lawngreen, fontcolor=black, fontsize=20, label="Turn(AC,On)", shape=box, style=filled];
"400b4104-ff96-4d64-89b2-49dc6e4e3cbd" -> "47af4df0-8811-45a5-95e2-f0fc9458ddfd";
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -4,208 +4,100 @@
<!-- Generated by graphviz version 9.0.0 (20230911.1827)
-->
<!-- Title: pastafarianism Pages: 1 -->
<svg width="1699pt" height="417pt"
viewBox="0.00 0.00 1699.49 416.87" 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 412.87)">
<svg width="716pt" height="220pt"
viewBox="0.00 0.00 715.70 219.87" 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 215.87)">
<title>pastafarianism</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-412.87 1695.49,-412.87 1695.49,4 -4,4"/>
<!-- a3ac082f&#45;ad46&#45;4cc9&#45;86b4&#45;3e76c3c564d3 -->
<polygon fill="white" stroke="none" points="-4,4 -4,-215.87 711.7,-215.87 711.7,4 -4,4"/>
<!-- c9a8671e&#45;b0b8&#45;4587&#45;a4de&#45;a094fd678334 -->
<g id="node1" class="node">
<title>a3ac082f&#45;ad46&#45;4cc9&#45;86b4&#45;3e76c3c564d3</title>
<polygon fill="cyan" stroke="black" points="495.87,-408.87 412.37,-377.62 495.87,-346.37 579.37,-377.62 495.87,-408.87"/>
<text text-anchor="middle" x="495.87" y="-370.24" font-family="Times New Roman,serif" font-size="20.00">Selector</text>
<title>c9a8671e&#45;b0b8&#45;4587&#45;a4de&#45;a094fd678334</title>
<polygon fill="orange" stroke="black" points="383.11,-178.04 383.11,-197.85 345.67,-211.87 292.73,-211.87 255.29,-197.85 255.29,-178.04 292.73,-164.03 345.67,-164.03 383.11,-178.04"/>
<text text-anchor="middle" x="319.2" y="-180.57" font-family="Times New Roman,serif" font-size="20.00">Selector</text>
</g>
<!-- 717a1290&#45;56bc&#45;41e1&#45;9b4b&#45;e6df93d40e64 -->
<!-- bc597ff6&#45;b3cb&#45;4573&#45;9dea&#45;944fdb38d045 -->
<g id="node2" class="node">
<title>717a1290&#45;56bc&#45;41e1&#45;9b4b&#45;e6df93d40e64</title>
<polygon fill="orange" stroke="black" points="395.38,-276.54 395.38,-296.35 352.9,-310.37 292.83,-310.37 250.35,-296.35 250.35,-276.54 292.83,-262.53 352.9,-262.53 395.38,-276.54"/>
<text text-anchor="middle" x="322.87" y="-279.07" font-family="Times New Roman,serif" font-size="20.00">Sequence</text>
<title>bc597ff6&#45;b3cb&#45;4573&#45;9dea&#45;944fdb38d045</title>
<ellipse fill="yellow" stroke="black" cx="114.2" cy="-104.11" rx="114.2" ry="22.1"/>
<text text-anchor="middle" x="114.2" y="-96.74" font-family="Times New Roman,serif" font-size="20.00">Holding(Nothing)</text>
</g>
<!-- a3ac082f&#45;ad46&#45;4cc9&#45;86b4&#45;3e76c3c564d3&#45;&gt;717a1290&#45;56bc&#45;41e1&#45;9b4b&#45;e6df93d40e64 -->
<!-- c9a8671e&#45;b0b8&#45;4587&#45;a4de&#45;a094fd678334&#45;&gt;bc597ff6&#45;b3cb&#45;4573&#45;9dea&#45;944fdb38d045 -->
<g id="edge1" class="edge">
<title>a3ac082f&#45;ad46&#45;4cc9&#45;86b4&#45;3e76c3c564d3&#45;&gt;717a1290&#45;56bc&#45;41e1&#45;9b4b&#45;e6df93d40e64</title>
<path fill="none" stroke="black" d="M461.27,-358.78C435.8,-345.66 400.81,-327.62 372.38,-312.97"/>
<polygon fill="black" stroke="black" points="374.07,-309.9 363.58,-308.43 370.87,-316.13 374.07,-309.9"/>
<title>c9a8671e&#45;b0b8&#45;4587&#45;a4de&#45;a094fd678334&#45;&gt;bc597ff6&#45;b3cb&#45;4573&#45;9dea&#45;944fdb38d045</title>
<path fill="none" stroke="black" d="M276.22,-169.79C246.35,-157.87 206.15,-141.82 173.26,-128.69"/>
<polygon fill="black" stroke="black" points="174.86,-125.56 164.27,-125.1 172.26,-132.06 174.86,-125.56"/>
</g>
<!-- ff83c742&#45;a2ba&#45;4aa5&#45;8b3a&#45;39ecd7c03b0e -->
<g id="node5" class="node">
<title>ff83c742&#45;a2ba&#45;4aa5&#45;8b3a&#45;39ecd7c03b0e</title>
<polygon fill="orange" stroke="black" points="742.38,-276.54 742.38,-296.35 699.9,-310.37 639.83,-310.37 597.35,-296.35 597.35,-276.54 639.83,-262.53 699.9,-262.53 742.38,-276.54"/>
<text text-anchor="middle" x="669.87" y="-279.07" font-family="Times New Roman,serif" font-size="20.00">Sequence</text>
</g>
<!-- a3ac082f&#45;ad46&#45;4cc9&#45;86b4&#45;3e76c3c564d3&#45;&gt;ff83c742&#45;a2ba&#45;4aa5&#45;8b3a&#45;39ecd7c03b0e -->
<g id="edge4" class="edge">
<title>a3ac082f&#45;ad46&#45;4cc9&#45;86b4&#45;3e76c3c564d3&#45;&gt;ff83c742&#45;a2ba&#45;4aa5&#45;8b3a&#45;39ecd7c03b0e</title>
<path fill="none" stroke="black" d="M530.24,-359C556.02,-345.79 591.68,-327.51 620.51,-312.74"/>
<polygon fill="black" stroke="black" points="621.74,-316.04 629.04,-308.37 618.55,-309.81 621.74,-316.04"/>
</g>
<!-- b3236b13&#45;d5f2&#45;4643&#45;ae7c&#45;6f27bd4ab6f2 -->
<!-- a8e26121&#45;f5cc&#45;4ba5&#45;b98e&#45;86bd84de06d6 -->
<g id="node3" class="node">
<title>b3236b13&#45;d5f2&#45;4643&#45;ae7c&#45;6f27bd4ab6f2</title>
<ellipse fill="yellow" stroke="black" cx="125.87" cy="-202.61" rx="125.87" ry="22.1"/>
<text text-anchor="middle" x="125.87" y="-195.24" font-family="Times New Roman,serif" font-size="20.00">CustomerChatting()</text>
<title>a8e26121&#45;f5cc&#45;4ba5&#45;b98e&#45;86bd84de06d6</title>
<polygon fill="orange" stroke="black" points="391.72,-94.2 391.72,-114.02 349.24,-128.03 289.16,-128.03 246.68,-114.02 246.68,-94.2 289.16,-80.19 349.24,-80.19 391.72,-94.2"/>
<text text-anchor="middle" x="319.2" y="-96.74" font-family="Times New Roman,serif" font-size="20.00">Sequence</text>
</g>
<!-- 717a1290&#45;56bc&#45;41e1&#45;9b4b&#45;e6df93d40e64&#45;&gt;b3236b13&#45;d5f2&#45;4643&#45;ae7c&#45;6f27bd4ab6f2 -->
<!-- c9a8671e&#45;b0b8&#45;4587&#45;a4de&#45;a094fd678334&#45;&gt;a8e26121&#45;f5cc&#45;4ba5&#45;b98e&#45;86bd84de06d6 -->
<g id="edge2" class="edge">
<title>717a1290&#45;56bc&#45;41e1&#45;9b4b&#45;e6df93d40e64&#45;&gt;b3236b13&#45;d5f2&#45;4643&#45;ae7c&#45;6f27bd4ab6f2</title>
<path fill="none" stroke="black" d="M278.16,-266.88C250.24,-255.28 213.99,-240.22 183.86,-227.7"/>
<polygon fill="black" stroke="black" points="185.46,-224.58 174.88,-223.97 182.77,-231.04 185.46,-224.58"/>
<title>c9a8671e&#45;b0b8&#45;4587&#45;a4de&#45;a094fd678334&#45;&gt;a8e26121&#45;f5cc&#45;4ba5&#45;b98e&#45;86bd84de06d6</title>
<path fill="none" stroke="black" d="M319.2,-163.72C319.2,-156.29 319.2,-147.89 319.2,-139.83"/>
<polygon fill="black" stroke="black" points="322.7,-139.92 319.2,-129.92 315.7,-139.92 322.7,-139.92"/>
</g>
<!-- 28015225&#45;b7a4&#45;4f38&#45;b26f&#45;4dbe5eea4154 -->
<g id="node4" class="node">
<title>28015225&#45;b7a4&#45;4f38&#45;b26f&#45;4dbe5eea4154</title>
<polygon fill="lawngreen" stroke="black" points="376.24,-220.61 269.49,-220.61 269.49,-184.61 376.24,-184.61 376.24,-220.61"/>
<text text-anchor="middle" x="322.87" y="-195.24" font-family="Times New Roman,serif" font-size="20.00">DealChat()</text>
</g>
<!-- 717a1290&#45;56bc&#45;41e1&#45;9b4b&#45;e6df93d40e64&#45;&gt;28015225&#45;b7a4&#45;4f38&#45;b26f&#45;4dbe5eea4154 -->
<g id="edge3" class="edge">
<title>717a1290&#45;56bc&#45;41e1&#45;9b4b&#45;e6df93d40e64&#45;&gt;28015225&#45;b7a4&#45;4f38&#45;b26f&#45;4dbe5eea4154</title>
<path fill="none" stroke="black" d="M322.87,-262.22C322.87,-252.88 322.87,-242.01 322.87,-232.2"/>
<polygon fill="black" stroke="black" points="326.37,-232.43 322.87,-222.43 319.37,-232.43 326.37,-232.43"/>
</g>
<!-- 2f77f976&#45;499c&#45;4601&#45;9d8c&#45;86dd80d66dfa -->
<!-- 400b4104&#45;ff96&#45;4d64&#45;89b2&#45;49dc6e4e3cbd -->
<g id="node6" class="node">
<title>2f77f976&#45;499c&#45;4601&#45;9d8c&#45;86dd80d66dfa</title>
<ellipse fill="yellow" stroke="black" cx="486.87" cy="-202.61" rx="92.45" ry="22.1"/>
<text text-anchor="middle" x="486.87" y="-195.24" font-family="Times New Roman,serif" font-size="20.00">HasSubTask()</text>
<title>400b4104&#45;ff96&#45;4d64&#45;89b2&#45;49dc6e4e3cbd</title>
<polygon fill="orange" stroke="black" points="562.72,-94.2 562.72,-114.02 520.24,-128.03 460.16,-128.03 417.68,-114.02 417.68,-94.2 460.16,-80.19 520.24,-80.19 562.72,-94.2"/>
<text text-anchor="middle" x="490.2" y="-96.74" font-family="Times New Roman,serif" font-size="20.00">Sequence</text>
</g>
<!-- ff83c742&#45;a2ba&#45;4aa5&#45;8b3a&#45;39ecd7c03b0e&#45;&gt;2f77f976&#45;499c&#45;4601&#45;9d8c&#45;86dd80d66dfa -->
<!-- c9a8671e&#45;b0b8&#45;4587&#45;a4de&#45;a094fd678334&#45;&gt;400b4104&#45;ff96&#45;4d64&#45;89b2&#45;49dc6e4e3cbd -->
<g id="edge5" class="edge">
<title>ff83c742&#45;a2ba&#45;4aa5&#45;8b3a&#45;39ecd7c03b0e&#45;&gt;2f77f976&#45;499c&#45;4601&#45;9d8c&#45;86dd80d66dfa</title>
<path fill="none" stroke="black" d="M626.96,-266.26C600.92,-254.61 567.48,-239.66 539.8,-227.28"/>
<polygon fill="black" stroke="black" points="541.44,-224.18 530.88,-223.3 538.58,-230.57 541.44,-224.18"/>
<title>c9a8671e&#45;b0b8&#45;4587&#45;a4de&#45;a094fd678334&#45;&gt;400b4104&#45;ff96&#45;4d64&#45;89b2&#45;49dc6e4e3cbd</title>
<path fill="none" stroke="black" d="M358,-168.38C382.01,-156.89 413.11,-142.01 439.11,-129.56"/>
<polygon fill="black" stroke="black" points="440.29,-132.88 447.8,-125.4 437.27,-126.56 440.29,-132.88"/>
</g>
<!-- 2428792c&#45;3896&#45;443d&#45;8744&#45;f5e286644fad -->
<!-- 676d8bda&#45;2c30&#45;44a5&#45;bca2&#45;ade68761403a -->
<g id="node4" class="node">
<title>676d8bda&#45;2c30&#45;44a5&#45;bca2&#45;ade68761403a</title>
<ellipse fill="yellow" stroke="black" cx="124.2" cy="-22.1" rx="96.17" ry="22.1"/>
<text text-anchor="middle" x="124.2" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">Is(Curtain,Off)</text>
</g>
<!-- a8e26121&#45;f5cc&#45;4ba5&#45;b98e&#45;86bd84de06d6&#45;&gt;676d8bda&#45;2c30&#45;44a5&#45;bca2&#45;ade68761403a -->
<g id="edge3" class="edge">
<title>a8e26121&#45;f5cc&#45;4ba5&#45;b98e&#45;86bd84de06d6&#45;&gt;676d8bda&#45;2c30&#45;44a5&#45;bca2&#45;ade68761403a</title>
<path fill="none" stroke="black" d="M274.46,-84.75C246.5,-73.28 210.25,-58.41 180.36,-46.14"/>
<polygon fill="black" stroke="black" points="182.06,-43.06 171.48,-42.5 179.4,-49.53 182.06,-43.06"/>
</g>
<!-- c3d096cf&#45;f848&#45;46a3&#45;9497&#45;5398614798e8 -->
<g id="node5" class="node">
<title>c3d096cf&#45;f848&#45;46a3&#45;9497&#45;5398614798e8</title>
<polygon fill="lawngreen" stroke="black" points="399.57,-40.1 238.82,-40.1 238.82,-4.1 399.57,-4.1 399.57,-40.1"/>
<text text-anchor="middle" x="319.2" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">Turn(Curtain,On)</text>
</g>
<!-- a8e26121&#45;f5cc&#45;4ba5&#45;b98e&#45;86bd84de06d6&#45;&gt;c3d096cf&#45;f848&#45;46a3&#45;9497&#45;5398614798e8 -->
<g id="edge4" class="edge">
<title>a8e26121&#45;f5cc&#45;4ba5&#45;b98e&#45;86bd84de06d6&#45;&gt;c3d096cf&#45;f848&#45;46a3&#45;9497&#45;5398614798e8</title>
<path fill="none" stroke="black" d="M319.2,-79.97C319.2,-71.24 319.2,-61.2 319.2,-52.01"/>
<polygon fill="black" stroke="black" points="322.7,-52.11 319.2,-42.11 315.7,-52.11 322.7,-52.11"/>
</g>
<!-- 3fc48afc&#45;1cef&#45;45f5&#45;826d&#45;2571d7979a2f -->
<g id="node7" class="node">
<title>2428792c&#45;3896&#45;443d&#45;8744&#45;f5e286644fad</title>
<polygon fill="orange" stroke="black" points="742.38,-192.7 742.38,-212.52 699.9,-226.53 639.83,-226.53 597.35,-212.52 597.35,-192.7 639.83,-178.69 699.9,-178.69 742.38,-192.7"/>
<text text-anchor="middle" x="669.87" y="-195.24" font-family="Times New Roman,serif" font-size="20.00">Sequence</text>
<title>3fc48afc&#45;1cef&#45;45f5&#45;826d&#45;2571d7979a2f</title>
<ellipse fill="yellow" stroke="black" cx="490.2" cy="-22.1" rx="72.3" ry="22.1"/>
<text text-anchor="middle" x="490.2" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">Is(AC,Off)</text>
</g>
<!-- ff83c742&#45;a2ba&#45;4aa5&#45;8b3a&#45;39ecd7c03b0e&#45;&gt;2428792c&#45;3896&#45;443d&#45;8744&#45;f5e286644fad -->
<!-- 400b4104&#45;ff96&#45;4d64&#45;89b2&#45;49dc6e4e3cbd&#45;&gt;3fc48afc&#45;1cef&#45;45f5&#45;826d&#45;2571d7979a2f -->
<g id="edge6" class="edge">
<title>ff83c742&#45;a2ba&#45;4aa5&#45;8b3a&#45;39ecd7c03b0e&#45;&gt;2428792c&#45;3896&#45;443d&#45;8744&#45;f5e286644fad</title>
<path fill="none" stroke="black" d="M669.87,-262.22C669.87,-254.79 669.87,-246.39 669.87,-238.33"/>
<polygon fill="black" stroke="black" points="673.37,-238.42 669.87,-228.42 666.37,-238.42 673.37,-238.42"/>
<title>400b4104&#45;ff96&#45;4d64&#45;89b2&#45;49dc6e4e3cbd&#45;&gt;3fc48afc&#45;1cef&#45;45f5&#45;826d&#45;2571d7979a2f</title>
<path fill="none" stroke="black" d="M490.2,-79.97C490.2,-72.46 490.2,-63.99 490.2,-55.92"/>
<polygon fill="black" stroke="black" points="493.7,-56.06 490.2,-46.06 486.7,-56.06 493.7,-56.06"/>
</g>
<!-- 64b2362a&#45;d99e&#45;4e99&#45;8772&#45;ad1419e53a2e -->
<g id="node9" class="node">
<title>64b2362a&#45;d99e&#45;4e99&#45;8772&#45;ad1419e53a2e</title>
<polygon fill="orange" stroke="black" points="905.38,-192.7 905.38,-212.52 862.9,-226.53 802.83,-226.53 760.35,-212.52 760.35,-192.7 802.83,-178.69 862.9,-178.69 905.38,-192.7"/>
<text text-anchor="middle" x="832.87" y="-195.24" font-family="Times New Roman,serif" font-size="20.00">Sequence</text>
</g>
<!-- ff83c742&#45;a2ba&#45;4aa5&#45;8b3a&#45;39ecd7c03b0e&#45;&gt;64b2362a&#45;d99e&#45;4e99&#45;8772&#45;ad1419e53a2e -->
<g id="edge8" class="edge">
<title>ff83c742&#45;a2ba&#45;4aa5&#45;8b3a&#45;39ecd7c03b0e&#45;&gt;64b2362a&#45;d99e&#45;4e99&#45;8772&#45;ad1419e53a2e</title>
<path fill="none" stroke="black" d="M709.74,-265.43C731.74,-254.38 759.28,-240.56 782.73,-228.78"/>
<polygon fill="black" stroke="black" points="784.12,-232 791.48,-224.39 780.98,-225.75 784.12,-232"/>
</g>
<!-- bea12066&#45;ecbd&#45;49b0&#45;8934&#45;efcb2c38b5f5 -->
<g id="node12" class="node">
<title>bea12066&#45;ecbd&#45;49b0&#45;8934&#45;efcb2c38b5f5</title>
<polygon fill="orange" stroke="black" points="1384.38,-192.7 1384.38,-212.52 1341.9,-226.53 1281.83,-226.53 1239.35,-212.52 1239.35,-192.7 1281.83,-178.69 1341.9,-178.69 1384.38,-192.7"/>
<text text-anchor="middle" x="1311.87" y="-195.24" font-family="Times New Roman,serif" font-size="20.00">Sequence</text>
</g>
<!-- ff83c742&#45;a2ba&#45;4aa5&#45;8b3a&#45;39ecd7c03b0e&#45;&gt;bea12066&#45;ecbd&#45;49b0&#45;8934&#45;efcb2c38b5f5 -->
<g id="edge11" class="edge">
<title>ff83c742&#45;a2ba&#45;4aa5&#45;8b3a&#45;39ecd7c03b0e&#45;&gt;bea12066&#45;ecbd&#45;49b0&#45;8934&#45;efcb2c38b5f5</title>
<path fill="none" stroke="black" d="M742.57,-276.18C862.55,-260.89 1101.31,-230.45 1228.15,-214.28"/>
<polygon fill="black" stroke="black" points="1228.34,-217.79 1237.82,-213.05 1227.46,-210.84 1228.34,-217.79"/>
</g>
<!-- 4bb7a9c3&#45;521b&#45;408f&#45;b403&#45;1fd25d54b192 -->
<!-- 47af4df0&#45;8811&#45;45a5&#45;95e2&#45;f0fc9458ddfd -->
<g id="node8" class="node">
<title>4bb7a9c3&#45;521b&#45;408f&#45;b403&#45;1fd25d54b192</title>
<polygon fill="lawngreen" stroke="black" points="574.49,-129.44 373.24,-129.44 373.24,-93.44 574.49,-93.44 574.49,-129.44"/>
<text text-anchor="middle" x="473.87" y="-104.07" font-family="Times New Roman,serif" font-size="20.00">SubTaskPlaceHolder()</text>
<title>47af4df0&#45;8811&#45;45a5&#45;95e2&#45;f0fc9458ddfd</title>
<polygon fill="lawngreen" stroke="black" points="707.7,-40.1 580.7,-40.1 580.7,-4.1 707.7,-4.1 707.7,-40.1"/>
<text text-anchor="middle" x="644.2" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">Turn(AC,On)</text>
</g>
<!-- 2428792c&#45;3896&#45;443d&#45;8744&#45;f5e286644fad&#45;&gt;4bb7a9c3&#45;521b&#45;408f&#45;b403&#45;1fd25d54b192 -->
<!-- 400b4104&#45;ff96&#45;4d64&#45;89b2&#45;49dc6e4e3cbd&#45;&gt;47af4df0&#45;8811&#45;45a5&#45;95e2&#45;f0fc9458ddfd -->
<g id="edge7" class="edge">
<title>2428792c&#45;3896&#45;443d&#45;8744&#45;f5e286644fad&#45;&gt;4bb7a9c3&#45;521b&#45;408f&#45;b403&#45;1fd25d54b192</title>
<path fill="none" stroke="black" d="M627.82,-182.48C596.86,-168.4 554.7,-149.22 522.33,-134.49"/>
<polygon fill="black" stroke="black" points="524.12,-131.46 513.57,-130.51 521.22,-137.83 524.12,-131.46"/>
</g>
<!-- fd7124ba&#45;c9d1&#45;4fde&#45;8063&#45;e8337d335121 -->
<g id="node10" class="node">
<title>fd7124ba&#45;c9d1&#45;4fde&#45;8063&#45;e8337d335121</title>
<ellipse fill="yellow" stroke="black" cx="720.87" cy="-111.44" rx="128.52" ry="22.1"/>
<text text-anchor="middle" x="720.87" y="-104.07" font-family="Times New Roman,serif" font-size="20.00">FocusingCustomer()</text>
</g>
<!-- 64b2362a&#45;d99e&#45;4e99&#45;8772&#45;ad1419e53a2e&#45;&gt;fd7124ba&#45;c9d1&#45;4fde&#45;8063&#45;e8337d335121 -->
<g id="edge9" class="edge">
<title>64b2362a&#45;d99e&#45;4e99&#45;8772&#45;ad1419e53a2e&#45;&gt;fd7124ba&#45;c9d1&#45;4fde&#45;8063&#45;e8337d335121</title>
<path fill="none" stroke="black" d="M803.73,-178.42C789.1,-166.77 771.27,-152.57 755.9,-140.33"/>
<polygon fill="black" stroke="black" points="758.36,-137.82 748.36,-134.33 754,-143.3 758.36,-137.82"/>
</g>
<!-- 169ebec9&#45;3645&#45;4fbb&#45;a533&#45;5186a8e5967b -->
<g id="node11" class="node">
<title>169ebec9&#45;3645&#45;4fbb&#45;a533&#45;5186a8e5967b</title>
<polygon fill="lawngreen" stroke="black" points="1020.49,-129.44 867.24,-129.44 867.24,-93.44 1020.49,-93.44 1020.49,-129.44"/>
<text text-anchor="middle" x="943.87" y="-104.07" font-family="Times New Roman,serif" font-size="20.00">ServeCustomer()</text>
</g>
<!-- 64b2362a&#45;d99e&#45;4e99&#45;8772&#45;ad1419e53a2e&#45;&gt;169ebec9&#45;3645&#45;4fbb&#45;a533&#45;5186a8e5967b -->
<g id="edge10" class="edge">
<title>64b2362a&#45;d99e&#45;4e99&#45;8772&#45;ad1419e53a2e&#45;&gt;169ebec9&#45;3645&#45;4fbb&#45;a533&#45;5186a8e5967b</title>
<path fill="none" stroke="black" d="M861.74,-178.42C877.67,-165.62 897.45,-149.73 913.6,-136.76"/>
<polygon fill="black" stroke="black" points="915.36,-139.83 920.97,-130.84 910.98,-134.37 915.36,-139.83"/>
</g>
<!-- a847a0cc&#45;c5af&#45;4757&#45;aa8c&#45;8baef72788dc -->
<g id="node13" class="node">
<title>a847a0cc&#45;c5af&#45;4757&#45;aa8c&#45;8baef72788dc</title>
<ellipse fill="yellow" stroke="black" cx="1186.87" cy="-111.44" rx="148.14" ry="22.1"/>
<text text-anchor="middle" x="1186.87" y="-104.07" font-family="Times New Roman,serif" font-size="20.00">NewCustomerComing()</text>
</g>
<!-- bea12066&#45;ecbd&#45;49b0&#45;8934&#45;efcb2c38b5f5&#45;&gt;a847a0cc&#45;c5af&#45;4757&#45;aa8c&#45;8baef72788dc -->
<g id="edge12" class="edge">
<title>bea12066&#45;ecbd&#45;49b0&#45;8934&#45;efcb2c38b5f5&#45;&gt;a847a0cc&#45;c5af&#45;4757&#45;aa8c&#45;8baef72788dc</title>
<path fill="none" stroke="black" d="M1280,-178.88C1263.4,-167.04 1242.97,-152.46 1225.48,-139.99"/>
<polygon fill="black" stroke="black" points="1227.51,-137.14 1217.34,-134.18 1223.44,-142.84 1227.51,-137.14"/>
</g>
<!-- 99354f05&#45;1716&#45;46b2&#45;9151&#45;d88eac0a5b27 -->
<g id="node14" class="node">
<title>99354f05&#45;1716&#45;46b2&#45;9151&#45;d88eac0a5b27</title>
<polygon fill="cyan" stroke="black" points="1436.87,-142.69 1353.37,-111.44 1436.87,-80.19 1520.37,-111.44 1436.87,-142.69"/>
<text text-anchor="middle" x="1436.87" y="-104.07" font-family="Times New Roman,serif" font-size="20.00">Selector</text>
</g>
<!-- bea12066&#45;ecbd&#45;49b0&#45;8934&#45;efcb2c38b5f5&#45;&gt;99354f05&#45;1716&#45;46b2&#45;9151&#45;d88eac0a5b27 -->
<g id="edge13" class="edge">
<title>bea12066&#45;ecbd&#45;49b0&#45;8934&#45;efcb2c38b5f5&#45;&gt;99354f05&#45;1716&#45;46b2&#45;9151&#45;d88eac0a5b27</title>
<path fill="none" stroke="black" d="M1343.73,-178.88C1360.85,-166.67 1382.05,-151.54 1399.9,-138.81"/>
<polygon fill="black" stroke="black" points="1401.55,-141.94 1407.65,-133.28 1397.48,-136.24 1401.55,-141.94"/>
</g>
<!-- a3766a34&#45;5152&#45;4f82&#45;8fba&#45;8bf1f6b3830b -->
<g id="node17" class="node">
<title>a3766a34&#45;5152&#45;4f82&#45;8fba&#45;8bf1f6b3830b</title>
<polygon fill="lawngreen" stroke="black" points="1691.49,-129.44 1538.24,-129.44 1538.24,-93.44 1691.49,-93.44 1691.49,-129.44"/>
<text text-anchor="middle" x="1614.87" y="-104.07" font-family="Times New Roman,serif" font-size="20.00">GreetCustomer()</text>
</g>
<!-- bea12066&#45;ecbd&#45;49b0&#45;8934&#45;efcb2c38b5f5&#45;&gt;a3766a34&#45;5152&#45;4f82&#45;8fba&#45;8bf1f6b3830b -->
<g id="edge16" class="edge">
<title>bea12066&#45;ecbd&#45;49b0&#45;8934&#45;efcb2c38b5f5&#45;&gt;a3766a34&#45;5152&#45;4f82&#45;8fba&#45;8bf1f6b3830b</title>
<path fill="none" stroke="black" d="M1369.59,-187.32C1413.74,-176.07 1475.98,-159.54 1529.87,-142.69 1538.78,-139.91 1548.16,-136.78 1557.3,-133.61"/>
<polygon fill="black" stroke="black" points="1558.17,-137.02 1566.45,-130.4 1555.85,-130.41 1558.17,-137.02"/>
</g>
<!-- 19de10a3&#45;7554&#45;43a3&#45;b892&#45;34cb2e32ab9a -->
<g id="node15" class="node">
<title>19de10a3&#45;7554&#45;43a3&#45;b892&#45;34cb2e32ab9a</title>
<ellipse fill="yellow" stroke="black" cx="1347.87" cy="-22.1" rx="95.64" ry="22.1"/>
<text text-anchor="middle" x="1347.87" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">At(Robot,Bar)</text>
</g>
<!-- 99354f05&#45;1716&#45;46b2&#45;9151&#45;d88eac0a5b27&#45;&gt;19de10a3&#45;7554&#45;43a3&#45;b892&#45;34cb2e32ab9a -->
<g id="edge14" class="edge">
<title>99354f05&#45;1716&#45;46b2&#45;9151&#45;d88eac0a5b27&#45;&gt;19de10a3&#45;7554&#45;43a3&#45;b892&#45;34cb2e32ab9a</title>
<path fill="none" stroke="black" d="M1414.41,-88.4C1403.11,-77.32 1389.28,-63.74 1377.16,-51.84"/>
<polygon fill="black" stroke="black" points="1379.76,-49.5 1370.17,-44.99 1374.86,-54.49 1379.76,-49.5"/>
</g>
<!-- 4286d652&#45;c4ef&#45;4522&#45;a7f1&#45;b5c865dcc4c9 -->
<g id="node16" class="node">
<title>4286d652&#45;c4ef&#45;4522&#45;a7f1&#45;b5c865dcc4c9</title>
<polygon fill="lawngreen" stroke="black" points="1589.74,-40.1 1461.99,-40.1 1461.99,-4.1 1589.74,-4.1 1589.74,-40.1"/>
<text text-anchor="middle" x="1525.87" y="-14.72" font-family="Times New Roman,serif" font-size="20.00">MoveTo(Bar)</text>
</g>
<!-- 99354f05&#45;1716&#45;46b2&#45;9151&#45;d88eac0a5b27&#45;&gt;4286d652&#45;c4ef&#45;4522&#45;a7f1&#45;b5c865dcc4c9 -->
<g id="edge15" class="edge">
<title>99354f05&#45;1716&#45;46b2&#45;9151&#45;d88eac0a5b27&#45;&gt;4286d652&#45;c4ef&#45;4522&#45;a7f1&#45;b5c865dcc4c9</title>
<path fill="none" stroke="black" d="M1459.32,-88.4C1471.74,-76.21 1487.23,-61.02 1500.13,-48.35"/>
<polygon fill="black" stroke="black" points="1502.42,-51.01 1507.1,-41.51 1497.51,-46.02 1502.42,-51.01"/>
<title>400b4104&#45;ff96&#45;4d64&#45;89b2&#45;49dc6e4e3cbd&#45;&gt;47af4df0&#45;8811&#45;45a5&#45;95e2&#45;f0fc9458ddfd</title>
<path fill="none" stroke="black" d="M529.46,-82.71C551.25,-71.39 578.4,-57.28 600.82,-45.64"/>
<polygon fill="black" stroke="black" points="602.15,-48.89 609.41,-41.17 598.92,-42.68 602.15,-48.89"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -1,16 +0,0 @@
import os
from robowaiter import Robot, task_map
TASK_NAME = 'VLM'
# create robot
project_path = "./robowaiter"
ptml_path = os.path.join(project_path, 'robot/Default.ptml')
behavior_lib_path = os.path.join(project_path, 'behavior_lib')
robot = Robot(ptml_path, behavior_lib_path)
# create task
task = task_map[TASK_NAME](robot)
task.reset()
task.run()

View File

@ -1,31 +0,0 @@
selector{
sequence{
cond On(Coffee,CoffeeTable)
cond On(Coffee,CoffeeTable)
}
sequence{
cond Holding(Nothing)
act Make(Coffee)
}
sequence{
cond At(Robot,CoffeeTable)
cond Holding(Coffee)
act PutDown(Coffee,CoffeeTable)
}
sequence{
cond At(Robot,Bar)
cond Holding(Coffee)
act PutDown(Coffee,Bar)
}
sequence{
cond At(Robot,WaterTable)
cond Holding(Coffee)
act PutDown(Coffee,WaterTable)
}
sequence{
cond Holding(Coffee)
act MoveTo(CoffeeTable)
}
}

View File

@ -40,7 +40,7 @@ class SceneAEM(Scene):
map_ratio = self.map_ratio
db = DBSCAN(eps=map_ratio, min_samples=int(map_ratio / 2))
file_name = '../../proto/map_1.pkl'
file_name = '../../robowaiter/proto/map_1.pkl'
if os.path.exists(file_name):
with open(file_name, 'rb') as file:
map = pickle.load(file)
@ -117,7 +117,7 @@ class SceneAEM(Scene):
{"id": f"{i}", "name": f"{cur_objs[i].name}", "location": f"{cur_objs[i].location}",
"height": f"{cur_objs[i].location.Z}"})
with open('../../proto/objs.json', 'w') as file:
with open('../../robowaiter/proto/objs.json', 'w') as file:
json.dump(obj_json_data, file)
# for i in range(-350, 600):

View File

@ -1,10 +1,5 @@
"""
人提出请求机器人完成任务
1. 做咖啡固定动画接收到做咖啡指令走到咖啡机拿杯子操作咖啡机取杯子送到客人桌子上
2. 倒水
3. 夹点心
具体描述设计一套点单规则如菜单包含咖啡点心等按照规则拟造随机的订单在收到订单后通过大模型让机器人输出合理的备餐计划并尝试在模拟环境中按照这个规划实现任务
交互式场景输入
"""
@ -27,9 +22,9 @@ class SubScene(Scene):
question = input("请输入指令:")
if question[-1] == ")":
print(f"设置目标:{question}")
self.set_goal(question)()
self.new_set_goal(question)
else:
self.state['chat_list'].append(question)
self.customer_say("System",question)

View File

@ -3,8 +3,6 @@
测试导航算法的动态避障(Obstacle Detection and Avoidance, ODA)能力
"""
import os
import pickle

View File

@ -1,27 +0,0 @@
import py_trees as ptree
from typing import Any
# _base Behavior
class Bahavior(ptree.behaviour.Behaviour):
scene = None
def __init__(self, name: str, scene):
super().__init__(name)
self.scene = scene
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def _update(self) -> ptree.common.Status:
print("this is just a _base behavior node.")
def update(self) -> ptree.common.Status:
re = self._update()
print(f"{self.__class__.__name__}: {re.value}")
return re
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,23 +0,0 @@
import py_trees as ptree
from typing import Any
from robowaiter.behavior_lib._base.Behavior import Bahavior
class Chatting(Bahavior):
def __init__(self, name: str, scene):
super().__init__(name, scene)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def _update(self) -> ptree.common.Status:
# if self.scene.status?
if self.scene.state['chat_list'] == []:
return ptree.common.Status.FAILURE
else:
return ptree.common.Status.SUCCESS
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,20 +0,0 @@
import py_trees as ptree
from typing import Any
from robowaiter.behavior_lib._base.Behavior import Bahavior
class CoffeeCupFound(Bahavior):
def __init__(self, name: str, scene):
super().__init__(name, scene)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> ptree.common.Status:
print("Start checking IsChatting...")
return ptree.common.Status.SUCCESS
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,22 +0,0 @@
import py_trees as ptree
from typing import Any
from robowaiter.behavior_lib._base.Behavior import Bahavior
class CoffeeCupGrasped(Bahavior):
def __init__(self, name: str, scene):
super().__init__(name, scene)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> ptree.common.Status:
print('Start checking IsChatting...')
return ptree.common.Status.SUCCESS
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,21 +0,0 @@
import py_trees as ptree
from typing import Any
class CoffeeCupPlaced(ptree.behaviour.Behaviour):
def __init__(self, name: str, scene):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> ptree.common.Status:
print('Start checking IsChatting...')
return ptree.common.Status.SUCCESS
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,26 +0,0 @@
import py_trees as ptree
from typing import Any
from robowaiter.behavior_lib._base.Behavior import Bahavior
from robowaiter.llm_client.ask_llm import ask_llm
class DealChat(Bahavior):
def __init__(self, name: str, scene):
super().__init__(name, scene)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def _update(self) -> ptree.common.Status:
# if self.scene.status?
chat = self.scene.state['chat_list'].pop()
answer = ask_llm(chat)
print(f"机器人回答:{answer}")
self.scene.chat_bubble(f"机器人回答:{answer}")
return ptree.common.Status.RUNNING
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,21 +0,0 @@
import py_trees as ptree
from typing import Any
class DestinationAReached(ptree.behaviour.Behaviour):
def __init__(self, name: str, scene):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> ptree.common.Status:
print('Start checking IsChatting...')
return ptree.common.Status.SUCCESS
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,21 +0,0 @@
import py_trees as ptree
from typing import Any
class FindCoffeeCup(ptree.behaviour.Behaviour):
def __init__(self, name: str, scene):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> ptree.common.Status:
print('Start checking IsChatting...')
return ptree.common.Status.SUCCESS
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,21 +0,0 @@
import py_trees as ptree
from typing import Any
class Grasp(ptree.behaviour.Behaviour):
def __init__(self, name: str, scene):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def _update(self) -> ptree.common.Status:
print('Start checking IsChatting...')
return ptree.common.Status.SUCCESS
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,21 +0,0 @@
import py_trees as ptree
from typing import Any
class GraspCoffeeCup(ptree.behaviour.Behaviour):
def __init__(self, name: str, scene):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> ptree.common.Status:
print('Start checking IsChatting...')
return ptree.common.Status.SUCCESS
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,21 +0,0 @@
import py_trees as ptree
from typing import Any
class Istask(ptree.behaviour.Behaviour):
def __init__(self, name: str, scene):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> ptree.common.Status:
print('Start checking IsChatting...')
return ptree.common.Status.SUCCESS
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,21 +0,0 @@
import py_trees as ptree
from typing import Any
class MoveTo(ptree.behaviour.Behaviour):
def __init__(self, name: str, scene, a, b, c, d):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def _update(self) -> ptree.common.Status:
print('Start checking IsChatting...')
return ptree.common.Status.SUCCESS
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,21 +0,0 @@
import py_trees as ptree
from typing import Any
class PlaceCoffeeCup(ptree.behaviour.Behaviour):
def __init__(self, name: str, scene):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> ptree.common.Status:
print('Start checking IsChatting...')
return ptree.common.Status.SUCCESS
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,21 +0,0 @@
import py_trees as ptree
from typing import Any
class ReachDestinationA(ptree.behaviour.Behaviour):
def __init__(self, name: str, scene):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> ptree.common.Status:
print('Start checking IsChatting...')
return ptree.common.Status.SUCCESS
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,21 +0,0 @@
import py_trees as ptree
from typing import Any
class SeqTest(ptree.behaviour.Behaviour):
def __init__(self, name: str, scene):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> ptree.common.Status:
print('Start checking IsChatting...')
return ptree.common.Status.SUCCESS
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,21 +0,0 @@
import py_trees as ptree
from typing import Any
class TestTask(ptree.behaviour.Behaviour):
def __init__(self, name: str, scene):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> ptree.common.Status:
print('Start checking IsChatting...')
return ptree.common.Status.SUCCESS
def terminate(self, new_status: ptree.common.Status) -> None:
return super().terminate(new_status)

View File

@ -1,124 +0,0 @@
"""
顶层行为树中的动作与条件节点
"""
from typing import *
import py_trees
from py_trees import common
from py_trees.common import Status
##############################################################
# 条件节点
##############################################################
class IsChatting(py_trees.behaviour.Behaviour):
def __init__(self, name: str = ""):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> Status:
print('Start checking IsChatting...')
return common.Status.SUCCESS
def terminate(self, new_status: Status) -> None:
return super().terminate(new_status)
class IsTakingAction(py_trees.behaviour.Behaviour):
def __init__(self, name: str = ""):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> Status:
print('Start checking IsTakingAction...')
return common.Status.SUCCESS
def terminate(self, new_status: Status) -> None:
return super().terminate(new_status)
class IsSomethingMore(py_trees.behaviour.Behaviour):
def __init__(self, name: str = ""):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> Status:
print('Start checking IsSomethingMore...')
return common.Status.SUCCESS
def terminate(self, new_status: Status) -> None:
return super().terminate(new_status)
##############################################################
# 动作节点
##############################################################
class Chatting(py_trees.behaviour.Behaviour):
def __init__(self, name: str = ""):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> Status:
print('Start executing Chatting...')
return common.Status.SUCCESS
def terminate(self, new_status: Status) -> None:
return super().terminate(new_status)
class TakingAction(py_trees.behaviour.Behaviour):
def __init__(self, name: str = ""):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> Status:
print('Start executing TakingAction...')
return common.Status.SUCCESS
def terminate(self, new_status: Status) -> None:
return super().terminate(new_status)
class TakingMoreAction(py_trees.behaviour.Behaviour):
def __init__(self, name: str = ""):
super().__init__(name)
def setup(self, **kwargs: Any) -> None:
return super().setup(**kwargs)
def initialise(self) -> None:
return super().initialise()
def update(self) -> Status:
print('Start executing TakingMoreAction...')
return common.Status.SUCCESS
def terminate(self, new_status: Status) -> None:
return super().terminate(new_status)

View File

@ -1,66 +0,0 @@
import py_trees
from behavior_library import *
def LoadMainTree() -> py_trees.trees.BehaviourTree:
"""
此方法用于加载固定的顶层行为树不包括实际执行
Args: None
"""
seq_subtree_0 = py_trees.composites.Sequence(
name='seq_subtree_0',
memory=False,
children=[IsChatting(), Chatting()]
)
seq_subtree_1 = py_trees.composites.Sequence(
name='seq_subtree_1',
memory=False,
children=[IsTakingAction(), TakingAction()]
)
seq_subtree_2 = py_trees.composites.Sequence(
name='seq_subtree_2',
memory=False,
children=[IsSomethingMore(), TakingMoreAction()]
)
root = py_trees.composites.Selector(
name='selector_root',
memory=False,
children=[seq_subtree_0, seq_subtree_1, seq_subtree_2]
)
return py_trees.trees.BehaviourTree(root)
def LoadSubTree(path: str) -> py_trees.behaviour.Behaviour:
"""
此方法用于从ptml文件中加载行为树不包括实际执行
Args:
-- path: ptml文件的路径
"""
# TODO
pass
if __name__ == '__main__':
btree = LoadMainTree()
def print_tree(tree):
print(py_trees.display.unicode_tree(root=tree.root, show_status=True))
try:
btree.tick_tock(
period_ms=500,
number_of_iterations=py_trees.trees.CONTINUOUS_TICK_TOCK,
pre_tick_handler=None,
post_tick_handler=print_tree
)
except KeyboardInterrupt:
btree.interrupt()

View File

View File

@ -1,59 +0,0 @@
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
import sys
import time
import grpc
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
from proto import GrabSim_pb2
from proto import GrabSim_pb2_grpc
channel = grpc.insecure_channel('localhost:30001',options=[
('grpc.max_send_message_length', 1024*1024*1024),
('grpc.max_receive_message_length', 1024*1024*1024)
])
sim_client = GrabSim_pb2_grpc.GrabSimStub(channel)
def map_test(map_id=0, scene_num=1):
initworld = sim_client.Init(GrabSim_pb2.NUL())
print(sim_client.AcquireAvailableMaps(GrabSim_pb2.NUL()))
initworld = sim_client.SetWorld(GrabSim_pb2.BatchMap(count=scene_num, mapID=map_id))
def joint_test(scene_id=0):
print('------------------joint_test----------------------')
action_list = [[0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 36.0, -39.37, 37.2, -92.4, 4.13, -0.62, 0.4],
[0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 36.0, -39.62, 34.75, -94.80, 3.22, -0.26, 0.85],
[0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 32.63, -32.80, 15.15, -110.70, 6.86, 2.36, 0.40],
[0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 28.18, -27.92, 6.75, -115.02, 9.46, 4.28, 1.35],
[0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 4.09, -13.15, -11.97, -107.35, 13.08, 8.58, 3.33]]
for value in action_list:
action = GrabSim_pb2.Action(scene=scene_id, action=GrabSim_pb2.Action.ActionType.RotateJoints, values=value)
scene = sim_client.Do(action)
for i in range(8, 21): # arm
print(
f"{scene.joints[i].name}:{scene.joints[i].angle} location:{scene.joints[i].location.X},{scene.joints[i].location.Y},{scene.joints[i].location.Z}"
)
print('')
for i in range(5, 10): # Right hand
print(
f"{scene.fingers[i].name} angle:{scene.fingers[i].angle} location:{scene.fingers[i].location[0].X},{scene.fingers[i].location[0].Y},{scene.fingers[i].location[0].Z}"
)
print('----------------------------------------')
time.sleep(0.03)
time.sleep(1)
if __name__ == '__main__':
map_id = 3 # 地图编号: 3: 咖啡厅
scene_num = 1 # 场景数量
map_test(map_id, scene_num) # 场景加载测试
time.sleep(5)
for i in range(scene_num):
print("------------------", i, "----------------------")
joint_test(i) # 关节控制测试

View File

@ -1,94 +0,0 @@
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
# enconding = utf8
import sys
import time
import grpc
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
from proto import GrabSim_pb2
from proto import GrabSim_pb2_grpc
channel = grpc.insecure_channel('localhost:30001', options=[
('grpc.max_send_message_length', 1024 * 1024 * 1024),
('grpc.max_receive_message_length', 1024 * 1024 * 1024)
])
sim_client = GrabSim_pb2_grpc.GrabSimStub(channel)
def map_test(map_id=0, scene_num=1):
initworld = sim_client.Init(GrabSim_pb2.NUL())
print(sim_client.AcquireAvailableMaps(GrabSim_pb2.NUL()))
initworld = sim_client.SetWorld(GrabSim_pb2.BatchMap(count=scene_num, mapID=map_id))
def control_robot_action(scene_id=0, type=0, action=0, message="你好"):
scene = sim_client.ControlRobot(GrabSim_pb2.ControlInfo(scene=scene_id, type=type, action=action, content=message))
if (scene.info == "action success"):
return True
else:
return False
if __name__ == '__main__':
map_id = 3 # 地图编号: 0空房间 1室内 2:咖啡厅1.0 3: 咖啡厅2.0 4:餐厅 5:养老院 6会议室
scene_num = 1 # 场景数量
map_test(map_id, scene_num) # 场景加载测试
time.sleep(5)
# 制作咖啡
control_robot_action(0, 0, 1, "开始制作咖啡")
result = control_robot_action(0, 1, 1)
if (result):
control_robot_action(0, 1, 2)
control_robot_action(0, 1, 3)
control_robot_action(0, 1, 4)
else:
control_robot_action(0, 0, 1, "制作咖啡失败")
# 倒水
control_robot_action(0, 0, 1, "开始倒水")
result = control_robot_action(0, 2, 1)
if (result):
control_robot_action(0, 2, 2)
control_robot_action(0, 2, 3)
control_robot_action(0, 2, 4)
control_robot_action(0, 2, 5)
else:
control_robot_action(0, 0, 1, "倒水失败")
# 夹点心
control_robot_action(0, 0, 1, "开始夹点心")
result = control_robot_action(0, 3, 1)
if (result):
control_robot_action(0, 3, 2)
control_robot_action(0, 3, 3)
control_robot_action(0, 3, 4)
control_robot_action(0, 3, 5)
control_robot_action(0, 3, 6)
control_robot_action(0, 3, 7)
else:
control_robot_action(0, 0, 1, "夹点心失败")
# 拖地
control_robot_action(0, 0, 1, "开始拖地")
result = control_robot_action(0, 4, 1)
if (result):
control_robot_action(0, 4, 2)
control_robot_action(0, 4, 3)
control_robot_action(0, 4, 4)
else:
control_robot_action(0, 0, 1, "拖地失败")
# 擦桌子
control_robot_action(0, 0, 1, "开始擦桌子")
result = control_robot_action(0, 5, 1)
if (result):
control_robot_action(0, 5, 2)
control_robot_action(0, 5, 3)
else:
control_robot_action(0, 0, 1, "擦桌子失败")

View File

@ -1,47 +0,0 @@
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
import sys
import time
import grpc
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
from proto import GrabSim_pb2
from proto import GrabSim_pb2_grpc
channel = grpc.insecure_channel('localhost:30001',options=[
('grpc.max_send_message_length', 1024*1024*1024),
('grpc.max_receive_message_length', 1024*1024*1024)
])
sim_client = GrabSim_pb2_grpc.GrabSimStub(channel)
def map_test(map_id=0, scene_num=1):
initworld = sim_client.Init(GrabSim_pb2.NUL())
print(sim_client.AcquireAvailableMaps(GrabSim_pb2.NUL()))
initworld = sim_client.SetWorld(GrabSim_pb2.BatchMap(count=scene_num, mapID=map_id))
def reset(scene_id=0):
scene = sim_client.Reset(GrabSim_pb2.ResetParams(scene=scene_id))
def show_env_info(scene_id=0):
scene = sim_client.Observe(GrabSim_pb2.SceneID(value=scene_id))
print('------------------show_env_info----------------------')
print(
f"location:{[scene.location.X, scene.location.Y]}, rotation:{scene.rotation.Yaw}\n",
f"joints number:{len(scene.joints)}, fingers number:{len(scene.fingers)}\n", f"objects number: {len(scene.objects)}\n"
f"rotation:{scene.rotation}, timestep:{scene.timestep}\n"
f"timestamp:{scene.timestamp}, collision:{scene.collision}, info:{scene.info}")
if __name__ == '__main__':
map_id = 3 # 地图编号: 3: 咖啡厅
scene_num = 1 # 场景数量
map_test(map_id, scene_num) # 场景加载测试
time.sleep(5)
for i in range(scene_num):
print("------------------", i, "----------------------")
reset(i) # 场景重置测试
show_env_info(i) # 场景信息测试

View File

@ -1,139 +0,0 @@
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
# enconding = utf8
import sys
import time
import grpc
sys.path.append('./')
sys.path.append('../')
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
from robowaiter.proto import GrabSim_pb2_grpc,GrabSim_pb2
channel = grpc.insecure_channel('localhost:30001', options=[
('grpc.max_send_message_length', 1024 * 1024 * 1024),
('grpc.max_receive_message_length', 1024 * 1024 * 1024)
])
sim_client = GrabSim_pb2_grpc.GrabSimStub(channel)
'''
初始化卸载已经加载的关卡清除所有机器人
'''
def Init():
sim_client.Init(GrabSim_pb2.NUL())
'''
获取当前可加载的地图信息(地图名字地图尺寸)
'''
def AcquireAvailableMaps():
AvailableMaps = sim_client.AcquireAvailableMaps(GrabSim_pb2.NUL())
print(AvailableMaps)
'''
1根据mapID加载指定地图
2如果scene_num>1,则根据地图尺寸偏移后加载多个相同地图
3这样就可以在一个关卡中训练多个地图
'''
def SetWorld(map_id=0, scene_num=1):
print('------------------SetWorld----------------------')
world = sim_client.SetWorld(GrabSim_pb2.BatchMap(count=scene_num, mapID=map_id))
'''
返回场景的状态信息
1返回机器人的位置和旋转
2返回各个关节的名字和旋转
3返回场景中标记的物品信息(名字类型位置旋转)
4返回场景中行人的信息(名字位置旋转速度)
5返回机器人手指和双臂的碰撞信息
'''
def Observe(scene_id=0):
print('------------------show_env_info----------------------')
scene = sim_client.Observe(GrabSim_pb2.SceneID(value=scene_id))
print(
f"location:{[scene.location]}, rotation:{scene.rotation}\n",
f"joints number:{len(scene.joints)}, fingers number:{len(scene.fingers)}\n",
f"objects number: {len(scene.objects)}, walkers number: {len(scene.walkers)}\n"
f"timestep:{scene.timestep}, timestamp:{scene.timestamp}\n"
f"collision:{scene.collision}, info:{scene.info}")
'''
重置场景
1重置桌子的宽度和高度
2清除生成的行人和物品
3重置关节角度位置旋转
4清除碰撞信息
5重置场景中标记的物品
'''
def Reset(scene_id=0):
print('------------------Reset----------------------')
scene = sim_client.Reset(GrabSim_pb2.ResetParams(scene=scene_id))
print(scene)
# 如果场景支持调整桌子
# sim_client.Reset(GrabSim_pb2.ResetParams(scene = scene_id, adjust = True, height = 100.0, width = 100.0))"
"""
导航移动
yaw:机器人朝向;
velocity:速度,>0代表移动,<0代表瞬移,=0代表只查询;
dis:最终达到的位置距离目标点最远距离,如果超过此距离则目标位置不可达
"""
def navigation_move(scene_id=0, map_id=0):
print('------------------navigation_move----------------------')
scene = sim_client.Observe(GrabSim_pb2.SceneID(value=scene_id))
walk_value = [scene.location.X, scene.location.Y, scene.rotation.Yaw]
print("position:", walk_value)
if map_id == 11: # coffee
v_list = [[0, 880], [250, 1200], [-55, 750], [70, -200]]
else:
v_list = [[0.0, 0.0]]
for walk_v in v_list:
walk_v = walk_v + [scene.rotation.Yaw - 90, 600, 100]
print("walk_v", walk_v)
action = GrabSim_pb2.Action(scene=scene_id, action=GrabSim_pb2.Action.ActionType.WalkTo, values=walk_v)
scene = sim_client.Do(action)
print(scene.info)
if __name__ == '__main__':
map_id = 11 # 地图编号
scene_num = 1 # 场景数量
print('------------ 初始化加载场景 ------------')
Init()
AcquireAvailableMaps()
SetWorld(map_id, scene_num)
time.sleep(5.0)
for i in range(scene_num):
print('------------ 场景操作 ------------')
Observe(i)
Reset(i)
print('------------ 导航移动 ------------')
navigation_move(i, map_id)

View File

@ -1,44 +0,0 @@
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
# enconding = utf8
import sys
import time
import grpc
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
from proto import GrabSim_pb2
from proto import GrabSim_pb2_grpc
channel = grpc.insecure_channel('localhost:30001', options=[
('grpc.max_send_message_length', 1024 * 1024 * 1024),
('grpc.max_receive_message_length', 1024 * 1024 * 1024)
])
sim_client = GrabSim_pb2_grpc.GrabSimStub(channel)
def map_test(map_id=0, scene_num=1):
initworld = sim_client.Init(GrabSim_pb2.NUL())
print(sim_client.AcquireAvailableMaps(GrabSim_pb2.NUL()))
initworld = sim_client.SetWorld(GrabSim_pb2.BatchMap(count=scene_num, mapID=map_id))
def control_robot_action(scene_id=0, type=0, action=0, message="你好"):
scene = sim_client.ControlRobot(GrabSim_pb2.ControlInfo(scene=scene_id, type=type, action=action, content=message))
if (scene.info == "action success"):
return True
else:
return False
if __name__ == '__main__':
map_id = 3 # 地图编号: 0空房间 1室内 2:咖啡厅1.0 3: 咖啡厅2.0 4:餐厅 5:养老院 6会议室
scene_num = 1 # 场景数量
map_test(map_id, scene_num) # 场景加载测试
time.sleep(5)
# 文字冒泡
control_robot_action(0, 0, 1, "你好,欢迎光临")

View File

@ -1,103 +0,0 @@
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
import sys
import time
import grpc
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
from proto import GrabSim_pb2
from proto import GrabSim_pb2_grpc
channel = grpc.insecure_channel('localhost:30001',options=[
('grpc.max_send_message_length', 1024*1024*1024),
('grpc.max_receive_message_length', 1024*1024*1024)
])
sim_client = GrabSim_pb2_grpc.GrabSimStub(channel)
def map_test(map_id=0, scene_num=1):
initworld = sim_client.Init(GrabSim_pb2.NUL())
print(sim_client.AcquireAvailableMaps(GrabSim_pb2.NUL()))
initworld = sim_client.SetWorld(GrabSim_pb2.BatchMap(count=scene_num, mapID=map_id))
def joint_test(scene_id=0):
print('------------------joint_test----------------------')
action_list = [[0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 36.0, -39.37, 37.2, -92.4, 4.13, -0.62, 0.4],
[0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 36.0, -39.62, 34.75, -94.80, 3.22, -0.26, 0.85],
[0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 32.63, -32.80, 15.15, -110.70, 6.86, 2.36, 0.40],
[0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 28.18, -27.92, 6.75, -115.02, 9.46, 4.28, 1.35],
[0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 4.09, -13.15, -11.97, -107.35, 13.08, 8.58, 3.33]]
for value in action_list:
action = GrabSim_pb2.Action(scene=scene_id, action=GrabSim_pb2.Action.ActionType.RotateJoints, values=value)
scene = sim_client.Do(action)
for i in range(8, 21): # arm
print(
f"{scene.joints[i].name}:{scene.joints[i].angle} location:{scene.joints[i].location.X},{scene.joints[i].location.Y},{scene.joints[i].location.Z}"
)
print('')
for i in range(5, 10): # Right hand
print(
f"{scene.fingers[i].name} angle:{scene.fingers[i].angle} location:{scene.fingers[i].location[0].X},{scene.fingers[i].location[0].Y},{scene.fingers[i].location[0].Z}"
)
print('----------------------------------------')
time.sleep(0.03)
time.sleep(1)
def gen_obj(scene_id, h=80):
print('------------------gen objs----------------------')
scene = sim_client.Observe(GrabSim_pb2.SceneID(value=scene_id))
ginger_loc = [scene.location.X, scene.location.Y, scene.location.Z]
obj_list = [
GrabSim_pb2.ObjectList.Object(x=ginger_loc[0] - 90, y=ginger_loc[1] + 30, yaw=10, z=h, type=4),
GrabSim_pb2.ObjectList.Object(x=ginger_loc[0] - 80, y=ginger_loc[1] + 31, z=h, type=5),
GrabSim_pb2.ObjectList.Object(x=ginger_loc[0] - 33, y=ginger_loc[1] - 10.5, z=h+20, type=7),
GrabSim_pb2.ObjectList.Object(x=ginger_loc[0] - 70, y=ginger_loc[1] + 33, z=h, type=9),
GrabSim_pb2.ObjectList.Object(x=ginger_loc[0] - 60, y=ginger_loc[1] + 34, z=h, type=13)
]
scene = sim_client.AddObjects(GrabSim_pb2.ObjectList(objects=obj_list, scene=scene_id))
print(scene.collision)
time.sleep(5)
def remove_obj(scene_id=0, id_list=[1]):
print('------------------remove objs----------------------')
remove_obj_list = id_list
scene = sim_client.RemoveObjects(GrabSim_pb2.RemoveList(IDs=remove_obj_list, scene=scene_id))
print(f"remove objects {id_list}. current obj:")
time.sleep(1)
def clean_obj(scene_id=0):
print('------------------clean objs----------------------')
scene = sim_client.CleanObjects(GrabSim_pb2.SceneID(value=scene_id))
def obj_test(scene_id=0):
gen_obj(scene_id)
# remove_obj(scene_id, id_list=[0])
# clean_obj(scene_id)
def grasp_test(hand_id, obj_scene_id, scene_id=0):
action = GrabSim_pb2.Action(scene=scene_id, action=GrabSim_pb2.Action.ActionType.Grasp, values=[hand_id, obj_scene_id])
scene = sim_client.Do(action)
def release_test(hand_id, scene_id=0):
action = GrabSim_pb2.Action(scene=scene_id, action=GrabSim_pb2.Action.ActionType.Release, values=[hand_id])
scene = sim_client.Do(action)
if __name__ == '__main__':
map_id = 3 # 地图编号: 3: 咖啡厅
scene_num = 1 # 场景数量
map_test(map_id, scene_num) # 场景加载测试
time.sleep(5)
for i in range(scene_num):
print("------------------", i, "----------------------")
joint_test(i) # 关节控制测试
obj_test(i) # 物品生成测试
grasp_test(1, 2) # 抓取物品测试
joint_test(i) # 关节控制测试
release_test(1) # 释放物品测试

View File

@ -1,49 +0,0 @@
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
import sys
import time
import grpc
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
from proto import GrabSim_pb2
from proto import GrabSim_pb2_grpc
channel = grpc.insecure_channel('localhost:30001',options=[
('grpc.max_send_message_length', 1024*1024*1024),
('grpc.max_receive_message_length', 1024*1024*1024)
])
sim_client = GrabSim_pb2_grpc.GrabSimStub(channel)
def map_test(map_id=0, scene_num=1):
initworld = sim_client.Init(GrabSim_pb2.NUL())
print(sim_client.AcquireAvailableMaps(GrabSim_pb2.NUL()))
initworld = sim_client.SetWorld(GrabSim_pb2.BatchMap(count=scene_num, mapID=map_id))
def get_camera(part, scene_id=0):
action = GrabSim_pb2.CameraList(cameras=part, scene=scene_id)
return sim_client.Capture(action)
def show_image(img_data):
im = img_data.images[0]
d = np.frombuffer(im.data, dtype=im.dtype).reshape((im.height, im.width, im.channels))
plt.imshow(d, cmap="gray" if "depth" in im.name.lower() else None)
plt.show()
def camera_test(scene_id=0):
for camera_name in [GrabSim_pb2.CameraName.Head_Color, GrabSim_pb2.CameraName.Head_Depth, GrabSim_pb2.CameraName.Head_Segment]:
img_data = get_camera([camera_name], scene_id)
show_image(img_data)
if __name__ == '__main__':
map_id = 3 # 地图编号: 0空房间 1室内 2:咖啡厅1.0 3: 咖啡厅2.0 4:餐厅 5:养老院 6会议室
scene_num = 1 # 场景数量
map_test(map_id, scene_num) # 场景加载测试
time.sleep(5)
for i in range(scene_num):
print("------------------", i, "----------------------")
camera_test(i) # 相机操作测试

View File

@ -1,86 +0,0 @@
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
import sys
import time
import grpc
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
from proto import GrabSim_pb2
from proto import GrabSim_pb2_grpc
channel = grpc.insecure_channel('localhost:30001',options=[
('grpc.max_send_message_length', 1024*1024*1024),
('grpc.max_receive_message_length', 1024*1024*1024)
])
sim_client = GrabSim_pb2_grpc.GrabSimStub(channel)
def map_test(map_id=0, scene_num=1):
initworld = sim_client.Init(GrabSim_pb2.NUL())
print(sim_client.AcquireAvailableMaps(GrabSim_pb2.NUL()))
initworld = sim_client.SetWorld(GrabSim_pb2.BatchMap(count=scene_num, mapID=map_id))
def add_walker(scene_id=0):
"""pose:表示行人的初始位置姿态"""
print('------------------add walker----------------------')
s = sim_client.Observe(GrabSim_pb2.SceneID(value=0))
walker_loc = [[0, 880], [250, 1200], [-55, 750], [70, -200]]
walker_list = []
for i in range(len(walker_loc)):
loc = walker_loc[i] + [0, 600, 100]
action = GrabSim_pb2.Action(scene=scene_id, action=GrabSim_pb2.Action.ActionType.WalkTo, values=loc)
scene = sim_client.Do(action)
print(scene.info)
# 只有可达的位置才能成功初始化行人显示unreachable的地方不能初始化行人
walker_list.append(GrabSim_pb2.WalkerList.Walker(id=i, pose=GrabSim_pb2.Pose(X=loc[0], Y=loc[1], Yaw=90)))
scene = sim_client.AddWalker(GrabSim_pb2.WalkerList(walkers=walker_list, scene=scene_id))
return scene
def control_walkers(scene_id=0):
"""pose:表示行人的终止位置姿态"""
s = sim_client.Observe(GrabSim_pb2.SceneID(value=scene_id))
walker_loc = [[-55, 750], [70, -200], [250, 1200], [0, 880]]
controls = []
for i in range(len(s.walkers)):
loc = walker_loc[i]
is_autowalk = False
pose = GrabSim_pb2.Pose(X=loc[0], Y=loc[1], Yaw=180)
controls.append(GrabSim_pb2.WalkerControls.WControl(id=i, autowalk=is_autowalk, speed=200, pose=pose))
scene = sim_client.ControlWalkers(GrabSim_pb2.WalkerControls(controls=controls, scene=scene_id))
time.sleep(10)
return scene
def remove_walkers(scene_id=0):
s = sim_client.Observe(GrabSim_pb2.SceneID(value=scene_id))
scene = sim_client.RemoveWalkers(GrabSim_pb2.RemoveList(IDs=[1, 3], scene=scene_id))
time.sleep(2)
return
def clean_walkers(scene_id=0):
scene = sim_client.CleanWalkers(GrabSim_pb2.SceneID(value=scene_id))
return scene
def walker_test(scene_id=0):
add_walker(scene_id)
control_walkers(scene_id)
print(sim_client.Observe(GrabSim_pb2.SceneID(value=scene_id)).walkers)
remove_walkers(scene_id)
print(sim_client.Observe(GrabSim_pb2.SceneID(value=scene_id)).walkers)
clean_walkers(scene_id)
return
if __name__ == '__main__':
map_id = 3 # 地图编号: 3: 咖啡厅
scene_num = 1 # 场景数量
map_test(map_id, scene_num) # 场景加载测试
time.sleep(5)
for i in range(scene_num):
print("------------------", i, "----------------------")
walker_test(i) # 行人控制测试

View File

@ -1 +0,0 @@
conda install pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cudatoolkit=11.3 -c pytorch

View File

@ -1,4 +0,0 @@
from . import navigate
from . import dstar_lite

View File

@ -1,510 +0,0 @@
'''
基于两个D* lite的实现
按照原始算法的伪代码
自己写的D* lite
'''
import math
import queue
from functools import partial
import numpy as np
import heapq
from matplotlib import pyplot as plt
def diagonal_distance(start, end): #
return max(abs(start[0] - end[0]), abs(start[1] - end[1]))
def manhattan_distance(start, end): # 曼哈顿距离
return abs(start[0] - end[0]) + abs(start[1] - end[1])
def euclidean_distance(start, end): # 欧式距离
# return np.linalg.norm(start-end)
return math.sqrt((start[0] - end[0]) ** 2 + (start[1] - end[1]) ** 2)
def heuristic(start, end, name='euclidean'):
if name == 'diagonal':
return diagonal_distance(start, end)
elif name == 'euclidean':
return euclidean_distance(start, end)
elif name == 'manhattan':
return manhattan_distance(start, end)
else:
raise Exception('Error heuristic name!')
class Priority:
'''
优先级类
'''
def __init__(self, k1, k2):
self.k1 = k1
self.k2 = k2
def __lt__(self, other): # 定义对象的 < 运算
return self.k1 < other.k1 or (self.k1 == other.k1 and self.k2 < other.k2)
def __le__(self, other): # 定于对象的 <= 运算
return self.k1 < other.k1 or (self.k1 == other.k1 and self.k2 <= other.k2)
class Node:
'''
节点类
'''
def __init__(self, pos: (int, int), priority: Priority):
self.pos = pos # X Y
self.priority = priority
def __lt__(self, other): # 定义对象的 < 运算
return self.priority < other.priority
def __le__(self, other): # 定于对象的 <= 运算
return self.priority <= other.priority
class PriorityQueue:
def __init__(self):
self.queue = [] # 节点队列
self.nodes = [] # 节点位置列表
def is_empty(self):
# 队列判空
return len(self.queue) == 0
def top(self):
return self.queue[0].pos
def top_key(self):
if self.is_empty():
return Priority(float('inf'), float('inf'))
return self.queue[0].priority
def pop(self):
# 取出第一个节点
node = heapq.heappop(self.queue)
self.nodes.remove(node.pos)
return node
def insert(self, pos, priority):
# 创建并添加节点
node = Node(pos, priority)
heapq.heappush(self.queue, node)
self.nodes.append(pos)
def remove(self, pos):
# 删除指定节点并重新排序
self.queue = [n for n in self.queue if n.pos != pos]
heapq.heapify(self.queue) # 重排序
self.nodes.remove(pos)
def update(self, pos, priority):
# 更新指定位置的priority值
for n in self.queue:
if n.pos == pos:
n.priority = priority
break
class DStarLite:
def __init__(self,
map: np.array([int, int]), # [X, Y]
area_range, # [x_min, x_max, y_min, y_max] 实际坐标范围
scale_ratio=5, # 地图缩放率
dyna_obs_radius=20 # dyna_obs实际身位半径
):
# self.area_bounds = area
self.map = map
self.background = map
self.X = map.shape[0]
self.Y = map.shape[1]
(self.x_min, self.x_max, self.y_min, self.y_max) = area_range
self.scale_ratio = scale_ratio
self.dyna_obs_list = [] # 动态障碍物位置列表( 当前地图 ) [(x, y)]
self.dyna_obs_radius = math.ceil(dyna_obs_radius/scale_ratio) # dyna_obs缩放后身位半径
# free:0, obs:1, dyna_obs:2
self.idx_to_object = {
0: "free",
1: "obstacle",
2: "dynamic obstacle"
}
self.object_to_idx = dict(zip(self.idx_to_object.values(), self.idx_to_object.keys()))
self.object_to_cost = {
"free": 0,
"obstacle": float('inf'),
"dynamic obstacle": 50
}
self.compute_cost_map()
self.s_start = None # (int,int) 必须是元组(元组可以直接当作矩阵索引)
self.s_goal = None # (int,int)
self.s_last = None # (int,int)
self.U = PriorityQueue()
self.k_m = 0
self.rhs = np.ones((self.X, self.Y)) * np.inf
self.g = self.rhs.copy()
self.path = []
def set_map(self, map_):
'''
设置map cost_map
'''
self.map = map_
self.X = map_.shape[0]
self.Y = map_.shape[1]
self.compute_cost_map()
def reset(self):
'''
(完成一次导航后)
重置 1.环境变量
2.dstar_lite变量
'''
# env reset
self.map = self.background.copy()
self.compute_cost_map()
self.dyna_obs_list.clear()
self.path.clear()
# dstar_lite reset
self.s_start = None
self.s_goal = None
self.s_last = None
self.U = PriorityQueue()
self.k_m = 0
self.rhs = np.ones((self.X, self.Y)) * np.inf
self.g = self.rhs.copy()
def calculate_key(self, s: (int, int)):
'''
计算 位置s key1, key2
:returns
Priority(k1, k2): 可比较的对象
'''
k1 = min(self.g[s], self.rhs[s]) + heuristic(self.s_start, s) + self.k_m
k2 = min(self.g[s], self.rhs[s])
return Priority(k1, k2)
def c(self, u: (int, int), v: (int, int), v_old=None) -> float:
'''
计算节点间的 路径代价 目标位置代价 (目标位置代价为0时采用路径代价)
(因为是终点->起点的扩展方向因此v是nodeu是v扩展的neighbor)
Args:
u: from pos
v: to pos
v_old: 指定的v的类型
'''
if v_old:
obj_cost = self.object_to_cost[v_old]
else:
obj_cost = self.cost_map[v]
if obj_cost > 0:
return obj_cost
return heuristic(u, v)
def contain(self, u: (int, int)):
'''
判断 节点u 是否在队列中
'''
return u in self.U.nodes
def update_vertex(self, u: (int, int)):
'''
判定节点状态, 更新队列
不一致且在队列 --> 更新key
不一致且不在队列 --> 计算key并加入队列
一致且在队列 --> 移出队列
'''
if self.g[u] != self.rhs[u] and self.contain(u):
self.U.update(u, self.calculate_key(u))
elif self.g[u] != self.rhs[u] and not self.contain(u):
self.U.insert(u, self.calculate_key(u))
elif self.g[u] == self.rhs[u] and self.contain(u):
self.U.remove(u)
def compute_shortest_path(self):
'''
计算最短路径
'''
while self.U.top_key() < self.calculate_key(self.s_start) or self.rhs[self.s_start] > self.g[self.s_start]:
u = self.U.top()
k_old = self.U.top_key()
k_new = self.calculate_key(u)
if k_old < k_new:
self.U.update(u, k_new)
elif self.g[u] > self.rhs[u]: # 过一致
self.g[u] = self.rhs[u]
self.U.remove(u)
pred = self.get_neighbors(u)
for s in pred:
if s != self.s_goal:
self.rhs[s] = min(self.rhs[s], self.c(s, u) + self.g[u])
self.update_vertex(s)
else: # 欠一致
g_old = self.g[u]
self.g[u] = float('inf')
pred = self.get_neighbors(u)
for s in pred + [u]:
if self.rhs[s] == self.c(s, u) + g_old:
if s != self.s_goal:
succ = self.get_neighbors(s)
self.rhs[s] = min([self.c(s, s_) + self.g[s_] for s_ in succ])
self.update_vertex(s)
def _planning(self, s_start, s_goal, dyna_obs, step_num=None, debug=False):
'''
规划路径(实际实现)
Args:
dyna_obs: 动态障碍物位置列表
step_num: 单次移动步数
'''
# 确保目标合法
if not self.in_bounds_without_obstacle(s_goal):
return None
# 第一次规划需要初始化rhs并将goal加入队列计算最短路径
if self.s_goal is None:
self.s_start = tuple(s_start)
self.s_goal = tuple(s_goal)
self.s_last = tuple(s_start)
self.rhs[tuple(s_goal)] = 0
self.U.insert(tuple(s_goal), Priority(k1=heuristic(tuple(s_start), tuple(s_goal)), k2=0))
self.compute_shortest_path() # 计算最短路径
self.path = self.get_path()
# 后续规划只更新起点,直接使用原路径(去掉已走过部分)
else:
self.s_start = tuple(s_start)
self.path = self.path[step_num:]
# 根据obs更新map, cost_map, edge_cost
changed_pos = self.update_map(dyna_obs=dyna_obs)
if changed_pos:
self.update_cost_map(changed_pos)
self.update_edge_costs(changed_pos)
# 若地图改变,重新计算最短路径
self.compute_shortest_path()
self.path = self.get_path()
# TODO: 误差抖动使robot没有到达路径上的点导致新起点的rhs=∞可能导致get_path失败 ( 当前版本没有该问题 )
# assert (self.rhs[self.s_start] != float('inf')), "There is no known path!"
# self.path = self.get_path(step_num)
# # debug
# if debug:
# pass
return self.path
def planning(self, s_start, s_goal, dyna_obs, step_num=None, debug=False):
'''
路径规划(供外部调用处理实际坐标和地图坐标的转换)
'''
# 实际坐标 -> 地图坐标
s_start = self.real2map(s_start)
s_goal = self.real2map(s_goal)
for i in range(len(dyna_obs)):
dyna_obs[i] = self.real2map(dyna_obs[i])
self._planning(s_start, s_goal, dyna_obs, step_num, debug)
# 地图坐标->实际坐标
path = [self.map2real(node) for node in self.path]
return path
def get_path(self):
'''
得到路径
Args:
step_num: 路径步数 (None表示返回完整路径)
return:
path: [(x, y), ...]
'''
if self.s_start is None or self.s_goal == self.s_start:
return []
path = []
cur = self.s_start
# if step_num is None: # 得到完整路径
while cur != self.s_goal:
succ = self.get_neighbors(cur)
cur = succ[np.argmin([self.c(cur, s_) + self.g[s_] for s_ in succ])]
path.append(cur)
# else:
# for i in range(step_num):
# if cur == self.s_goal:
# break
# succ = self.get_neighbors(cur)
# cur = succ[np.argmin([self.c(cur, s_) + self.g[s_] for s_ in succ])]
# path.append(cur)
return path
def in_bounds_without_obstacle(self, pos):
'''
判断位置在地图范围内 不是静态障碍物
'''
(x, y) = pos
return 0 <= x < self.X and 0 <= y < self.Y and self.map[x, y] != self.object_to_idx["obstacle"]
def get_neighbors(self, pos, mode=8):
'''
获取邻居节点, 地图范围内
'''
(x_, y_) = pos
# results = [(x_+1,y_), (x_-1,y_), (x_, y_+1), (x_,y_-1)]
# if mode == 8:
neighbors = [(x_ + 1, y_), (x_ - 1, y_), (x_, y_ + 1), (x_, y_ - 1), (x_ + 1, y_ + 1), (x_ - 1, y_ + 1),
(x_ + 1, y_ - 1), (x_ - 1, y_ - 1)]
neighbors = filter(self.in_bounds_without_obstacle, neighbors) # 确保位置在地图范围内 且 不是静态障碍物
return list(neighbors)
def compute_cost_map(self):
# 计算当前地图的cost_map
self.cost_map = np.zeros(self.map.shape)
for idx, obj in self.idx_to_object.items():
self.cost_map[self.map == idx] = self.object_to_cost[obj]
def update_map(self, dyna_obs):
'''
更新地图 动态障碍物列表
Args:
dyna_obs: 当前动态障碍物位置列表 [(x,y), ...]
return:
update_obj: 改变的位置列表 [(x, y, obj_idx, obj_idx_old), ...]
'''
# dyna_obs没有变化 (集合set可以忽略元素在列表中的位置)
if set(dyna_obs) == set(self.dyna_obs_list):
return []
# 新旧dyna_obs占用位置列表
old_obs_occupy = []
new_obs_occupy = []
for pos in self.dyna_obs_list:
old_obs_occupy.extend(self.get_occupy_pos(pos))
for pos in dyna_obs:
new_obs_occupy.extend(self.get_occupy_pos(pos))
old_obs_occupy = [pos for i, pos in enumerate(old_obs_occupy) if pos not in old_obs_occupy[:i]] # 去除重复位置
new_obs_occupy = [pos for i, pos in enumerate(new_obs_occupy) if pos not in new_obs_occupy[:i]] # 去除重复位置
# 转变为free 和 转变为obs的位置列表
changed_free = [pos for pos in old_obs_occupy if pos not in new_obs_occupy]
changed_obs = [pos for pos in new_obs_occupy if pos not in old_obs_occupy]
# 更新地图计算changed_pos
changed_pos = []
for (x, y) in changed_free:
self.map[x, y] = self.object_to_idx['free']
changed_pos.append((x, y, self.object_to_idx["free"], self.object_to_idx["dynamic obstacle"]))
for (x, y) in changed_obs:
self.map[x, y] = self.object_to_idx['dynamic obstacle']
changed_pos.append((x, y, self.object_to_idx["dynamic obstacle"], self.object_to_idx["free"]))
# 更新动态障碍物列表
self.dyna_obs_list = dyna_obs
return changed_pos
def get_occupy_pos(self, obs_pos):
'''
根据dyna_obs中心位置计算其占用的所有网格位置
'''
(x, y) = obs_pos
occupy_pos = []
for i in range(x-self.dyna_obs_radius, x+self.dyna_obs_radius+1):
for j in range(y-self.dyna_obs_radius, y+self.dyna_obs_radius+1):
occupy_pos.append((i, j))
occupy_pos = filter(self.in_bounds_without_obstacle, occupy_pos) # 确保位置在地图范围内 且 不是静态障碍物
return list(occupy_pos)
def update_cost_map(self, changed_pos):
'''
更新cost_map
Args:
changed_pos: 改变的位置列表 [x, y, idx]
'''
for (x, y, idx, _) in changed_pos:
self.cost_map[x, y] = self.object_to_cost[self.idx_to_object[idx]]
def update_edge_costs(self, changed_pos):
'''
重新计算edge_cost更新受影响节点的rhs
Args:
changed_pos: 改变的位置列表 [(x, y, obj_idx_new, obj_idx_old)]
'''
if not changed_pos: return
self.k_m += heuristic(self.s_last, self.s_start, name='euclidean') # 使用欧式距离 更新km
self.s_last = self.s_start
for pos in changed_pos:
v = (pos[0], pos[1]) # to pos
v_old = self.idx_to_object[pos[3]] # 位置v的旧类型
pred_v = self.get_neighbors(v)
for u in pred_v:
c_old = self.c(u, v, v_old=v_old)
c_new = self.c(u, v)
if c_old > c_new and u != self.s_goal:
self.rhs[u] = min(self.rhs[u], self.c(u, v) + self.g[v])
elif self.rhs[u] == c_old + self.g[v] and u != self.s_goal:
succ_u = self.get_neighbors(u)
self.rhs[u] = min([self.c(u, s_) + self.g[s_] for s_ in succ_u])
self.update_vertex(u)
def map2real(self, pos):
'''
地图坐标->实际坐标
'''
x = pos[0] * self.scale_ratio + self.x_min
y = pos[1] * self.scale_ratio + self.y_min
return tuple((x, y))
def real2map(self, pos, approximation='round'):
'''
实际坐标->地图坐标
'''
if approximation == 'round': # 四舍五入
x = round((pos[0] - self.x_min) / self.scale_ratio)
y = round((pos[1] - self.y_min) / self.scale_ratio)
elif approximation == 'low': # 向下取整
x = math.floor((pos[0] - self.x_min) / self.scale_ratio)
y = math.floor((pos[1] - self.y_min) / self.scale_ratio)
else:
raise Exception("Wrong approximation!")
return tuple((x, y))
def draw_graph(self, step_num):
# 清空当前figure内容保留figure对象
plt.clf()
# for stopping simulation with the esc key. 按esc结束
plt.gcf().canvas.mpl_connect(
'key_release_event',
lambda event: [exit(0) if event.key == 'escape' else None])
# 缩放坐标偏移量
offset = (self.x_min / self.scale_ratio, self.x_max / self.scale_ratio,
self.y_min / self.scale_ratio, self.y_max / self.scale_ratio,)
# 画地图: X行Y列第一行在下面
# 范围: 横向Y[-80,290] 纵向X[-70,120]
plt.imshow(self.map, cmap='binary', alpha=0.5, origin='lower',
extent=(offset[2], offset[3],
offset[0], offset[1]))
# 画起点和目标
plt.plot(self.s_start[1] + offset[2], self.s_start[0] + offset[0], "xr")
plt.plot(self.s_goal[1] + offset[2], self.s_goal[0] + offset[0], "xr")
# 画搜索路径
plt.plot([y + offset[2] for (x, y) in self.path],
[x + offset[0] for (x, y) in self.path], "-g")
# 画移动路径
next_step = min(step_num, len(self.path))
# plt.plot([self.s_start[1] + offset[2], self.path[next_step-1][1] + offset[2]],
# [self.s_start[0] + offset[0], self.path[next_step-1][0] + offset[0]], "-r")
plt.plot([y + offset[2] for (x, y) in self.path[:next_step]],
[x + offset[0] for (x, y) in self.path[:next_step]], "-r")
plt.xlabel('y', loc='right')
plt.ylabel('x', loc='top')
plt.grid(color='black', linestyle='-', linewidth=0.5)
plt.pause(0.3)

Binary file not shown.

View File

@ -1,78 +0,0 @@
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
import math
import sys
import time
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
from scene_utils import Scene
from dstar_lite import DStarLite
class Navigator:
'''
导航类
'''
def __init__(self, scene, area_range, map, scale_ratio=5):
self.scene = scene
self.area_range = area_range # 地图实际坐标范围 xmin, xmax, ymin, ymax
self.map = map # 缩放并离散化的地图 array(X,Y)
self.scale_ratio = scale_ratio # 地图缩放率
self.step_length = 50 # 步长(单次移动)
self.step_num = self.step_length // self.scale_ratio # 单次移动地图格数
self.v = 200 # 速度
self.step_time = self.step_length/self.v + 0.1 # 单步移动时长
self.planner = DStarLite(area_range=area_range, map=map, scale_ratio=scale_ratio)
@staticmethod
def is_reached(pos: np.array((float, float)), goal: np.array((float, float)), dis_limit=25):
'''
判断是否到达目标
'''
dis = np.linalg.norm(pos - goal)
return dis < dis_limit
def reset_goal(self, goal:(float, float)):
# TODO: 使目标可达
# 目标在障碍物上:从目标开始方形向外扩展,直到找到可行点
# 目标在地图外面:起点和目标连线最靠近目标的可行点
pass
def navigate(self, goal: (float, float), animation=True):
'''
单次导航直到到达目标
'''
pos = np.array((self.scene.status.location.X, self.scene.status.location.Y)) # 机器人当前: 位置 和 朝向
yaw = self.scene.status.rotation.Yaw
print('------------------navigation_start----------------------')
while not self.is_reached(pos, goal):
dyna_obs = [(walker.pose.X, walker.pose.Y) for walker in self.scene.status.walkers] # 动态障碍物(顾客)位置列表
path = self.planner.planning(pos, goal, dyna_obs, step_num=self.step_num)
if path:
next_step = min(self.step_num, len(path))
(next_x, next_y) = path[next_step-1]
print('plan pos:', (next_x, next_y), end=' ')
self.scene.walk_to(next_x, next_y, yaw, velocity=self.v)
if animation:
self.planner.draw_graph(self.step_num) # 画出搜索路径
time.sleep(self.step_time)
pos = np.array((self.scene.status.location.X, self.scene.status.location.Y))
print('reach pos:', pos)
self.planner.reset() # 完成一轮导航,重置变量
if self.is_reached(pos, goal):
print('The robot has achieved goal !!')

View File

@ -1,4 +0,0 @@
### dstar_lite.py ——Dstar lite算法文件
### navigate.py ——导航类
### test.py ——测试文件
### map_5.pkl ——离散化地图文件

View File

@ -1,72 +0,0 @@
import os
import pickle
import time
import random
import matplotlib.pyplot as plt
import numpy as np
from scene_utils import Scene # TODO: 文件名改成Scene.py
from navigate import Navigator
if __name__ == '__main__':
file_name = 'map_5.pkl'
if os.path.exists(file_name):
with open(file_name, 'rb') as file:
map = pickle.load(file)
Scene.init_world(1, 3)
scene = Scene.Scene(sceneID=0)
navigator = Navigator(scene=scene, area_range=[-350, 600, -400, 1450], map=map)
'''场景1: 无行人环境 robot到达指定目标'''
# goal = np.array((-100, 700))
'''场景2: 静止行人环境 robot到达指定目标'''
# scene.clean_walker()
# scene.add_walker(50, 300, 0)
# scene.add_walker(-50, 500, 0)
# goal = np.array((-100, 700))
'''场景3: 移动行人环境 robot到达指定目标'''
scene.clean_walker()
scene.add_walker(50, 300, 0)
scene.add_walker(-50, 500, 0)
scene.control_walker([scene.walker_control_generator(walkerID=0, autowalk=False, speed=20, X=-50, Y=600, Yaw=0)])
scene.control_walker([scene.walker_control_generator(walkerID=1, autowalk=False, speed=20, X=100, Y=150, Yaw=0)])
goal = np.array((-100, 700))
'''场景4: 行人自由移动 robot到达指定目标'''
# # TODO: autowalk=True仿真器会闪退 ???
# scene.clean_walker()
# scene.add_walker(50, 300, 0)
# scene.add_walker(-50, 500, 0)
# scene.control_walker([scene.walker_control_generator(walkerID=0, autowalk=True, speed=20, X=0, Y=0, Yaw=0)])
# scene.control_walker([scene.walker_control_generator(walkerID=1, autowalk=True, speed=20, X=0, Y=0, Yaw=0)])
# time.sleep(5)
# goal = np.array((-100, 700))
navigator.navigate(goal, animation=False)
scene.clean_walker()
print(scene.status.collision) # TODO: 不显示碰撞信息 ???

View File

@ -1,95 +0,0 @@
#叶结点
class Leaf:
def __init__(self,type,content,mincost):
self.type=type
self.content=content #conditionset or action
self.parent=None
self.parent_index=0
self.mincost=mincost
# tick 叶节点返回返回值以及对应的条件或行动对象self.content
def tick(self,state):
if self.type=='cond':
if self.content <= state:
return 'success',self.content
else:
return 'failure',self.content
if self.type=='act':
if self.content.pre<=state:
return 'running',self.content #action
else:
return 'failure',self.content
def __str__(self):
print( self.content)
return ''
def print_nodes(self):
print(self.content)
def count_size(self):
return 1
#可能包含控制结点的行为树
class ControlBT:
def __init__(self,type):
self.type=type
self.children=[]
self.parent=None
self.parent_index=0
def add_child(self,subtree_list):
for subtree in subtree_list:
self.children.append(subtree)
subtree.parent=self
subtree.parent_index=len(self.children)-1
# tick行为树根据不同控制结点逻辑tick子结点
def tick(self,state):
if len(self.children) < 1:
print("error,no child")
if self.type =='?':#选择结点,即或结点
for child in self.children:
val,obj=child.tick(state)
if val=='success':
return val,obj
if val=='running':
return val,obj
return 'failure','?fails'
if self.type =='>':#顺序结点,即与结点
for child in self.children:
val,obj=child.tick(state)
if val=='failure':
return val,obj
if val=='running':
return val,obj
return 'success', '>success'
if self.type =='act':#行动结点
return self.children[0].tick(state)
if self.type =='cond':#条件结点
return self.children[0].tick(state)
def getFirstChild(self):
return self.children[0]
def __str__(self):
print(self.type+'\n')
for child in self.children:
print (child)
return ''
def print_nodes(self):
print(self.type)
for child in self.children:
child.print_nodes()
# 递归统计树中结点数
def count_size(self):
result=1
for child in self.children:
result+= child.count_size()
return result

View File

@ -1,59 +0,0 @@
selector{
cond At(Table,Coffee)
selector{
cond At(Robot,Table), Holding(Coffee)
act PutDown(Table,Coffee)
}
selector{
cond At(Robot,Coffee), NotHolding, At(Robot,Table)
act PickUp(Coffee)
}
selector{
cond Available(Table), Holding(Coffee)
act MoveTo(Table)
}
selector{
cond At(Robot,Coffee), At(Robot,Table), Holding(VacuumCup)
act PutDown(Table,VacuumCup)
}
selector{
cond At(Robot,CoffeeMachine), NotHolding, At(Robot,Table)
act OpCoffeeMachine
}
selector{
cond At(Robot,Coffee), Available(Table), NotHolding
act PickUp(Coffee)
}
selector{
cond At(Robot,CoffeeMachine), At(Robot,Table), Holding(VacuumCup)
act PutDown(Table,VacuumCup)
}
selector{
cond Available(Table), Available(Coffee), NotHolding
act MoveTo(Coffee)
}
selector{
cond Available(Table), At(Robot,CoffeeMachine), NotHolding
act OpCoffeeMachine
}
selector{
cond Available(Table), Available(Coffee), At(Robot,Table), Holding(VacuumCup)
act PutDown(Table,VacuumCup)
}
selector{
cond Available(Table), NotHolding, Available(CoffeeMachine)
act MoveTo(CoffeeMachine)
}
selector{
cond Available(Table), Available(Coffee), Holding(VacuumCup)
act MoveTo(Table)
}
selector{
cond Available(Table), Available(CoffeeMachine), At(Robot,Table), Holding(VacuumCup)
act PutDown(Table,VacuumCup)
}
selector{
cond Available(Table), Available(CoffeeMachine), Holding(VacuumCup)
act MoveTo(Table)
}
}

View File

@ -1,210 +0,0 @@
import copy
import random
from robowaiter.behavior_tree.obtea.BehaviorTree import Leaf,ControlBT
class CondActPair:
def __init__(self, cond_leaf,act_leaf):
self.cond_leaf = cond_leaf
self.act_leaf = act_leaf
#定义行动类,行动包括前提、增加和删除影响
class Action:
def __init__(self,name='anonymous action',pre=set(),add=set(),del_set=set(),cost=1):
self.pre=copy.deepcopy(pre)
self.add=copy.deepcopy(add)
self.del_set=copy.deepcopy(del_set)
self.name=name
self.cost=cost
def __str__(self):
return self.name
#生成随机状态
def generate_random_state(num):
result = set()
for i in range(0,num):
if random.random()>0.5:
result.add(i)
return result
#从状态和行动生成后继状态
def state_transition(state,action):
if not action.pre <= state:
print ('error: action not applicable')
return state
new_state=(state | action.add) - action.del_set
return new_state
#本文所提出的完备规划算法
class OptBTExpAlgorithm:
def __init__(self,verbose=False):
self.bt = None
self.nodes=[]
self.traversed=[]
self.mounted=[]
self.conditions=[]
self.conditions_index=[]
self.verbose=verbose
def clear(self):
self.bt = None
self.nodes = []
self.traversed = []
self.conditions = []
self.conditions_index = []
#运行规划算法从初始状态、目标状态和可用行动计算行为树self.bt
def run_algorithm(self,goal,actions):
if self.verbose:
print("\n算法开始!")
self.bt = ControlBT(type='cond')
# 初始行为树只包含目标条件
gc_node = Leaf(type='cond', content=goal,mincost=0) # 为了统一,都成对出现
ga_node = Leaf(type='act', content=None, mincost=0)
subtree = ControlBT(type='?')
subtree.add_child([copy.deepcopy(gc_node)]) # 子树首先保留所扩展结
self.bt.add_child([subtree])
# self.conditions.append(goal)
cond_anc_pair = CondActPair(cond_leaf=gc_node,act_leaf=ga_node)
self.nodes.append(copy.deepcopy(cond_anc_pair)) # the set of explored but unexpanded conditions
self.traversed = [goal] # the set of expanded conditions
while len(self.nodes)!=0:
# Find the condition for the shortest cost path
pair_node = None
min_cost = float ('inf')
index= -1
for i,cond_anc_pair in enumerate(self.nodes):
if cond_anc_pair.cond_leaf.mincost < min_cost:
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)
# Update self.nodes and self.traversed
self.nodes.pop(index) # the set of explored but unexpanded conditions. self.nodes.remove(pair_node)
c = pair_node.cond_leaf.content # 子树所扩展结点对应的条件一个文字的set
# Mount the action node and extend BT. T = Eapand(T,c,A(c))
if c!=goal:
sequence_structure = ControlBT(type='>')
sequence_structure.add_child(
[copy.deepcopy(pair_node.cond_leaf), copy.deepcopy(pair_node.act_leaf)])
subtree.add_child([copy.deepcopy(sequence_structure)]) # subtree 是回不断变化的它的父亲是self.bt
if self.verbose:
print("完成扩展 a_node= %s,对应的新条件 c_attr= %s,mincost=%d" \
% (cond_anc_pair.act_leaf.content.name, cond_anc_pair.cond_leaf.content,
cond_anc_pair.cond_leaf.mincost))
if self.verbose:
print("遍历所有动作, 寻找符合条件的动作")
# 遍历所有动作, 寻找符合条件的动作
current_mincost = pair_node.cond_leaf.mincost # 当前的最短路径是多少
for i in range(0, len(actions)):
if not c & ((actions[i].pre | actions[i].add) - actions[i].del_set) <= set():
if (c - actions[i].del_set) == c:
if self.verbose:
print("———— 满足条件可以扩展")
c_attr = (actions[i].pre | c) - actions[i].add
# 剪枝操作,现在的条件是以前扩展过的条件的超集
valid = True
for j in self.traversed: # 剪枝操作
if j <= c_attr:
valid = False
if self.verbose:
print("———— --被剪枝")
break
if valid:
# 把符合条件的动作节点都放到列表里
if self.verbose:
print("———— -- %s 符合条件放入列表" % actions[i].name)
c_attr_node = Leaf(type='cond', content=c_attr, mincost=current_mincost + actions[i].cost)
a_attr_node = Leaf(type='act', content=actions[i], mincost=current_mincost + actions[i].cost)
cond_anc_pair = CondActPair(cond_leaf=c_attr_node, act_leaf=a_attr_node)
self.nodes.append(copy.deepcopy(cond_anc_pair)) # condition node list
self.traversed.append(c_attr) # 重点 the set of expanded conditions
if self.verbose:
print("算法结束!\n")
return True
def print_solution(self):
print("========= BT ==========") # 树的bfs遍历
nodes_ls = []
nodes_ls.append(self.bt)
while len(nodes_ls) != 0:
parnode = nodes_ls[0]
print("Parrent:", parnode.type)
for child in parnode.children:
if isinstance(child, Leaf):
print("---- Leaf:", child.content)
elif isinstance(child, ControlBT):
print("---- ControlBT:", child.type)
nodes_ls.append(child)
print()
nodes_ls.pop(0)
print("========= BT ==========\n")
# 返回所有能到达目标状态的初始状态
def get_all_state_leafs(self):
state_leafs=[]
nodes_ls = []
nodes_ls.append(self.bt)
while len(nodes_ls) != 0:
parnode = nodes_ls[0]
for child in parnode.children:
if isinstance(child, Leaf):
if child.type == "cond":
state_leafs.append(child.content)
elif isinstance(child, ControlBT):
nodes_ls.append(child)
nodes_ls.pop(0)
return state_leafs
# 树的dfs
def dfs_ptml(self,parnode):
for child in parnode.children:
if isinstance(child, Leaf):
if child.type == 'cond':
self.ptml_string += "cond "
c_set_str = ', '.join(map(str, child.content)) + "\n"
self.ptml_string += c_set_str
elif child.type == 'act':
self.ptml_string += 'act ' + child.content.name + "\n"
elif isinstance(child, ControlBT):
if parnode.type == '?':
self.ptml_string += "selector{\n"
self.dfs_ptml(parnode=child)
elif parnode.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])
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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

View File

@ -1,125 +0,0 @@
## 代码说明
### 1. `BehaviorTree.py` 实现行为树叶子结点和非叶子结点的定义
- **Leaf**:表示叶节点,可以是动作(`act`)或条件(`cond`)。
- **ControlBT**:代表可能包含控制节点的行为树。它们可以是选择器(`?`)、序列(`>`)、动作节点(`act`)或条件节点(`cond`)。
- 上述两个类都包含 `tick` 方法。
### 2. `OptimalBTExpansionAlgorithm.py` 实现最优行为树扩展算法
![image-20231103191141047](README.assets/image-20231103191141047.png)
定义行动类
```python
#定义行动类,行动包括前提、增加和删除影响
class Action:
def __init__(self,name='anonymous action',pre=set(),add=set(),del_set=set(),cost=1):
self.pre=copy.deepcopy(pre)
self.add=copy.deepcopy(add)
self.del_set=copy.deepcopy(del_set)
self.name=name
self.cost=cost
def __str__(self):
return self.name
```
调用算法
```python
algo = OptBTExpAlgorithm(verbose=True)
algo.clear()
algo.run_algorithm(start, goal, actions) # 使用算法得到行为树在 algo.bt
algo.print_solution() # 打印行为树
val, obj = algo.bt.tick(state) # 执行行为树
algo.save_ptml_file("bt.ptml") # 保存行为树为 ptml 文件
```
### 3. **`tools.py`** 实现打印数据、行为树测试等模块
使用方法
```python
print_action_data_table(goal,start,actions) # 打印所有变量
# 行为树鲁棒性测试,随机生成规划问题
# 设置生成规划问题集的超参数:文字数、解深度、迭代次数
seed=1
literals_num=10
depth = 10
iters= 10
BTTest(seed=seed,literals_num=literals_num,depth=depth,iters=iters)
```
### 4. `example.py` 中设计规划案例 goals, start, actions
```python
def MoveBtoB ():
actions=[]
a = Action(name="Move(b,ab)")
a.pre={'Free(ab)','WayClear'}
a.add={'At(b,ab)'}
a.del_set= {'Free(ab)','At(b,pb)'}
a.cost = 1
actions.append(a)
a=Action(name="Move(s,ab)")
a.pre={'Free(ab)'}
a.add={'Free(ab)','WayClear'}
a.del_set={'Free(ab)','At(s,ps)'}
a.cost = 1
actions.append(a)
a=Action(name="Move(s,as)")
a.pre={'Free(as)'}
a.add={'At(s,ps)','WayClear'}
a.del_set={'Free(as)','At(s,ps)'}
a.cost = 1
actions.append(a)
start = {'Free(ab)','Free(as)','At(b,pb)','At(s,ps)'}
goal= {'At(b,ab)'}
return goal,start,actions
```
### 5. `opt_bt_exp_main.py` 为主函数,在此演示如何调用最优行为树扩展算法得到完全扩展最优行为树
初始化的时候:传入 actions (包含 pre,add,del,cost).
调用的时候,传入 goal 状态集合 (set类型),返回完全最优扩展行为树的 ptml 形式 (string类型)
```python
actions=[
Action(name='PutDown(Table,Coffee)', pre={'Holding(Coffee)','At(Robot,Table)'}, add={'At(Table,Coffee)','NotHolding'}, del_set={'Holding(Coffee)'}, cost=1)
…………
]
algo = BTOptExpInterface(actions)
goal = {'At(Table,Coffee)'}
ptml_string = algo.process(goal,start)
print(ptml_string)
```
两种检测方法,用于检测当前状态 `start` 能否到达目标状态 `goal`
```python
# 判断初始状态能否到达目标状态
start = {'At(Robot,Bar)', 'Holding(VacuumCup)', 'Available(Table)', 'Available(CoffeeMachine)','Available(FrontDesk)'}
# 方法一:算法返回所有可能的初始状态,在里面看看有没有对应的初始状态
right_bt = algo.find_all_leaf_states_contain_start(start)
if not right_bt:
print("ERROR1: The current state cannot reach the goal state!")
else:
print("Right1: The current state can reach the goal state!")
# 方法二:预先跑一边行为树,看能否到达目标状态
right_bt2 = algo.run_bt_from_start(goal,start)
if not right_bt2:
print("ERROR2: The current state cannot reach the goal state!")
else:
print("Right2: The current state can reach the goal state!")
```

View File

@ -1,174 +0,0 @@
from zoo.opt_bt_expansion.OptimalBTExpansionAlgorithm import Action
def MakeCoffee():
actions=[
Action(name='Put(Table,Coffee)', pre={'Holding(Coffee)','At(Table)'}, add={'At(Table,Coffee)','NotHolding'}, del_set={'Holding(Coffee)'}, cost=1),
Action(name='Put(Table,VacuumCup)', pre={'Holding(VacuumCup)','At(Table)'}, add={'At(Table,VacuumCup)','NotHolding'}, del_set={'Holding(VacuumCup)'}, cost=1),
Action(name='Grasp(Coffee)', pre={'NotHolding','At(Coffee)'}, add={'Holding(Coffee)'}, del_set={'NotHolding'}, cost=1),
Action(name='MoveTo(Table)', pre={'Exist(Table)'}, add={'At(Table)'}, del_set={'At(FrontDesk)','At(Coffee)','At(CoffeeMachine)'}, cost=1),
Action(name='MoveTo(Coffee)', pre={'Exist(Coffee)'}, add={'At(Coffee)'}, del_set={'At(FrontDesk)','At(Table)','At(CoffeeMachine)'}, cost=1),
Action(name='MoveTo(CoffeeMachine)', pre={'Exist(CoffeeMachine)'}, add={'At(CoffeeMachine)'}, del_set={'At(FrontDesk)','At(Coffee)','At(Table)'}, cost=1),
Action(name='OpCoffeeMachine', pre={'At(CoffeeMachine)','NotHolding'}, add={'Exist(Coffee)','At(Coffee)'}, del_set=set(), cost=1),
]
start = {'At(FrontDesk)','Holding(VacuumCup)','Exist(Table)','Exist(CoffeeMachine)','Exist(FrontDesk)'}
goal = {'At(Table,Coffee)'}
return goal,start,actions
# 本例子中,将 VacuumCup 放到 FrontDesk比 MoveTo(Table) 再 Put(Table,VacuumCup) 的 cost 要小
def MakeCoffeeCost():
actions=[
Action(name='PutDown(Table,Coffee)', pre={'Holding(Coffee)','At(Robot,Table)'}, add={'At(Table,Coffee)','NotHolding'}, del_set={'Holding(Coffee)'}, cost=1),
Action(name='PutDown(Table,VacuumCup)', pre={'Holding(VacuumCup)','At(Robot,Table)'}, add={'At(Table,VacuumCup)','NotHolding'}, del_set={'Holding(VacuumCup)'}, cost=1),
Action(name='PickUp(Coffee)', pre={'NotHolding','At(Robot,Coffee)'}, add={'Holding(Coffee)'}, del_set={'NotHolding'}, cost=1),
Action(name='MoveTo(Table)', pre={'Available(Table)'}, add={'At(Robot,Table)'}, del_set={'At(Robot,FrontDesk)','At(Robot,Coffee)','At(Robot,CoffeeMachine)'}, cost=1),
Action(name='MoveTo(Coffee)', pre={'Available(Coffee)'}, add={'At(Robot,Coffee)'}, del_set={'At(Robot,FrontDesk)','At(Robot,Table)','At(Robot,CoffeeMachine)'}, cost=1),
Action(name='MoveTo(CoffeeMachine)', pre={'Available(CoffeeMachine)'}, add={'At(Robot,CoffeeMachine)'}, del_set={'At(Robot,FrontDesk)','At(Robot,Coffee)','At(Robot,Table)'}, cost=1),
Action(name='OpCoffeeMachine', pre={'At(Robot,CoffeeMachine)','NotHolding'}, add={'Available(Coffee)','At(Robot,Coffee)'}, del_set=set(), cost=1),
]
start = {'At(Robot,Bar)','Holding(VacuumCup)','Available(Table)','Available(CoffeeMachine)','Available(FrontDesk)'}
goal = {'At(Table,Coffee)'}
return goal,start,actions
# test
def Test():
actions=[
Action(name='a1', pre={6}, add={0,2,4}, del_set={1,5}, cost=1),
Action(name='a2', pre=set(), add={0,1}, del_set=set(), cost=1),
Action(name='a3', pre={1,6}, add={0,2,3,5}, del_set={1,6}, cost=1),
Action(name='a4', pre={0,2,3}, add={4,5}, del_set={0,6}, cost=1),
Action(name='a5', pre={0,1,4}, add={2,3,6}, del_set={0}, cost=1),
]
start = {1,2,6}
goal={0,1,2,4,6}
return goal,start,actions
# def Test():
# actions=[
# Action(name='a1', pre={2}, add={1}, del_set=set(), cost=1),
# Action(name='a2', pre=set(), add={1}, del_set={0,2}, cost=1),
# Action(name='a3', pre={1}, add=set(), del_set={0,2}, cost=1),
# Action(name='a4', pre=set(), add={0}, del_set=set(), cost=1),
# Action(name='a5', pre={1}, add={0,2}, del_set={1}, cost=1),
# Action(name='a6', pre={1}, add=set(), del_set={0,1,2}, cost=1),
# Action(name='a7', pre={1}, add={2}, del_set={0, 2}, cost=1),
# ]
#
# start = {1,2}
# goal={0,1}
# return goal,start,actions
# todo: 最原始的例子
def MoveBtoB_num ():
actions=[]
a = Action(name='a1')
a.pre={1,4}
a.add={"c_goal"}
a.del_set={1,4}
a.cost = 1
actions.append(a)
a=Action(name='a2')
a.pre={1,2,3}
a.add={"c_goal"}
a.del_set={1,2,3}
a.cost = 1
actions.append(a)
a=Action(name='a3')
a.pre={1,2}
a.add={4}
a.del_set={2}
a.cost = 1
actions.append(a)
a=Action(name='a4')
a.pre={"c_start"}
a.add={1,2,3}
a.del_set={"c_start",4}
a.cost = 1
actions.append(a)
start = {"c_start"}
goal={"c_goal"}
return goal,start,actions
# todo: 最原始的例子
def MoveBtoB ():
actions=[]
a = Action(name="Move(b,ab)") #'movebtob'
a.pre={'Free(ab)','WayClear'} #{1,2}
a.add={'At(b,ab)'} #{3}
a.del_set= {'Free(ab)','At(b,pb)'} #{1,4}
a.cost = 1
actions.append(a)
a=Action(name="Move(s,ab)") #'moveatob'
a.pre={'Free(ab)'} #{1}
a.add={'Free(ab)','WayClear'} #{5,2}
a.del_set={'Free(ab)','At(s,ps)'} #{1,6}
a.cost = 1
actions.append(a)
a=Action(name="Move(s,as)") #'moveatoa'
a.pre={'Free(as)'} #{7}
a.add={'At(s,ps)','WayClear'} #{8,2}
a.del_set={'Free(as)','At(s,ps)'} #{7,6}
a.cost = 1
actions.append(a)
start = {'Free(ab)','Free(as)','At(b,pb)','At(s,ps)'} #{1,7,4,6}
goal= {'At(b,ab)'} #{3}
return goal,start,actions
# 小蔡师兄论文里的例子
def Cond2BelongsToCond3():
actions=[]
a = Action(name='a1')
a.pre={1,4}
a.add={"c_goal"}
a.del_set={1,4}
a.cost = 1
actions.append(a)
a=Action(name='a2')
a.pre={1,2,3}
a.add={"c_goal"}
a.del_set={1,2,3}
a.cost = 100
actions.append(a)
a=Action(name='a3')
a.pre={1,2}
a.add={4}
a.del_set={2}
a.cost = 1
actions.append(a)
a=Action(name='a4')
a.pre={"c_start"}
a.add={1,2,3}
a.del_set={"c_start",4}
a.cost = 1
actions.append(a)
start = {"c_start"}
goal={"c_goal"}
return goal,start,actions

View File

@ -1,118 +0,0 @@
from zoo.opt_bt_expansion.OptimalBTExpansionAlgorithm import Action,OptBTExpAlgorithm,state_transition # 调用最优行为树扩展算法
from opt_bt_expansion.examples import *
# 封装好的主接口
class BTOptExpInterface:
def __init__(self, action_list):
"""
Initialize the BTOptExpansion with a list of actions.
:param action_list: A list of actions to be used in the behavior tree.
"""
# self.actions = []
# for act in action_list:
# a = Action(name=act.name)
# a.pre=act['pre']
# a.add=act['add']
# a.del_set= act['del_set']
# a.cost = 1
# self.actions.append(a)
self.actions = action_list
self.has_processed = False
def process(self, goal):
"""
Process the input sets and return a string result.
:param input_set: The set of goal states and the set of initial states.
:return: A PTML string representing the outcome of the behavior tree.
"""
self.goal = goal
self.algo = OptBTExpAlgorithm(verbose=False)
self.algo.clear()
self.algo.run_algorithm(self.goal, self.actions) # 调用算法得到行为树保存至 algo.bt
self.ptml_string = self.algo.get_ptml()
self.has_processed = True
# algo.print_solution() # print behavior tree
return self.ptml_string
# 方法一:查找所有初始状态是否包含当前状态
def find_all_leaf_states_contain_start(self,start):
if not self.has_processed:
raise RuntimeError("The process method must be called before find_all_leaf_states_contain_start!")
# 返回所有能到达目标状态的初始状态
state_leafs = self.algo.get_all_state_leafs()
for state in state_leafs:
if start >= state:
return True
return False
# 方法二:模拟跑一遍行为树,看 start 能够通过执行一系列动作到达 goal
def run_bt_from_start(self,goal,start):
if not self.has_processed:
raise RuntimeError("The process method must be called before run_bt_from_start!")
# 检查是否能到达目标
right_bt = True
state = start
steps = 0
val, obj = self.algo.bt.tick(state)
while val != 'success' and val != 'failure':
state = state_transition(state, obj)
val, obj = self.algo.bt.tick(state)
if (val == 'failure'):
# print("bt fails at step", steps)
right_bt = False
steps += 1
if not goal <= state:
# print("wrong solution", steps)
right_bt = False
else:
pass
# print("right solution", steps)
return right_bt
if __name__ == '__main__' :
# todo: Example Cafe
# todo: Define goal, start, actions
actions=[
Action(name='PutDown(Table,Coffee)', pre={'Holding(Coffee)','At(Robot,Table)'}, add={'At(Table,Coffee)','NotHolding'}, del_set={'Holding(Coffee)'}, cost=1),
Action(name='PutDown(Table,VacuumCup)', pre={'Holding(VacuumCup)','At(Robot,Table)'}, add={'At(Table,VacuumCup)','NotHolding'}, del_set={'Holding(VacuumCup)'}, cost=1),
Action(name='PickUp(Coffee)', pre={'NotHolding','At(Robot,Coffee)'}, add={'Holding(Coffee)'}, del_set={'NotHolding'}, cost=1),
Action(name='MoveTo(Table)', pre={'Available(Table)'}, add={'At(Robot,Table)'}, del_set={'At(Robot,FrontDesk)','At(Robot,Coffee)','At(Robot,CoffeeMachine)'}, cost=1),
Action(name='MoveTo(Coffee)', pre={'Available(Coffee)'}, add={'At(Robot,Coffee)'}, del_set={'At(Robot,FrontDesk)','At(Robot,Table)','At(Robot,CoffeeMachine)'}, cost=1),
Action(name='MoveTo(CoffeeMachine)', pre={'Available(CoffeeMachine)'}, add={'At(Robot,CoffeeMachine)'}, del_set={'At(Robot,FrontDesk)','At(Robot,Coffee)','At(Robot,Table)'}, cost=1),
Action(name='OpCoffeeMachine', pre={'At(Robot,CoffeeMachine)','NotHolding'}, add={'Available(Coffee)','At(Robot,Coffee)'}, del_set=set(), cost=1),
]
algo = BTOptExpInterface(actions)
goal = {'At(Table,Coffee)'}
ptml_string = algo.process(goal)
print(ptml_string)
file_name = "MakeCoffee"
with open(f'./{file_name}.ptml', 'w') as file:
file.write(ptml_string)
# 判断初始状态能否到达目标状态
start = {'At(Robot,Bar)', 'Holding(VacuumCup)', 'Available(Table)', 'Available(CoffeeMachine)','Available(FrontDesk)'}
# 方法一:算法返回所有可能的初始状态,在里面看看有没有对应的初始状态
right_bt = algo.find_all_leaf_states_contain_start(start)
if not right_bt:
print("ERROR1: The current state cannot reach the goal state!")
else:
print("Right1: The current state can reach the goal state!")
# 方法二:预先跑一边行为树,看能否到达目标状态
right_bt2 = algo.run_bt_from_start(goal,start)
if not right_bt2:
print("ERROR2: The current state cannot reach the goal state!")
else:
print("Right2: The current state can reach the goal state!")

View File

@ -1,167 +0,0 @@
from tabulate import tabulate
import numpy as np
import random
from zoo.opt_bt_expansion.OptimalBTExpansionAlgorithm import Action,OptBTExpAlgorithm
import time
def print_action_data_table(goal,start,actions):
data = []
for a in actions:
data.append([a.name , a.pre , a.add , a.del_set , a.cost])
data.append(["Goal" ,goal ," " ,"Start" ,start])
print(tabulate(data, headers=["Name", "Pre", "Add" ,"Del" ,"Cost"], tablefmt="fancy_grid")) # grid plain simple github fancy_grid
# 从状态随机生成一个行动
def generate_from_state(act,state,num):
for i in range(0,num):
if i in state:
if random.random() >0.5:
act.pre.add(i)
if random.random() >0.5:
act.del_set.add(i)
continue
if random.random() > 0.5:
act.add.add(i)
continue
if random.random() >0.5:
act.del_set.add(i)
def print_action(act):
print (act.pre)
print(act.add)
print(act.del_set)
#行为树测试代码
def BTTest(seed=1,literals_num=10,depth=10,iters=10,total_count=1000):
print("============= BT Test ==============")
random.seed(seed)
# 设置生成规划问题集的超参数:文字数、解深度、迭代次数
literals_num=literals_num
depth = depth
iters= iters
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 (total_count):
action_num = 1
# 生成一个规划问题,包括随机的状态和行动,以及目标状态
states = []
actions = []
start = generate_random_state(literals_num)
state = start
states.append(state)
#print (state)
for i in range (0,depth):
a = Action()
generate_from_state(a,state,literals_num)
if not a in actions:
a.name = "a"+str(action_num)
action_num+=1
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()
generate_from_state(a,state,literals_num)
if not a in actions:
a.name = "a"+str(action_num)
action_num+=1
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 = OptBTExpAlgorithm()
#algo = Weakalgorithm()
start_time = time.time()
# print_action_data_table(goal, start, list(actions))
if algo.run_algorithm(start, goal, actions):#运行算法规划后行为树为algo.bt
total_tree_size.append( algo.bt.count_size()-1)
# algo.print_solution() # 打印行为树
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:",success_count,"failure:",failure_count)#算法成功和失败次数
print("Total Tree Size: mean=",np.mean(total_tree_size), "std=",np.std(total_tree_size, ddof=1))#1000次测试树大小
print ("Total Steps Num: mean=",np.mean(total_steps_num),"std=",np.std(total_steps_num,ddof=1))
print ("Average number of states:",np.mean(total_state_num))#1000次问题的平均状态数
print ("Average number of actions",np.mean(total_action_num))#1000次问题的平均行动数
print("Planning Time Total:",planning_time_total,planning_time_total/1000.0)
print("============ End BT Test ===========")
# xiao cai
# success: 1000 failure: 0
# Total Tree Size: mean= 35.303 std= 29.71336526001515
# Total Steps Num: mean= 1.898 std= 0.970844240101644
# Average number of states: 20.678
# Average number of actions 20.0
# Planning Time Total: 0.6280641555786133 0.0006280641555786133
# our start
# success: 1000 failure: 0
# Total Tree Size: mean= 17.945 std= 12.841997192488865
# Total Steps Num: mean= 1.785 std= 0.8120556843187752
# Average number of states: 20.678
# Average number of actions 20.0
# Planning Time Total: 1.4748523235321045 0.0014748523235321046
# our
# success: 1000 failure: 0
# Total Tree Size: mean= 48.764 std= 20.503626574406358
# Total Steps Num: mean= 1.785 std= 0.8120556843187752
# Average number of states: 20.678
# Average number of actions 20.0
# Planning Time Total: 3.3271877765655518 0.0033271877765655516