Skip to content

Commit 76524a1

Browse files
committed
Merge branch 'notebook-test-ci' of github.com:Tigul/pycram-1 into test-test-ci
2 parents 82cc545 + dde07d0 commit 76524a1

File tree

12 files changed

+96
-106
lines changed

12 files changed

+96
-106
lines changed

.github/workflows/notebook-test-ci.yml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,25 @@ jobs:
2626

2727
steps:
2828

29-
- name: Checkout 🛎
29+
- name: Checkout PyCRAM
3030
uses: actions/checkout@v3
31+
with:
32+
path: "ros/src/pycram"
33+
repository: ${{ github.repository }}
34+
ref: ${{ github.ref }}
35+
submodules: "recursive"
36+
37+
# For debugging
38+
- name: Setup tmate session
39+
uses: mxschmitt/action-tmate@v3
40+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
41+
42+
- name: Update PyCRAM source files
43+
run: |
44+
rm -rf /opt/ros/overlay_ws/src/pycram/*
45+
cd /opt/ros/overlay_ws/src/pycram
46+
rm -rf .git .github .gitignore .gitmodules .readthedocs.yaml
47+
cp -r /__w/${{ github.event.repository.name }}/${{ github.event.repository.name }}/ros/src/pycram /opt/ros/overlay_ws/src
3148
3249
# ----------------------------------------------------------------------------------------------------------------
3350

@@ -36,6 +53,7 @@ jobs:
3653
pip3 install --upgrade pip --root-user-action=ignore
3754
cd /opt/ros/overlay_ws/src/pycram
3855
pip3 install -r requirements.txt
56+
sudo apt-get install -y libpq-dev
3957
pip3 install -r requirements-resolver.txt
4058
4159
# ----------------------------------------------------------------------------------------------------------------
@@ -48,9 +66,9 @@ jobs:
4866
- name: Convert Notebooks
4967
run: |
5068
cd /opt/ros/overlay_ws/src/pycram/examples
69+
rm -rf tmp
5170
mkdir tmp
5271
jupytext --to notebook *.md
53-
ls .
5472
mv *.ipynb tmp && cd tmp
5573
5674
- name: Source and start ROS

examples/action_designator.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ First, we need a BulletWorld with a robot.
4040
from pycram.worlds.bullet_world import BulletWorld
4141
from pycram.world_concepts.world_object import Object
4242
from pycram.datastructures.enums import ObjectType, WorldMode
43+
from pycram.datastructures.pose import Pose
4344

4445
world = BulletWorld(WorldMode.GUI)
4546
pr2 = Object("pr2", ObjectType.ROBOT, "pr2.urdf", pose=Pose([1, 2, 0]))

examples/cram_plan_tutorial.md

Lines changed: 39 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
---
1+
from pycram.robot_description import RobotDescriptionfrom pycram.datastructures.enums import ObjectType---
22
jupyter:
33
jupytext:
44
text_representation:
@@ -16,28 +16,26 @@ jupyter:
1616

1717
In this tutorial we will walk through the capabilities of task trees in pycram.
1818

19-
First we have to import the necessary functionality from pycram.
19+
Next we will create a bullet world with a PR2 in a kitchen containing milk and cereal.
2020

2121
```python
22-
from pycram.bullet_world import BulletWorld
23-
from pycram.robot_descriptions import robot_description
24-
import pycram.task
25-
from pycram.resolver.plans import Arms
22+
from pycram.worlds.bullet_world import BulletWorld
23+
from pycram.robot_description import RobotDescription
24+
import pycram.tasktree
25+
from pycram.datastructures.enums import Arms, ObjectType
2626
from pycram.designators.action_designator import *
2727
from pycram.designators.location_designator import *
2828
from pycram.process_module import simulated_robot
2929
from pycram.designators.object_designator import *
30+
from pycram.datastructures.pose import Pose
31+
from pycram.world_concepts.world_object import Object
3032
import anytree
3133
import pycram.failures
32-
```
3334

34-
Next we will create a bullet world with a PR2 in a kitchen containing milk and cereal.
35-
36-
```python
3735
world = BulletWorld()
38-
robot = Object(robot_description.name, "robot", robot_description.name + ".urdf")
36+
robot = Object("pr2", ObjectType.ROBOT, "pr2.urdf")
3937
robot_desig = ObjectDesignatorDescription(names=['pr2']).resolve()
40-
apartment = Object("apartment", "environment", "apartment.urdf", position=[-1.5, -2.5, 0])
38+
apartment = Object("apartment", "environment", "apartment.urdf", pose=Pose([-1.5, -2.5, 0]))
4139
apartment_desig = ObjectDesignatorDescription(names=['apartment']).resolve()
4240
table_top = apartment.get_link_position("cooktop")
4341
# milk = Object("milk", "milk", "milk.stl", position=[table_top[0]-0.15, table_top[1], table_top[2]])
@@ -53,7 +51,7 @@ import numpy as np
5351

5452

5553
def get_n_random_positions(pose_list, n=4, dist=0.5, random=True):
56-
positions = [pos[0] for pos in pose_list[:1000]]
54+
positions = [pose.position_as_list() for pose in pose_list[:1000]]
5755
all_indices = list(range(len(positions)))
5856
print(len(all_indices))
5957
pos_idx = np.random.choice(all_indices) if random else all_indices[0]
@@ -98,11 +96,11 @@ def get_n_random_positions(pose_list, n=4, dist=0.5, random=True):
9896

9997
```python
10098
from pycram.costmaps import SemanticCostmap
101-
from pycram.pose_generator_and_validator import pose_generator
99+
from pycram.pose_generator_and_validator import PoseGenerator
102100

103101
scm = SemanticCostmap(apartment, "island_countertop")
104-
poses_list = list(pose_generator(scm, number_of_samples=-1))
105-
poses_list.sort(reverse=True, key=lambda x: np.linalg.norm(x[0]))
102+
poses_list = list(PoseGenerator(scm, number_of_samples=-1))
103+
poses_list.sort(reverse=True, key=lambda x: np.linalg.norm(x.position_as_list()))
106104
object_poses = get_n_random_positions(poses_list)
107105
object_names = ["bowl", "milk", "breakfast_cereal", "spoon"]
108106
objects = {}
@@ -111,9 +109,9 @@ for obj_name, obj_pose in zip(object_names, object_poses):
111109
print(obj_name)
112110
print(obj_pose)
113111
objects[obj_name] = Object(obj_name, obj_name, obj_name + ".stl",
114-
position=[obj_pose[0][0], obj_pose[0][1], table_top[2]])
115-
objects[obj_name].move_base_to_origin_pos()
116-
objects[obj_name].original_pose = objects[obj_name].get_position_and_orientation()
112+
pose=Pose([obj_pose.position.x, obj_pose.position.y, table_top.z]))
113+
objects[obj_name].move_base_to_origin_pose()
114+
objects[obj_name].original_pose = objects[obj_name].pose
117115
object_desig[obj_name] = ObjectDesignatorDescription(names=[obj_name], types=[obj_name]).resolve()
118116
print(object_poses)
119117
```
@@ -125,24 +123,25 @@ import pybullet as p
125123

126124
for link_name in apartment.links.keys():
127125
world.add_vis_axis(apartment.get_link_pose(link_name))
128-
p.addUserDebugText(link_name, apartment.get_link_position(link_name))
126+
#p.addUserDebugText(link_name, apartment.get_link_position(link_name), physicsClientId=world.id)
129127
```
130128

131129
```python
132130
world.remove_vis_axis()
133-
p.removeAllUserDebugItems()
131+
#p.removeAllUserDebugItems()
134132
```
135133

136134
Finally, we create a plan where the robot parks his arms, walks to the kitchen counter and picks the thingy. Then we
137135
execute the plan.
138136

139137
```python
140138
from pycram.external_interfaces.ik import IKError
139+
from pycram.datastructures.enums import Grasp
141140

142141

143-
@pycram.task.with_tree
142+
@pycram.tasktree.with_tree
144143
def plan(obj, obj_desig, torso=0.2, place="countertop"):
145-
world.reset_bullet_world()
144+
world.reset_world()
146145
with simulated_robot:
147146
ParkArmsActionPerformable(Arms.BOTH).perform()
148147

@@ -154,7 +153,7 @@ def plan(obj, obj_desig, torso=0.2, place="countertop"):
154153
ParkArmsActionPerformable(Arms.BOTH).perform()
155154
good_torsos.append(torso)
156155
picked_up_arm = pose.reachable_arms[0]
157-
PickUpActionPerformable(object_designator=obj_desig, arm=pose.reachable_arms[0], grasp="front").perform()
156+
PickUpActionPerformable(object_designator=obj_desig, arm=pose.reachable_arms[0], grasp=Grasp.FRONT).perform()
158157

159158
ParkArmsActionPerformable(Arms.BOTH).perform()
160159
scm = SemanticCostmapLocation(place, apartment_desig, obj_desig)
@@ -180,7 +179,7 @@ for obj_name in object_names:
180179
try:
181180
plan(objects[obj_name], object_desig[obj_name], torso=torso, place="island_countertop")
182181
done = True
183-
objects[obj_name].original_pose = objects[obj_name].get_position_and_orientation()
182+
objects[obj_name].original_pose = objects[obj_name].pose
184183
except (StopIteration, IKError) as e:
185184
print(type(e))
186185
print(e)
@@ -195,7 +194,7 @@ Now we get the task tree from its module and render it. Rendering can be done wi
195194
anytree package. We will use ascii rendering here for ease of displaying.
196195

197196
```python
198-
tt = pycram.task.task_tree
197+
tt = pycram.tasktree.task_tree
199198
print(anytree.RenderTree(tt, style=anytree.render.AsciiStyle()))
200199
```
201200

@@ -205,8 +204,8 @@ tree. Hence, a NoOperation node is the root of any tree. If we re-execute the pl
205204
tree even though they are not connected.
206205

207206
```python
208-
world.reset_bullet_world()
209-
plan()
207+
world.reset_world()
208+
plan(objects["milk"], object_desig["milk"])
210209
print(anytree.RenderTree(tt, style=anytree.render.AsciiStyle()))
211210
```
212211

@@ -216,9 +215,9 @@ reset objects are available. At the end of a with block the old state is restore
216215
called ``simulation()``.
217216

218217
```python
219-
with pycram.task.SimulatedTaskTree() as stt:
220-
print(anytree.RenderTree(pycram.task.task_tree, style=anytree.render.AsciiStyle()))
221-
print(anytree.RenderTree(pycram.task.task_tree, style=anytree.render.AsciiStyle()))
218+
with pycram.tasktree.SimulatedTaskTree() as stt:
219+
print(anytree.RenderTree(pycram.tasktree.task_tree, style=anytree.render.AsciiStyle()))
220+
print(anytree.RenderTree(pycram.tasktree.task_tree, style=anytree.render.AsciiStyle()))
222221
```
223222

224223
Task tree can be manipulated with ordinary anytree manipulation. If we for example want to discard the second plan, we
@@ -233,30 +232,30 @@ We can now re-execute this (modified) plan by executing the leaf in pre-ordering
233232
functionality. This will not append the re-execution to the task tree.
234233

235234
```python
236-
world.reset_bullet_world()
235+
world.reset_world()
237236
with simulated_robot:
238-
[node.code.execute() for node in tt.root.leaves]
239-
print(anytree.RenderTree(pycram.task.task_tree, style=anytree.render.AsciiStyle()))
237+
[node.action.perform() for node in tt.root.leaves]
238+
print(anytree.RenderTree(pycram.tasktree.task_tree, style=anytree.render.AsciiStyle()))
240239
```
241240

242241
Nodes in the task tree contain additional information about the status and time of a task.
243242

244243
```python
245-
print(pycram.task.task_tree.children[0])
244+
print(pycram.tasktree.task_tree.children[0])
246245
```
247246

248247
The task tree can also be reset to an empty one by invoking:
249248

250249
```python
251-
pycram.task.reset_tree()
252-
print(anytree.RenderTree(pycram.task.task_tree, style=anytree.render.AsciiStyle()))
250+
pycram.tasktree.task_tree.reset_tree()
251+
print(anytree.RenderTree(pycram.tasktree.task_tree, style=anytree.render.AsciiStyle()))
253252
```
254253

255254
If a plan fails using the PlanFailure exception, the plan will not stop. Instead, the error will be logged and saved in
256255
the task tree as a failed subtask. First let's create a simple failing plan and execute it.
257256

258257
```python
259-
@pycram.task.with_tree
258+
@pycram.tasktree.with_tree
260259
def failing_plan():
261260
raise pycram.plan_failures.PlanFailure("Oopsie!")
262261

@@ -267,8 +266,8 @@ failing_plan()
267266
We can now investigate the nodes of the tree, and we will see that the tree indeed contains a failed task.
268267

269268
```python
270-
print(anytree.RenderTree(pycram.task.task_tree, style=anytree.render.AsciiStyle()))
271-
print(pycram.task.task_tree.children[0])
269+
print(anytree.RenderTree(pycram.tasktree.task_tree, style=anytree.render.AsciiStyle()))
270+
print(pycram.tasktree.task_tree.children[0])
272271
```
273272

274273
```python

examples/intro.md

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ from pycram.datastructures.enums import ObjectType, WorldMode
3434
from pycram.datastructures.pose import Pose
3535

3636
world = BulletWorld(mode=WorldMode.GUI)
37+
38+
milk = Object("Milk", ObjectType.MILK, "milk.stl")
39+
pr2 = Object("pr2", ObjectType.ROBOT, "pr2.urdf")
40+
cereal = Object("cereal", ObjectType.BREAKFAST_CEREAL, "breakfast_cereal.stl", pose=Pose([1.4, 1, 0.95]))
3741
```
3842

3943
The BulletWorld allows to render images from arbitrary positions. In the following example we render images with the
@@ -72,12 +76,6 @@ Optional:
7276
* Color
7377
* Ignore Cached Files
7478

75-
If there is only a filename and no path, PyCRAM will check in the resource directory if there is a matching file.
76-
77-
```python
78-
milk = Object("Milk", ObjectType.MILK, "milk.stl")
79-
```
80-
8179
Objects provide methods to change the position and rotation, change the color, attach other objects, set the state of
8280
joints if the objects has any or get the position and orientation of a link.
8381

@@ -88,12 +86,6 @@ methods related to these will not work.
8886
milk.set_position(Pose([1, 0, 0]))
8987
```
9088

91-
To remove an Object from the BulletWorld just call the 'remove' method on the Object.
92-
93-
```python
94-
milk.remove()
95-
```
96-
9789
Since everything inside the BulletWorld is an Object, even a complex environment Object like the kitchen can be spawned
9890
in the same way as the milk.
9991

@@ -187,35 +179,33 @@ Allows for geometric reasoning in the BulletWorld. At the moment the following t
187179
* {meth}`~pycram.world_reasoning.blocking`
188180
* {meth}`~pycram.world_reasoning.supporting`
189181

190-
To show the geometric reasoning we first spawn a robot as well as the milk Object again.
191-
192-
```python
193-
import pycram.world_reasoning as btr
194-
195-
milk = Object("Milk", ObjectType.MILK, "milk.stl", pose=Pose([1, 0, 1]))
196-
pr2 = Object("pr2", ObjectType.ROBOT, "pr2.urdf")
197-
```
198-
199182
We start with testing for visibility
200183

201184
```python
185+
from pycram.world_reasoning import visible
186+
202187
milk.set_position(Pose([1, 0, 1]))
203-
visible = btr.visible(milk, pr2.get_link_pose("wide_stereo_optical_frame"))
188+
visible = visible(milk, pr2.get_link_pose("wide_stereo_optical_frame"))
204189
print(f"Milk visible: {visible}")
205190
```
206191

207192
```python
193+
from pycram.world_reasoning import contact
194+
from pycram.datastructures.world import World
195+
208196
milk.set_position(Pose([1, 0, 0.05]))
209197

210198
plane = World.current_world.objects[0]
211-
contact = btr.contact(milk, plane)
199+
contact = contact(milk, plane)
212200
print(f"Milk is in contact with the floor: {contact}")
213201
```
214202

215203
```python
204+
from pycram.world_reasoning import reachable
205+
216206
milk.set_position(Pose([0.6, -0.5, 0.7]))
217207

218-
reachable = btr.reachable(milk, pr2, "r_gripper_tool_frame")
208+
reachable = reachable(milk, pr2, "r_gripper_tool_frame")
219209
print(f"Milk is reachable for the PR2: {reachable}")
220210
```
221211

@@ -334,14 +324,6 @@ with simulated_robot:
334324
To get familiar with the PyCRAM Framework we will write a simple pick and place plan. This plan will let the robot grasp
335325
a cereal box from the kitchen counter and place it on the kitchen island. This is a simple pick and place plan.
336326

337-
```python
338-
from pycram.designators.object_designator import *
339-
from pycram.datastructures.enums import Grasp
340-
341-
cereal = Object("cereal", ObjectType.BREAKFAST_CEREAL, "breakfast_cereal.stl", pose=Pose([1.4, 1, 0.95]))
342-
343-
```
344-
345327
```python
346328
from pycram.datastructures.enums import Grasp
347329

@@ -351,7 +333,7 @@ robot_desig = ObjectDesignatorDescription(names=["pr2"]).resolve()
351333
with simulated_robot:
352334
ParkArmsAction([Arms.BOTH]).resolve().perform()
353335

354-
MoveTorsoAction([0.3]).resolve().perform()
336+
MoveTorsoAction([0.5]).resolve().perform()
355337

356338
pickup_pose = CostmapLocation(target=cereal_desig.resolve(), reachable_for=robot_desig).resolve()
357339
pickup_arm = pickup_pose.reachable_arms[0]

0 commit comments

Comments
 (0)