Miosy commited on
Commit
25ea53c
·
verified ·
1 Parent(s): 7c41ef4

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +93 -0
  2. aloha_robot_project/Miniconda3-latest-Linux-x86_64.sh +3 -0
  3. aloha_robot_project/calvin/.flake8 +15 -0
  4. aloha_robot_project/calvin/.github/workflows/codeql.yml +41 -0
  5. aloha_robot_project/calvin/.gitignore +146 -0
  6. aloha_robot_project/calvin/.gitmodules +3 -0
  7. aloha_robot_project/calvin/.pre-commit-config.yaml +33 -0
  8. aloha_robot_project/calvin/LICENSE +21 -0
  9. aloha_robot_project/calvin/README.md +377 -0
  10. aloha_robot_project/calvin/RL_with_CALVIN.ipynb +325 -0
  11. aloha_robot_project/calvin/calvin_env/.flake8 +15 -0
  12. aloha_robot_project/calvin/calvin_env/.gitignore +161 -0
  13. aloha_robot_project/calvin/calvin_env/.gitmodules +3 -0
  14. aloha_robot_project/calvin/calvin_env/.pre-commit-config.yaml +32 -0
  15. aloha_robot_project/calvin/calvin_env/LICENSE +21 -0
  16. aloha_robot_project/calvin/calvin_env/README.md +12 -0
  17. aloha_robot_project/calvin/calvin_env/calvin_env/__init__.py +10 -0
  18. aloha_robot_project/calvin/calvin_env/calvin_env/camera/camera.py +91 -0
  19. aloha_robot_project/calvin/calvin_env/calvin_env/camera/gripper_camera.py +46 -0
  20. aloha_robot_project/calvin/calvin_env/calvin_env/camera/static_camera.py +72 -0
  21. aloha_robot_project/calvin/calvin_env/calvin_env/camera/tactile_sensor.py +41 -0
  22. aloha_robot_project/calvin/calvin_env/calvin_env/datarenderer.py +299 -0
  23. aloha_robot_project/calvin/calvin_env/calvin_env/envs/play_lmp_wrapper.py +106 -0
  24. aloha_robot_project/calvin/calvin_env/calvin_env/envs/play_table_env.py +304 -0
  25. aloha_robot_project/calvin/calvin_env/calvin_env/envs/tasks.py +306 -0
  26. aloha_robot_project/calvin/calvin_env/calvin_env/io_utils/data_recorder.py +135 -0
  27. aloha_robot_project/calvin/calvin_env/calvin_env/io_utils/vr_input.py +187 -0
  28. aloha_robot_project/calvin/calvin_env/calvin_env/robot/IKfast.py +72 -0
  29. aloha_robot_project/calvin/calvin_env/calvin_env/robot/mixed_ik.py +118 -0
  30. aloha_robot_project/calvin/calvin_env/calvin_env/robot/robot.py +412 -0
  31. aloha_robot_project/calvin/calvin_env/calvin_env/scene/objects/base_object.py +13 -0
  32. aloha_robot_project/calvin/calvin_env/calvin_env/scene/objects/button.py +76 -0
  33. aloha_robot_project/calvin/calvin_env/calvin_env/scene/objects/door.py +40 -0
  34. aloha_robot_project/calvin/calvin_env/calvin_env/scene/objects/fixed_object.py +41 -0
  35. aloha_robot_project/calvin/calvin_env/calvin_env/scene/objects/light.py +52 -0
  36. aloha_robot_project/calvin/calvin_env/calvin_env/scene/objects/movable_object.py +95 -0
  37. aloha_robot_project/calvin/calvin_env/calvin_env/scene/objects/switch.py +73 -0
  38. aloha_robot_project/calvin/calvin_env/calvin_env/scene/play_table_scene.py +234 -0
  39. aloha_robot_project/calvin/calvin_env/calvin_env/scripts/check_tasks.py +103 -0
  40. aloha_robot_project/calvin/calvin_env/calvin_env/scripts/convert_gripper_actions.py +16 -0
  41. aloha_robot_project/calvin/calvin_env/calvin_env/scripts/dataset_to_euler.py +34 -0
  42. aloha_robot_project/calvin/calvin_env/calvin_env/scripts/record_video_icra.py +112 -0
  43. aloha_robot_project/calvin/calvin_env/calvin_env/scripts/render_low_freq.py +74 -0
  44. aloha_robot_project/calvin/calvin_env/calvin_env/scripts/reset_env_rendered_episode.py +84 -0
  45. aloha_robot_project/calvin/calvin_env/calvin_env/scripts/unnormalize_depth.py +24 -0
  46. aloha_robot_project/calvin/calvin_env/calvin_env/utils/utils.py +233 -0
  47. aloha_robot_project/calvin/calvin_env/calvin_env/vrdatacollector.py +52 -0
  48. aloha_robot_project/calvin/calvin_env/conf/cameras/cameras/gripper.yaml +8 -0
  49. aloha_robot_project/calvin/calvin_env/conf/cameras/cameras/opposing.yaml +10 -0
  50. aloha_robot_project/calvin/calvin_env/conf/cameras/cameras/static.yaml +11 -0
.gitattributes CHANGED
@@ -33,3 +33,96 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ aloha_robot_project/Miniconda3-latest-Linux-x86_64.sh filter=lfs diff=lfs merge=lfs -text
37
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_A/meshes/light_link.STL filter=lfs diff=lfs merge=lfs -text
38
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_A/textures/dark_wood.png filter=lfs diff=lfs merge=lfs -text
39
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_A/textures/dark_wood__black_handle.png filter=lfs diff=lfs merge=lfs -text
40
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_A/textures/dark_wood__gray_handle.png filter=lfs diff=lfs merge=lfs -text
41
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_A/textures/light_wood.png filter=lfs diff=lfs merge=lfs -text
42
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_A/textures/light_wood__black_handle.png filter=lfs diff=lfs merge=lfs -text
43
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_A/textures/light_wood__gray_handle.png filter=lfs diff=lfs merge=lfs -text
44
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_A/textures/wood.png filter=lfs diff=lfs merge=lfs -text
45
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_A/textures/wood__black_handle.png filter=lfs diff=lfs merge=lfs -text
46
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_A/textures/wood__gray_handle.png filter=lfs diff=lfs merge=lfs -text
47
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_B/meshes/light_link.STL filter=lfs diff=lfs merge=lfs -text
48
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_B/textures/dark_wood.png filter=lfs diff=lfs merge=lfs -text
49
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_B/textures/dark_wood__black_handle.png filter=lfs diff=lfs merge=lfs -text
50
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_B/textures/dark_wood__gray_handle.png filter=lfs diff=lfs merge=lfs -text
51
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_B/textures/light_wood.png filter=lfs diff=lfs merge=lfs -text
52
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_B/textures/light_wood__black_handle.png filter=lfs diff=lfs merge=lfs -text
53
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_B/textures/light_wood__gray_handle.png filter=lfs diff=lfs merge=lfs -text
54
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_B/textures/wood.png filter=lfs diff=lfs merge=lfs -text
55
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_B/textures/wood__black_handle.png filter=lfs diff=lfs merge=lfs -text
56
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_B/textures/wood__gray_handle.png filter=lfs diff=lfs merge=lfs -text
57
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_C/meshes/light_link.STL filter=lfs diff=lfs merge=lfs -text
58
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_C/textures/dark_wood.png filter=lfs diff=lfs merge=lfs -text
59
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_C/textures/dark_wood__black_handle.png filter=lfs diff=lfs merge=lfs -text
60
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_C/textures/dark_wood__gray_handle.png filter=lfs diff=lfs merge=lfs -text
61
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_C/textures/light_wood.png filter=lfs diff=lfs merge=lfs -text
62
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_C/textures/light_wood__black_handle.png filter=lfs diff=lfs merge=lfs -text
63
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_C/textures/light_wood__gray_handle.png filter=lfs diff=lfs merge=lfs -text
64
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_C/textures/wood.png filter=lfs diff=lfs merge=lfs -text
65
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_C/textures/wood__black_handle.png filter=lfs diff=lfs merge=lfs -text
66
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_C/textures/wood__gray_handle.png filter=lfs diff=lfs merge=lfs -text
67
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_D/meshes/light_link.STL filter=lfs diff=lfs merge=lfs -text
68
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_D/textures/dark_wood.png filter=lfs diff=lfs merge=lfs -text
69
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_D/textures/dark_wood__black_handle.png filter=lfs diff=lfs merge=lfs -text
70
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_D/textures/dark_wood__gray_handle.png filter=lfs diff=lfs merge=lfs -text
71
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_D/textures/light_wood.png filter=lfs diff=lfs merge=lfs -text
72
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_D/textures/light_wood__black_handle.png filter=lfs diff=lfs merge=lfs -text
73
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_D/textures/light_wood__gray_handle.png filter=lfs diff=lfs merge=lfs -text
74
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_D/textures/wood.png filter=lfs diff=lfs merge=lfs -text
75
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_D/textures/wood__black_handle.png filter=lfs diff=lfs merge=lfs -text
76
+ aloha_robot_project/calvin/calvin_env/data/calvin_table_D/textures/wood__gray_handle.png filter=lfs diff=lfs merge=lfs -text
77
+ aloha_robot_project/calvin/calvin_env/data/franka_panda/meshes/visual/Assem1.SLDASM filter=lfs diff=lfs merge=lfs -text
78
+ aloha_robot_project/calvin/calvin_env/data/franka_panda/meshes/visual/FRANKA_Finger.SLDPRT filter=lfs diff=lfs merge=lfs -text
79
+ aloha_robot_project/calvin/calvin_env/data/franka_panda/meshes/visual/digit.STL filter=lfs diff=lfs merge=lfs -text
80
+ aloha_robot_project/calvin/calvin_env/data/franka_panda/meshes/visual/digit_gel_only.STL filter=lfs diff=lfs merge=lfs -text
81
+ aloha_robot_project/calvin/calvin_env/data/franka_panda/meshes/visual/finger.SLDPRT filter=lfs diff=lfs merge=lfs -text
82
+ aloha_robot_project/calvin/calvin_env/tacto/examples/allegro_hand_description/meshes/base_link.STL filter=lfs diff=lfs merge=lfs -text
83
+ aloha_robot_project/calvin/calvin_env/tacto/examples/allegro_hand_description/meshes/base_link_left.STL filter=lfs diff=lfs merge=lfs -text
84
+ aloha_robot_project/calvin/calvin_env/tacto/examples/allegro_hand_description/meshes/digit.STL filter=lfs diff=lfs merge=lfs -text
85
+ aloha_robot_project/calvin/calvin_env/tacto/examples/allegro_hand_description/meshes/link_12.0_left.STL filter=lfs diff=lfs merge=lfs -text
86
+ aloha_robot_project/calvin/calvin_env/tacto/examples/allegro_hand_description/meshes/link_12.0_right.STL filter=lfs diff=lfs merge=lfs -text
87
+ aloha_robot_project/calvin/calvin_env/tacto/examples/sawyer_robot/sawyer_description/meshes/sawyer_mp1/l6.STL filter=lfs diff=lfs merge=lfs -text
88
+ aloha_robot_project/calvin/calvin_env/tacto/examples/sawyer_robot/sawyer_description/meshes/sawyer_mp3/l0.STL filter=lfs diff=lfs merge=lfs -text
89
+ aloha_robot_project/calvin/calvin_env/tacto/examples/sawyer_robot/sawyer_description/meshes/sawyer_mp3/l1.STL filter=lfs diff=lfs merge=lfs -text
90
+ aloha_robot_project/calvin/calvin_env/tacto/examples/sawyer_robot/sawyer_description/meshes/sawyer_pv/base.STL filter=lfs diff=lfs merge=lfs -text
91
+ aloha_robot_project/calvin/calvin_env/tacto/examples/sawyer_robot/sawyer_description/meshes/sawyer_pv/head.STL filter=lfs diff=lfs merge=lfs -text
92
+ aloha_robot_project/calvin/calvin_env/tacto/examples/sawyer_robot/sawyer_description/meshes/sawyer_pv/l0.STL filter=lfs diff=lfs merge=lfs -text
93
+ aloha_robot_project/calvin/calvin_env/tacto/examples/sawyer_robot/sawyer_description/meshes/sawyer_pv/l1.STL filter=lfs diff=lfs merge=lfs -text
94
+ aloha_robot_project/calvin/calvin_env/tacto/examples/sawyer_robot/sawyer_description/meshes/sawyer_pv/l2.STL filter=lfs diff=lfs merge=lfs -text
95
+ aloha_robot_project/calvin/calvin_env/tacto/examples/sawyer_robot/sawyer_description/meshes/sawyer_pv/l3.STL filter=lfs diff=lfs merge=lfs -text
96
+ aloha_robot_project/calvin/calvin_env/tacto/examples/sawyer_robot/sawyer_description/meshes/sawyer_pv/l4.STL filter=lfs diff=lfs merge=lfs -text
97
+ aloha_robot_project/calvin/calvin_env/tacto/examples/sawyer_robot/sawyer_description/meshes/sawyer_pv/l5.STL filter=lfs diff=lfs merge=lfs -text
98
+ aloha_robot_project/calvin/calvin_env/tacto/examples/sawyer_robot/sawyer_description/meshes/sawyer_pv/l6.STL filter=lfs diff=lfs merge=lfs -text
99
+ aloha_robot_project/calvin/calvin_env/tacto/examples/sawyer_robot/sawyer_description/meshes/sawyer_pv/pedestal.STL filter=lfs diff=lfs merge=lfs -text
100
+ aloha_robot_project/calvin/calvin_env/tacto/examples/wsg50/WSG-FMF.stl filter=lfs diff=lfs merge=lfs -text
101
+ aloha_robot_project/calvin/calvin_env/tacto/examples/wsg50/digit.STL filter=lfs diff=lfs merge=lfs -text
102
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/sawyer_robot/sawyer_description/meshes/sawyer_mp1/l6.STL filter=lfs diff=lfs merge=lfs -text
103
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/sawyer_robot/sawyer_description/meshes/sawyer_mp3/l0.STL filter=lfs diff=lfs merge=lfs -text
104
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/sawyer_robot/sawyer_description/meshes/sawyer_mp3/l1.STL filter=lfs diff=lfs merge=lfs -text
105
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/sawyer_robot/sawyer_description/meshes/sawyer_pv/base.STL filter=lfs diff=lfs merge=lfs -text
106
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/sawyer_robot/sawyer_description/meshes/sawyer_pv/head.STL filter=lfs diff=lfs merge=lfs -text
107
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/sawyer_robot/sawyer_description/meshes/sawyer_pv/l0.STL filter=lfs diff=lfs merge=lfs -text
108
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/sawyer_robot/sawyer_description/meshes/sawyer_pv/l1.STL filter=lfs diff=lfs merge=lfs -text
109
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/sawyer_robot/sawyer_description/meshes/sawyer_pv/l2.STL filter=lfs diff=lfs merge=lfs -text
110
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/sawyer_robot/sawyer_description/meshes/sawyer_pv/l3.STL filter=lfs diff=lfs merge=lfs -text
111
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/sawyer_robot/sawyer_description/meshes/sawyer_pv/l4.STL filter=lfs diff=lfs merge=lfs -text
112
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/sawyer_robot/sawyer_description/meshes/sawyer_pv/l5.STL filter=lfs diff=lfs merge=lfs -text
113
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/sawyer_robot/sawyer_description/meshes/sawyer_pv/l6.STL filter=lfs diff=lfs merge=lfs -text
114
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/sawyer_robot/sawyer_description/meshes/sawyer_pv/pedestal.STL filter=lfs diff=lfs merge=lfs -text
115
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/wsg50/WSG-FMF.stl filter=lfs diff=lfs merge=lfs -text
116
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/grasp_stability/setup/wsg50/digit.STL filter=lfs diff=lfs merge=lfs -text
117
+ aloha_robot_project/calvin/calvin_env/tacto/experiments/rolling/setup/sensors/digit.STL filter=lfs diff=lfs merge=lfs -text
118
+ aloha_robot_project/calvin/calvin_env/tacto/meshes/digit.STL filter=lfs diff=lfs merge=lfs -text
119
+ aloha_robot_project/calvin/calvin_env/tacto/meshes/omnitact.STL filter=lfs diff=lfs merge=lfs -text
120
+ aloha_robot_project/calvin/calvin_env/tacto/meshes/omnitact_mod_pybullet.STL filter=lfs diff=lfs merge=lfs -text
121
+ aloha_robot_project/calvin/calvin_env/tacto/website/static/img/demo_allegro.gif filter=lfs diff=lfs merge=lfs -text
122
+ aloha_robot_project/calvin/calvin_env/tacto/website/static/img/demo_digit.gif filter=lfs diff=lfs merge=lfs -text
123
+ aloha_robot_project/calvin/calvin_env/tacto/website/static/img/demo_grasp.gif filter=lfs diff=lfs merge=lfs -text
124
+ aloha_robot_project/calvin/calvin_env/tacto/website/static/img/demo_omnitact.gif filter=lfs diff=lfs merge=lfs -text
125
+ aloha_robot_project/calvin/calvin_env/tacto/website/static/img/demo_rolling.gif filter=lfs diff=lfs merge=lfs -text
126
+ aloha_robot_project/calvin/calvin_env/tacto/website/static/img/demo_shadow.gif filter=lfs diff=lfs merge=lfs -text
127
+ aloha_robot_project/calvin/media/sensors.png filter=lfs diff=lfs merge=lfs -text
128
+ aloha_robot_project/calvin/media/teaser.png filter=lfs diff=lfs merge=lfs -text
aloha_robot_project/Miniconda3-latest-Linux-x86_64.sh ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e0b10e050e8928e2eb9aad2c522ee3b5d31d30048b8a9997663a8a460d538cef
3
+ size 156772981
aloha_robot_project/calvin/.flake8 ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [flake8]
2
+ exclude = .git
3
+ # Default is 79 in PEP 8
4
+ max-line-length = 120
5
+ select = E,F,W,C
6
+ ignore=W503, # line break before binary operator, need for black
7
+ E203, # whitespace before ':'. Opposite convention enforced by black
8
+ E731, # do not assign a lambda expression, use a def
9
+ E722,
10
+ F401,
11
+ F841,
12
+ E402, # module level import not at top of file
13
+ E741, # ambiguous variable name
14
+ E501, # line too long. Handled by black
15
+ C406, # Unnecessary list literal - rewrite as a dict literal
aloha_robot_project/calvin/.github/workflows/codeql.yml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: "CodeQL"
2
+
3
+ on:
4
+ push:
5
+ branches: [ "main" ]
6
+ pull_request:
7
+ branches: [ "main" ]
8
+ schedule:
9
+ - cron: "33 22 * * 4"
10
+
11
+ jobs:
12
+ analyze:
13
+ name: Analyze
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ actions: read
17
+ contents: read
18
+ security-events: write
19
+
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ language: [ python ]
24
+
25
+ steps:
26
+ - name: Checkout
27
+ uses: actions/checkout@v3
28
+
29
+ - name: Initialize CodeQL
30
+ uses: github/codeql-action/init@v2
31
+ with:
32
+ languages: ${{ matrix.language }}
33
+ queries: +security-and-quality
34
+
35
+ - name: Autobuild
36
+ uses: github/codeql-action/autobuild@v2
37
+
38
+ - name: Perform CodeQL Analysis
39
+ uses: github/codeql-action/analyze@v2
40
+ with:
41
+ category: "/language:${{ matrix.language }}"
aloha_robot_project/calvin/.gitignore ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ pip-wheel-metadata/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py,cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # IPython
81
+ profile_default/
82
+ ipython_config.py
83
+
84
+ # pyenv
85
+ .python-version
86
+
87
+ # pipenv
88
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
90
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
91
+ # install all needed dependencies.
92
+ #Pipfile.lock
93
+
94
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95
+ __pypackages__/
96
+
97
+ # Celery stuff
98
+ celerybeat-schedule
99
+ celerybeat.pid
100
+
101
+ # SageMath parsed files
102
+ *.sage.py
103
+
104
+ # Environments
105
+ .env
106
+ .venv
107
+ env/
108
+ venv/
109
+ ENV/
110
+ env.bak/
111
+ venv.bak/
112
+
113
+ # Spyder project settings
114
+ .spyderproject
115
+ .spyproject
116
+
117
+ # Rope project settings
118
+ .ropeproject
119
+
120
+ # mkdocs documentation
121
+ /site
122
+
123
+ # mypy
124
+ .mypy_cache/
125
+ .dmypy.json
126
+ dmypy.json
127
+
128
+ # Pyre type checker
129
+ .pyre/
130
+
131
+ # vscode
132
+ .vscode
133
+
134
+ */runs/*
135
+
136
+ dataset/task_D_D/*
137
+ dataset/task_ABCD_D/*
138
+ dataset/task_ABC_D/*
139
+
140
+ .idea/*
141
+
142
+ # Ignore venv created as part of installation instructions
143
+ calvin_venv/*
144
+
145
+ # Ignore datasets as downloaded according to instructions
146
+ dataset/*
aloha_robot_project/calvin/.gitmodules ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ [submodule "calvin_env"]
2
+ path = calvin_env
3
+ url = https://github.com/mees/calvin_env.git
aloha_robot_project/calvin/.pre-commit-config.yaml ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ default_language_version:
2
+ python: python3.8
3
+ repos:
4
+ - repo: https://github.com/psf/black
5
+ rev: 22.3.0
6
+ hooks:
7
+ - id: black
8
+ language_version: python3.8
9
+
10
+ - repo: https://gitlab.com/pycqa/flake8
11
+ rev: 3.8.4
12
+ hooks:
13
+ - id: flake8
14
+ additional_dependencies: [-e, "git+git://github.com/pycqa/pyflakes.git@c72d6cf#egg=pyflakes"]
15
+
16
+ - repo: https://github.com/pycqa/isort
17
+ rev: 5.7.0
18
+ hooks:
19
+ - id: isort
20
+
21
+ - repo: https://github.com/pre-commit/mirrors-mypy
22
+ rev: v0.812
23
+ hooks:
24
+ - id: mypy
25
+ args: [--ignore-missing-imports, --warn-no-return, --warn-redundant-casts, --disallow-incomplete-defs]
26
+ additional_dependencies: [pytorch-lightning==1.4.9, torch==1.10.0, numpy]
27
+
28
+ - repo: https://github.com/pre-commit/pre-commit-hooks
29
+ rev: v4.0.1
30
+ hooks:
31
+ - id: check-yaml
32
+ - id: trailing-whitespace
33
+ - id: end-of-file-fixer
aloha_robot_project/calvin/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Oier Mees
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
aloha_robot_project/calvin/README.md ADDED
@@ -0,0 +1,377 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CALVIN
2
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
3
+ [![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/mees/calvin.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/mees/calvin/context:python)
4
+ [![Total alerts](https://img.shields.io/lgtm/alerts/g/mees/calvin.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/mees/calvin/alerts/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ [<b>CALVIN - A benchmark for Language-Conditioned Policy Learning for Long-Horizon Robot Manipulation Tasks</b>](https://arxiv.org/pdf/2112.03227.pdf)
8
+
9
+ [Oier Mees](https://www.oiermees.com/), [Lukas Hermann](https://lukashermann.github.io/), [Erick Rosete](https://www.erickrosete.com/), [Wolfram Burgard](http://www2.informatik.uni-freiburg.de/~burgard)
10
+
11
+ #### CALVIN won the 2022 IEEE Robotics and Automation Letters (RA-L) Best Paper Award!
12
+
13
+
14
+ We present **CALVIN** (**C**omposing **A**ctions from **L**anguage and **Vi**sio**n**), an open-source simulated benchmark to learn long-horizon language-conditioned tasks.
15
+ Our aim is to make it possible to develop agents that can solve many robotic manipulation tasks over a long horizon, from onboard sensors, and specified only via human language. CALVIN tasks are more complex in terms of sequence length, action space, and language than existing vision-and-language task datasets and supports flexible specification of sensor
16
+ suites.
17
+
18
+ ![](media/teaser.png)
19
+
20
+ # :computer: Quick Start
21
+ To begin, clone this repository locally
22
+ ```bash
23
+ git clone --recurse-submodules https://github.com/mees/calvin.git
24
+ $ export CALVIN_ROOT=$(pwd)/calvin
25
+
26
+ ```
27
+ Install requirements:
28
+ ```bash
29
+ $ cd $CALVIN_ROOT
30
+ $ conda create -n calvin_venv python=3.8 # or use virtualenv
31
+ $ conda activate calvin_venv
32
+ $ sh install.sh
33
+ ```
34
+ If you encounter problems installing pyhash, you might have to downgrade setuptools to a version below 58.
35
+
36
+ Download dataset (choose which split you want to download with the argument `D`, `ABC` or `ABCD`): \
37
+ If you want to get started without downloading the whole dataset, use the argument `debug` to download a small debug dataset (1.3 GB).
38
+ ```bash
39
+ $ cd $CALVIN_ROOT/dataset
40
+ $ sh download_data.sh D | ABC | ABCD | debug
41
+ ```
42
+ ## :weight_lifting_man: Train Baseline Agent
43
+ Train baseline models:
44
+ ```bash
45
+ $ cd $CALVIN_ROOT/calvin_models/calvin_agent
46
+ $ python training.py datamodule.root_data_dir=/path/to/dataset/ datamodule/datasets=vision_lang_shm
47
+ ```
48
+ The `vision_lang_shm` option loads the CALVIN dataset into shared memory at the beginning of the training,
49
+ speeding up the data loading during training.
50
+ The preparation of the shared memory cache will take some time
51
+ (approx. 20 min at our SLURM cluster). \
52
+ If you want to use the original data loader (e.g. for debugging) just override the command with `datamodule/datasets=vision_lang`. \
53
+ For an additional speed up, you can disable the evaluation callbacks during training by adding `~callbacks/rollout` and `~callbacks/rollout_lh`
54
+
55
+ You want to scale your training to a multi-gpu setup? Just specify the [number of GPUs](https://pytorch-lightning.readthedocs.io/en/latest/advanced/multi_gpu.html#select-gpu-devices) and DDP will automatically be used
56
+ for training thanks to [Pytorch Lightning](https://www.pytorchlightning.ai/).
57
+ To train on all available GPUs:
58
+ ```bash
59
+ $ python training.py trainer.gpus=-1
60
+ ```
61
+ If you have access to a Slurm cluster, follow this [guide](https://github.com/mees/calvin/blob/main/slurm_scripts/README.md).
62
+
63
+ You can use [Hydra's](https://hydra.cc/) flexible overriding system for changing hyperparameters.
64
+ For example, to train a model with rgb images from both static camera and the gripper camera with relative actions:
65
+ ```bash
66
+ $ python training.py datamodule/observation_space=lang_rgb_static_gripper_rel_act model/perceptual_encoder=gripper_cam
67
+ ```
68
+ To train a model with RGB-D from both cameras:
69
+ ```bash
70
+ $ python training.py datamodule/observation_space=lang_rgbd_both model/perceptual_encoder=RGBD_both
71
+ ```
72
+ To train a model with rgb images from the static camera and visual tactile observations with absolute actions:
73
+ ```bash
74
+ $ python training.py datamodule/observation_space=lang_rgb_static_tactile_abs_act model/perceptual_encoder=static_RGB_tactile
75
+ ```
76
+
77
+ To see all available hyperparameters:
78
+ ```console
79
+ $ python training.py --help
80
+ ```
81
+ To resume a training, just override the hydra working directory :
82
+ ```console
83
+ $ python training.py hydra.run.dir=runs/my_dir
84
+ ```
85
+
86
+ ## :framed_picture: Sensory Observations
87
+ CALVIN supports a range of sensors commonly utilized for visuomotor control:
88
+ 1. **Static camera RGB images** - with shape `200x200x3`.
89
+ 2. **Static camera Depth maps** - with shape `200x200`.
90
+ 3. **Gripper camera RGB images** - with shape `84x84x3`.
91
+ 4. **Gripper camera Depth maps** - with shape `84x84`.
92
+ 5. **Tactile image** - with shape `120x160x6`.
93
+ 6. **Proprioceptive state** - EE position (3), EE orientation in euler angles (3), gripper width (1), joint positions (7), gripper action (1).
94
+
95
+ <p align="center">
96
+ <img src="media/sensors.png" alt="" width="50%">
97
+ </p>
98
+
99
+ ## :joystick: Action Space
100
+ In CALVIN, the agent must perform closed-loop continuous control to follow unconstrained language instructions characterizing complex robot manipulation tasks, sending continuous actions to the robot at 30hz.
101
+ In order to give researchers and practitioners the freedom to experiment with different action spaces, CALVIN supports the following actions spaces:
102
+ 1. **Absolute cartesian pose** - EE position (3), EE orientation in euler angles (3), gripper action (1).
103
+ 2. **Relative cartesian displacement** - EE position (3), EE orientation in euler angles (3), gripper action (1).
104
+ 3. **Joint action** - Joint positions (7), gripper action (1).
105
+
106
+ For more information, please refer to this more detailed [README](https://github.com/mees/calvin/blob/main/dataset/README.md).
107
+
108
+ ## :muscle: Evaluation: The Calvin Challenge
109
+ ### Long-horizon Multi-task Language Control (LH-MTLC)
110
+ The aim of the CALVIN benchmark is to evaluate the learning of long-horizon language-conditioned continuous control policies. In this setting, a single agent must solve complex manipulation tasks by understanding a series of unconstrained language expressions in a row, e.g., “open the drawer. . . pick up the blue block. . . now push the block into the drawer. . . now open the sliding door”.
111
+ We provide an evaluation protocol with evaluation modes of varying difficulty by choosing different combinations of sensor suites and amounts of training environments.
112
+ To avoid a biased initial position, the robot is reset to a neutral position before every multi-step sequence.
113
+
114
+ To evaluate a trained calvin baseline agent, run the following command:
115
+
116
+ ```
117
+ $ cd $CALVIN_ROOT/calvin_models/calvin_agent
118
+ $ python evaluation/evaluate_policy.py --dataset_path <PATH/TO/DATASET> --train_folder <PATH/TO/TRAINING/FOLDER>
119
+ ```
120
+ Optional arguments:
121
+
122
+ - `--checkpoint <PATH/TO/CHECKPOINT>`: by default, the evaluation loads the last checkpoint in the training log directory.
123
+ You can instead specify the path to another checkpoint by adding this to the evaluation command.
124
+ - `--debug`: print debug information and visualize environment.
125
+
126
+ If you want to evaluate your own model architecture on the CALVIN challenge, you can implement the `CustomModel` class in `evaluate_policy.py`
127
+ as an interface to your agent. You need to implement the following methods:
128
+
129
+ - \_\_init__():
130
+ gets called once at the beginning of the evaluation.
131
+ - reset(): gets called at the beginning of each evaluation sequence.
132
+ - step(obs, goal): gets called every step and returns the predicted action.
133
+
134
+ Then evaluate the model by running:
135
+ ```
136
+ $ python evaluation/evaluate_policy.py --dataset_path <PATH/TO/DATASET> --custom_model
137
+ ```
138
+
139
+ You are also free to use your own language model instead of using the precomputed language embeddings provided by CALVIN.
140
+ For this, implement `CustomLangEmbeddings` in `evaluate_policy.py` and add `--custom_lang_embeddings` to the evaluation command.
141
+
142
+ ### Multi-task Language Control (MTLC)
143
+ Alternatively, you can evaluate the policy on single tasks and without resetting the robot to a neutral position.
144
+ Note that this evaluation is currently only available for our baseline agent.
145
+ ```
146
+ $ python evaluation/evaluate_policy_singlestep.py --dataset_path <PATH/TO/DATASET> --train_folder <PATH/TO/TRAINING/FOLDER> [--checkpoint <PATH/TO/CHECKPOINT>] [--debug]
147
+ ```
148
+
149
+ ### Pre-trained Model
150
+ Download the [MCIL](http://calvin.cs.uni-freiburg.de/model_weights/D_D_static_rgb_baseline.zip) model checkpoint trained on the static camera rgb images on environment D.
151
+ ```
152
+ $ wget http://calvin.cs.uni-freiburg.de/model_weights/D_D_static_rgb_baseline.zip
153
+ $ unzip D_D_static_rgb_baseline.zip
154
+ ```
155
+ ## :speech_balloon: Relabeling Raw Language Annotations
156
+ You want to try learning language conditioned policies in CALVIN with a new awesome language model?
157
+
158
+ We provide an [example script](https://github.com/mees/calvin/blob/main/calvin_models/calvin_agent/utils/relabel_with_new_lang_model.py) to relabel the annotations with different language model provided in [SBert](https://www.sbert.net/docs/pretrained_models.html), such as the larger MPNet (paraphrase-mpnet-base-v2) or its corresponding multilingual model (paraphrase-multilingual-mpnet-base-v2).
159
+ The supported options are "mini", "mpnet" and "multi". If you want to try different SBert models, just change the model name [here](https://github.com/mees/calvin/blob/main/calvin_models/calvin_agent/models/encoders/language_network.py#L18).
160
+ ```
161
+ cd $CALVIN_ROOT/calvin_models/calvin_agent
162
+ python utils/relabel_with_new_lang_model.py +path=$CALVIN_ROOT/dataset/task_D_D/ +name_folder=new_lang_model_folder model.nlp_model=mpnet
163
+ ```
164
+ If you additionally want to sample different language annotations for each sequence (from the same task annotations) in the training split run the same command with the parameter `reannotate=true`.
165
+
166
+ ## :chart_with_upwards_trend: SOTA Models
167
+ Open-source models that outperform the MCIL baselines from CALVIN:
168
+
169
+ For a detailed overview of the evaluation performances, have a look at our **[LEADERBOARD](http://calvin.cs.uni-freiburg.de/)**.
170
+
171
+ <br>
172
+ <b> Grounding Language with Visual Affordances over Unstructured Data</b>
173
+ <br>
174
+ Oier Mees, Jessica Borja-Diaz, Wolfram Burgard
175
+ <br>
176
+ <a href="https://arxiv.org/pdf/2210.01911.pdf"> Paper</a>, <a href="https://github.com/mees/hulc2"> Code </a>
177
+
178
+ <b> FLOWER: Democratizing Generalist Robot Policies with Efficient Vision-Language-Action Flow Policies </b>
179
+ <br>
180
+ Moritz Reuss, Hongyi Zhou, Marcel Rühle, Ömer Erdinç Yağmurlu, Fabian Otto, Rudolf Lioutikov
181
+ <br>
182
+ <a href="https://arxiv.org/pdf/2509.04996"> Paper</a>, <a href="https://intuitive-robots.github.io/flower_vla/"> Code </a>
183
+
184
+
185
+ <b> Unified Vision-Language-Action Model </b>
186
+ <br>
187
+ Yuqi Wang, Xinghang Li, Wenxuan Wang, Junbo Zhang, Yingyan Li, Yuntao Chen, Xinlong Wang, Zhaoxiang Zhang
188
+ <br>
189
+ <a href="https://arxiv.org/pdf/2506.19850"> Paper</a>, <a href="https://robertwyq.github.io/univla.github.io/"> Code </a>
190
+
191
+ <b> Predictive Inverse Dynamics Models are Scalable Learners for Robotic Manipulation </b>
192
+ <br>
193
+ Yang Tian, Sizhe Yang, Jia Zeng, Ping Wang, Dahua Lin, Hao Dong, Jiangmiao Pang
194
+ <br>
195
+ <a href="https://arxiv.org/pdf/2412.15109"> Paper</a>, <a href="https://github.com/OpenRobotLab/Seer/"> Code </a>
196
+
197
+ <b> Diffusion Transformer Policy: Scaling Diffusion Transformer for Generalist Vision-Language-Action Learning </b>
198
+ <br>
199
+ Zhi Hou, Tianyi Zhang, Yuwen Xiong, Hengjun Pu, Chengyang Zhao, Ronglei Tong, Yu Qiao, Jifeng Dai, Yuntao Chen
200
+ <br>
201
+ <a href="https://arxiv.org/pdf/2410.15959"> Paper</a>, <a href="https://github.com/zhihou7/dit_policy_vla"> Code </a>
202
+
203
+ <b> GR-MG: Leveraging Partially Annotated Data via Multi-Modal Goal Conditioned Policy </b>
204
+ <br>
205
+ Peiyan Li, Hongtao Wu, Yan Huang, Chilam Cheang, Liang Wang, Tao Kong
206
+ <br>
207
+ <a href="https://arxiv.org/pdf/2408.14368"> Paper</a>, <a href="https://github.com/bytedance/GR-MG/"> Code </a>
208
+
209
+ <b> GHIL-Glue: Hierarchical Control with Filtered Subgoal Images </b>
210
+ <br>
211
+ Kyle B Hatch, Ashwin Balakrishna, Oier Mees, Suraj Nair, Seohong Park, Blake Wulfe, Masha Itkina, Benjamin Eysenbach, Sergey Levine, Thomas Kollar, Benjamin Burchfiel
212
+ <br>
213
+ <a href="https://arxiv.org/pdf/2410.20018"> Paper</a>, <a href="https://github.com/kyle-hatch-tri/ghil-glue"> Code </a>
214
+
215
+ <b> Efficient Diffusion Transformer Policies with Mixture of Expert Denoisers for Multitask Learning </b>
216
+ <br>
217
+ Moritz Reuss, Jyothish Pari, Pulkit Agrawal, Rudolf Lioutikov
218
+ <br>
219
+ <a href="https://arxiv.org/pdf/2412.12953"> Paper</a>, <a href="https://github.com/intuitive-robots/MoDE_Diffusion_Policy"> Code </a>
220
+
221
+ <b> Incorporating Task Progress Knowledge for Subgoal Generation in Robotic Manipulation through Image Edits </b>
222
+ <br>
223
+ Xuhui Kang, Yen-Ling Kuo
224
+ <br>
225
+ <a href="https://arxiv.org/pdf/2410.11013"> Paper</a>, <a href="https://github.com/Shua-Kang/TaKSIE"> Code </a>
226
+
227
+ <b> Closed-Loop Visuomotor Control with Generative Expectation for Robotic Manipulation </b>
228
+ <br>
229
+ Qingwen Bu, Jia Zeng, Li Chen, Yanchao Yang, Guyue Zhou, Junchi Yan, Ping Luo, Heming Cui, Yi Ma, Hongyang Li
230
+ <br>
231
+ <a href="https://arxiv.org/pdf/2409.09016"> Paper</a>, <a href="https://github.com/OpenDriveLab/CLOVER"> Code </a>
232
+
233
+ <b> DeeR-VLA: Dynamic Inference of Multimodal Large Language Models for Efficient Robot Execution </b>
234
+ <br>
235
+ Yang Yue, Yulin Wang, Bingyi Kang, Yizeng Han, Shenzhi Wang, Shiji Song, Jiashi Feng, Gao Huang
236
+ <br>
237
+ <a href="https://arxiv.org/pdf/2411.02359"> Paper</a>, <a href="https://github.com/yueyang130/DeeR-VLA"> Code </a>
238
+
239
+ <b> RoboUniView: Visual-Language Model with Unified View Representation for Robotic Manipulation </b>
240
+ <br>
241
+ Fanfan Liu, Feng Yan, Liming Zheng, Yiyang Huang, Chengjian Feng, Lin Ma
242
+ <br>
243
+ <a href="https://arxiv.org/pdf/2406.18977v2"> Paper</a>, <a href="https://github.com/liufanfanlff/RoboUniview"> Code </a>
244
+
245
+ <b> Multimodal Diffusion Transformer: Learning Versatile Behavior from Multimodal Goals </b>
246
+ <br>
247
+ Moritz Reuss, Ömer Erdinç Yağmurlu, Fabian Wenzel, Rudolf Lioutikov
248
+ <br>
249
+ <a href="https://arxiv.org/pdf/2407.05996"> Paper</a>, <a href="https://github.com/intuitive-robots/mdt_policy"> Code </a>
250
+
251
+ <b> 3D Diffuser Actor: Policy Diffusion with 3D Scene Representations</b>
252
+ <br>
253
+ Tsung-Wei Ke, Nikolaos Gkanatsios, Katerina Fragkiadaki
254
+ <br>
255
+ <a href="https://arxiv.org/pdf/2402.10885.pdf"> Paper</a>, <a href="https://github.com/nickgkan/3d_diffuser_actor"> Code </a>
256
+
257
+ <b> Unleashing Large-Scale Video Generative Pre-training for Visual Robot Manipulation</b>
258
+ <br>
259
+ Hongtao Wu, Ya Jing, Chilam Cheang, Guangzeng Chen, Jiafeng Xu, Xinghang Li, Minghuan Liu, Hang Li, Tao Kong
260
+ <br>
261
+ <a href="https://arxiv.org/pdf/2312.13139.pdf"> Paper</a>, <a href="https://github.com/bytedance/GR-1"> Code </a>
262
+
263
+ <b> Vision-Language Foundation Models as Effective Robot Imitators</b>
264
+ <br>
265
+ Xinghang Li, Minghuan Liu, Hanbo Zhang, Cunjun Yu, Jie Xu, Hongtao Wu, Chilam Cheang, Ya Jing, Weinan Zhang, Huaping Liu, Hang Li, and Tao Kong
266
+ <br>
267
+ <a href="https://arxiv.org/pdf/2311.01378.pdf"> Paper</a>, <a href="https://github.com/RoboFlamingo/RoboFlamingo"> Code </a>
268
+
269
+ <b> Zero-Shot Robotic Manipulation With Pretrained Image-Editing Diffusion Models</b>
270
+ <br>
271
+ Kevin Black, Mitsuhiko Nakamoto, Pranav Atreya, Homer Walke, Chelsea Finn, Aviral Kumar, Sergey Levine
272
+ <br>
273
+ <a href="https://arxiv.org/pdf/2310.10639.pdf"> Paper</a>, <a href="https://github.com/kvablack/susie"> Code </a>
274
+
275
+ <b> Language Control Diffusion: Efficiently Scaling through Space, Time, and Tasks</b>
276
+ <br>
277
+ Eddie Zhang, Yujie Lu, William Wang, Amy Zhang
278
+ <br>
279
+ <a href="https://arxiv.org/pdf/2210.15629.pdf"> Paper</a>, <a href="https://github.com/ezhang7423/language-control-diffusion"> Code </a>
280
+
281
+ <b> What Matters in Language Conditioned Robotic Imitation Learning over Unstructured Data</b>
282
+ <br>
283
+ Oier Mees, Lukas Hermann, Wolfram Burgard
284
+ <br>
285
+ <a href="https://arxiv.org/pdf/2204.06252.pdf"> Paper</a>, <a href="https://github.com/lukashermann/hulc"> Code </a>
286
+
287
+ <b> Language-Conditioned Imitation Learning with Base Skill Priors under Unstructured Data</b>
288
+ <br>
289
+ Hongkuan Zhou, Zhenshan Bing, Xiangtong Yao, Xiaojie Su, Chenguang Yang, Kai Huang, Alios Knoll
290
+ <br>
291
+ <a href="https://arxiv.org/pdf/2305.19075.pdf"> Paper</a>, <a href="https://github.com/hk-zh/spil"> Code
292
+
293
+ Contact [Oier](https://www.oiermees.com/) to add your model here.
294
+
295
+ ## Reinforcement Learning with CALVIN
296
+ Are you interested in trying reinforcement learning agents for the different manipulation tasks in the CALVIN environment?
297
+ We provide a [google colab](https://github.com/mees/calvin/blob/main/RL_with_CALVIN.ipynb) to showcase how to leverage the CALVIN task indicators to learn RL agents with a sparse reward.
298
+
299
+ ## FAQ
300
+
301
+ #### Why do you use EGL rendering?
302
+ We use EGL to move the bullet rendering from cpu (which is the default) to gpu, which is much faster.
303
+ This way, we can also do rollouts during the training of the agent to track its performance.
304
+ By changing from cpu to gpu, the rendered textures change slightly, so be aware of this if you plan on testing pretrained models.
305
+ #### I am training with multiple GPUs and why am I get OOM errors during rollouts?
306
+ PyBullet only recently added an option to select which GPU to use for rendering when using EGL (fix was commited in 3c4cb80
307
+ on Oct 22, 2021, see [here](https://github.com/bulletphysics/bullet3/blob/master/examples/OpenGLWindow/EGLOpenGLWindow.cpp#L134).
308
+ If you have an old version of PyBullet, there is no way to choose the GPU, which can lead to problems on cluster nodes with multiple GPUs, because all instances would be placed on the same GPU, slowing down the rendering and potentially leading to OOM erros.
309
+
310
+ The fix introduced an environment variable EGL_VISIBLE_DEVICES (similar to CUDA_VISIBLE_DEVICES) which lets you specify the GPU device to render on.
311
+ However, there is one catch: On some machines, the device ids of CUDA and EGL do not match (e.g. CUDA device 0 could be EGL device 3).
312
+ We automatically handle this in our wrapper in calvin_env and find the corresponding egl device id, so you don't have to set EGL_VISIBLE_DEVICES yourself, see [here](https://github.com/mees/calvin_env/blob/main/calvin_env/envs/play_lmp_wrapper.py#L31).
313
+
314
+ #### I am not interested in the manipulation tasks recorded, can I record different demonstration with teleop?
315
+ Yes, although it is not documented right now, all the code to record data with a VR headset is present in
316
+ calvin_env in [https://github.com/mees/calvin_env/blob/main/calvin_env/vrdatacollector.py](https://github.com/mees/calvin_env/blob/main/calvin_env/vrdatacollector.py)
317
+
318
+
319
+ ## Changelog
320
+ ### 24 Feb 2023
321
+ - Wrong `scene_info.npy` in D dataset. Note that we have updated the corresponding checksum. Please replace as follows:
322
+ ```
323
+ cd task_D_D
324
+ wget http://calvin.cs.uni-freiburg.de/scene_info_fix/task_D_D_scene_info.zip
325
+ unzip task_D_D_scene_info.zip && rm task_D_D_scene_info.zip
326
+ ```
327
+
328
+ ### 16 Sep 2022
329
+ - **MAJOR BUG IN ABC and ABCD dataset:** If you downloaded these datasets before this date you have to do these fixes:
330
+ - Wrong language annotations in ABC and ABCD dataset. You can download the corrected language embeddings [here](https://github.com/mees/calvin/blob/main/dataset/README.md#language-embeddings).
331
+ - Bug in `calvin_env` that only affects the generation of language embeddings.
332
+ - Wrong `scene_info.npy` in ABC and ABCD dataset. Please replace as follows:
333
+ ```
334
+ cd task_ABCD_D
335
+ wget http://calvin.cs.uni-freiburg.de/scene_info_fix/task_ABCD_D_scene_info.zip
336
+ unzip task_ABCD_D_scene_info.zip && rm task_ABCD_D_scene_info.zip
337
+ ```
338
+ ```
339
+ cd task_ABC_D
340
+ wget http://calvin.cs.uni-freiburg.de/scene_info_fix/task_ABC_D_scene_info.zip
341
+ unzip task_ABC_D_scene_info.zip && rm task_ABC_D_scene_info.zip
342
+ ```
343
+ - Added additional language embeddings to dataset.
344
+
345
+
346
+ ### 15 May 2022
347
+ - Added shared memory dataset loader for faster training. Refactored data loading classes.
348
+
349
+ ### 7 Feb 2022
350
+ - Minor changes to the distribution of tasks in the long-horizon multi-step sequences.
351
+ - Changes to the task success criteria of pushing and lifting.
352
+ - Set `use_nullspace: true` for robot in hydra cfg of dataset. If you downloaded one of the datasets prior to this date,
353
+ edit this line in <PATH_TO_DATASET>/training/.hydra/merged_config.yaml and <PATH_TO_DATASET>/validation/.hydra/merged_config.yaml.
354
+ - Renaming `model.decoder` to `model.action_decoder`.
355
+
356
+ ### 10 Jan 2022
357
+ - Breaking change to evaluation, using different intitial states for environment.
358
+
359
+ ## Citation
360
+
361
+ If you find the dataset or code useful, please cite:
362
+
363
+ ```bibtex
364
+ @article{mees2022calvin,
365
+ author = {Oier Mees and Lukas Hermann and Erick Rosete-Beas and Wolfram Burgard},
366
+ title = {CALVIN: A Benchmark for Language-Conditioned Policy Learning for Long-Horizon Robot Manipulation Tasks},
367
+ journal={IEEE Robotics and Automation Letters (RA-L)},
368
+ volume={7},
369
+ number={3},
370
+ pages={7327-7334},
371
+ year={2022}
372
+ }
373
+ ```
374
+
375
+ ## License
376
+
377
+ MIT License
aloha_robot_project/calvin/RL_with_CALVIN.ipynb ADDED
@@ -0,0 +1,325 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "nbformat": 4,
3
+ "nbformat_minor": 0,
4
+ "metadata": {
5
+ "colab": {
6
+ "name": "RL_with_CALVIN.ipynb",
7
+ "provenance": [],
8
+ "collapsed_sections": [],
9
+ "authorship_tag": "ABX9TyNwSDlhfoXLR2ORP+8/+3zP",
10
+ "include_colab_link": true
11
+ },
12
+ "kernelspec": {
13
+ "display_name": "Python 3",
14
+ "name": "python3"
15
+ },
16
+ "language_info": {
17
+ "name": "python"
18
+ }
19
+ },
20
+ "cells": [
21
+ {
22
+ "cell_type": "markdown",
23
+ "metadata": {
24
+ "id": "view-in-github",
25
+ "colab_type": "text"
26
+ },
27
+ "source": [
28
+ "<a href=\"https://colab.research.google.com/github/mees/calvin/blob/main/RL_with_CALVIN.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
29
+ ]
30
+ },
31
+ {
32
+ "cell_type": "markdown",
33
+ "metadata": {
34
+ "id": "MDAC0SvBi1-9"
35
+ },
36
+ "source": [
37
+ "<h1>Reinforcement Learning with CALVIN</h1>\n",
38
+ "\n",
39
+ "The **CALVIN** simulated benchmark is perfectly suited for training agents with reinforcement learning, in this notebook we will demonstrate how to integrate your agents to these environments."
40
+ ]
41
+ },
42
+ {
43
+ "cell_type": "markdown",
44
+ "metadata": {
45
+ "id": "Gk7gEiqXizze"
46
+ },
47
+ "source": [
48
+ "## Installation\n",
49
+ "The first step is to install the CALVIN github repository such that we have access to the packages"
50
+ ]
51
+ },
52
+ {
53
+ "cell_type": "code",
54
+ "metadata": {
55
+ "id": "K1cSDZwLlAhR"
56
+ },
57
+ "source": [
58
+ "# Download repo\n",
59
+ "%mkdir /content/calvin\n",
60
+ "%cd /content/calvin\n",
61
+ "!git clone https://github.com/mees/calvin_env.git\n",
62
+ "%cd /content/calvin/calvin_env\n",
63
+ "!git clone https://github.com/lukashermann/tacto.git\n",
64
+ "# Install packages \n",
65
+ "%cd /content/calvin/calvin_env/tacto/\n",
66
+ "!pip3 install -e .\n",
67
+ "%cd /content/calvin/calvin_env\n",
68
+ "!pip3 install -e .\n",
69
+ "!pip3 install -U numpy"
70
+ ],
71
+ "execution_count": null,
72
+ "outputs": []
73
+ },
74
+ {
75
+ "cell_type": "code",
76
+ "metadata": {
77
+ "id": "hPiKJ7mY58o3"
78
+ },
79
+ "source": [
80
+ "# Run this to check if the installation was succesful\n",
81
+ "from calvin_env.envs.play_table_env import PlayTableSimEnv"
82
+ ],
83
+ "execution_count": 2,
84
+ "outputs": []
85
+ },
86
+ {
87
+ "cell_type": "markdown",
88
+ "metadata": {
89
+ "id": "JSmDkjlx0FOW"
90
+ },
91
+ "source": [
92
+ "## Loading the environment\n",
93
+ "After the installation has finished successfully, we can start using the environment for reinforcement Learning.\n",
94
+ "To be able to use the environment we need to have the appropriate configuration that define the desired features, for this example, we will load the static and gripper camera."
95
+ ]
96
+ },
97
+ {
98
+ "cell_type": "code",
99
+ "metadata": {
100
+ "id": "vp1-mgIgekvY"
101
+ },
102
+ "source": [
103
+ "%cd /content/calvin\n",
104
+ "from hydra import initialize, compose\n",
105
+ "\n",
106
+ "with initialize(config_path=\"./calvin_env/conf/\"):\n",
107
+ " cfg = compose(config_name=\"config_data_collection.yaml\", overrides=[\"cameras=static_and_gripper\"])\n",
108
+ " cfg.env[\"use_egl\"] = False\n",
109
+ " cfg.env[\"show_gui\"] = False\n",
110
+ " cfg.env[\"use_vr\"] = False\n",
111
+ " cfg.env[\"use_scene_info\"] = True\n",
112
+ " print(cfg.env)"
113
+ ],
114
+ "execution_count": null,
115
+ "outputs": []
116
+ },
117
+ {
118
+ "cell_type": "markdown",
119
+ "metadata": {
120
+ "id": "onN9sssj1JV6"
121
+ },
122
+ "source": [
123
+ "The environment has similar structure to traditional OpenAI Gym environments.\n",
124
+ "\n",
125
+ "* We can restart the simulation with the *reset* function.\n",
126
+ "* We can perform an action in the environment with the *step* function.\n",
127
+ "* We can visualize images taken from the cameras in the environment by using the *render* function.\n",
128
+ "\n",
129
+ "\n",
130
+ "\n"
131
+ ]
132
+ },
133
+ {
134
+ "cell_type": "code",
135
+ "metadata": {
136
+ "id": "MwIuxueazYOh"
137
+ },
138
+ "source": [
139
+ "import time\n",
140
+ "import hydra\n",
141
+ "import numpy as np\n",
142
+ "from google.colab.patches import cv2_imshow\n",
143
+ "\n",
144
+ "env = hydra.utils.instantiate(cfg.env)\n",
145
+ "observation = env.reset()\n",
146
+ "#The observation is given as a dictionary with different values\n",
147
+ "print(observation.keys())\n",
148
+ "for i in range(5):\n",
149
+ " # The action consists in a pose displacement (position and orientation)\n",
150
+ " action_displacement = np.random.uniform(low=-1, high=1, size=6)\n",
151
+ " # And a binary gripper action, -1 for closing and 1 for oppening\n",
152
+ " action_gripper = np.random.choice([-1, 1], size=1)\n",
153
+ " action = np.concatenate((action_displacement, action_gripper), axis=-1)\n",
154
+ " observation, reward, done, info = env.step(action)\n",
155
+ " rgb = env.render(mode=\"rgb_array\")[:,:,::-1]\n",
156
+ " cv2_imshow(rgb)"
157
+ ],
158
+ "execution_count": null,
159
+ "outputs": []
160
+ },
161
+ {
162
+ "cell_type": "markdown",
163
+ "metadata": {
164
+ "id": "_0yYw5pHC0eE"
165
+ },
166
+ "source": [
167
+ "## Custom environment for Reinforcement Learning\n",
168
+ "There are some aspects that needs to be defined to be able to use it for reinforcement learning, including:\n",
169
+ "\n",
170
+ "1. Observation space\n",
171
+ "2. Action space\n",
172
+ "3. Reward function\n",
173
+ "\n",
174
+ "We are going to create a Custom environment that extends the **PlaytableSimEnv** to add these requirements. <br/>\n",
175
+ "The specific task that will be solved is called \"move_slider_left\", here you can find a [list of possible tasks](https://github.com/mees/calvin_env/blob/main/conf/tasks/new_playtable_tasks.yaml) that can be evaluated using CALVIN.\n",
176
+ "\n"
177
+ ]
178
+ },
179
+ {
180
+ "cell_type": "code",
181
+ "metadata": {
182
+ "id": "Bwj-5UQz2vyF"
183
+ },
184
+ "source": [
185
+ "from gym import spaces\n",
186
+ "from calvin_env.envs.play_table_env import PlayTableSimEnv\n",
187
+ "\n",
188
+ "class SlideEnv(PlayTableSimEnv):\n",
189
+ " def __init__(self,\n",
190
+ " tasks: dict = {},\n",
191
+ " **kwargs):\n",
192
+ " super(SlideEnv, self).__init__(**kwargs)\n",
193
+ " # For this example we will modify the observation to\n",
194
+ " # only retrieve the end effector pose\n",
195
+ " self.action_space = spaces.Box(low=-1, high=1, shape=(7,))\n",
196
+ " self.observation_space = spaces.Box(low=-1, high=1, shape=(7,))\n",
197
+ " # We can use the task utility to know if the task was executed correctly\n",
198
+ " self.tasks = hydra.utils.instantiate(tasks)\n",
199
+ "\n",
200
+ " def reset(self):\n",
201
+ " obs = super().reset()\n",
202
+ " self.start_info = self.get_info()\n",
203
+ " return obs\n",
204
+ "\n",
205
+ " def get_obs(self):\n",
206
+ " \"\"\"Overwrite robot obs to only retrieve end effector position\"\"\"\n",
207
+ " robot_obs, robot_info = self.robot.get_observation()\n",
208
+ " return robot_obs[:7]\n",
209
+ "\n",
210
+ " def _success(self):\n",
211
+ " \"\"\" Returns a boolean indicating if the task was performed correctly \"\"\"\n",
212
+ " current_info = self.get_info()\n",
213
+ " task_filter = [\"move_slider_left\"]\n",
214
+ " task_info = self.tasks.get_task_info_for_set(self.start_info, current_info, task_filter)\n",
215
+ " return 'move_slider_left' in task_info\n",
216
+ "\n",
217
+ " def _reward(self):\n",
218
+ " \"\"\" Returns the reward function that will be used \n",
219
+ " for the RL algorithm \"\"\"\n",
220
+ " reward = int(self._success()) * 10\n",
221
+ " r_info = {'reward': reward}\n",
222
+ " return reward, r_info\n",
223
+ "\n",
224
+ " def _termination(self):\n",
225
+ " \"\"\" Indicates if the robot has reached a terminal state \"\"\"\n",
226
+ " success = self._success()\n",
227
+ " done = success\n",
228
+ " d_info = {'success': success} \n",
229
+ " return done, d_info\n",
230
+ "\n",
231
+ " def step(self, action):\n",
232
+ " \"\"\" Performing a relative action in the environment\n",
233
+ " input:\n",
234
+ " action: 7 tuple containing\n",
235
+ " Position x, y, z. \n",
236
+ " Angle in rad x, y, z. \n",
237
+ " Gripper action\n",
238
+ " each value in range (-1, 1)\n",
239
+ "\n",
240
+ " OR\n",
241
+ " 8 tuple containing\n",
242
+ " Relative Joint angles j1 - j7 (in rad)\n",
243
+ " Gripper action\n",
244
+ " output:\n",
245
+ " observation, reward, done info\n",
246
+ " \"\"\"\n",
247
+ " # Transform gripper action to discrete space\n",
248
+ " env_action = action.copy()\n",
249
+ " env_action[-1] = (int(action[-1] >= 0) * 2) - 1\n",
250
+ "\n",
251
+ " # for using actions in joint space\n",
252
+ " if len(env_action) == 8:\n",
253
+ " env_action = {\"action\": env_action, \"type\": \"joint_rel\"}\n",
254
+ "\n",
255
+ " self.robot.apply_action(env_action)\n",
256
+ " for i in range(self.action_repeat):\n",
257
+ " self.p.stepSimulation(physicsClientId=self.cid)\n",
258
+ " obs = self.get_obs()\n",
259
+ " info = self.get_info()\n",
260
+ " reward, r_info = self._reward()\n",
261
+ " done, d_info = self._termination()\n",
262
+ " info.update(r_info)\n",
263
+ " info.update(d_info)\n",
264
+ " return obs, reward, done, info"
265
+ ],
266
+ "execution_count": 5,
267
+ "outputs": []
268
+ },
269
+ {
270
+ "cell_type": "markdown",
271
+ "metadata": {
272
+ "id": "IJo-HWRqcJHc"
273
+ },
274
+ "source": [
275
+ "# Training an RL agent\n",
276
+ "After generating the wrapper training a reinforcement learning agent is straightforward, for this example we will use stable baselines 3 agents"
277
+ ]
278
+ },
279
+ {
280
+ "cell_type": "code",
281
+ "metadata": {
282
+ "id": "XOkD9S-iMVcj"
283
+ },
284
+ "source": [
285
+ "!pip3 install stable_baselines3"
286
+ ],
287
+ "execution_count": null,
288
+ "outputs": []
289
+ },
290
+ {
291
+ "cell_type": "markdown",
292
+ "metadata": {
293
+ "id": "WxWRcJJFcpEF"
294
+ },
295
+ "source": [
296
+ "To train the agent we create an instance of our new environment and send it to the stable baselines agent to learn a policy.\n",
297
+ "\n",
298
+ "\n",
299
+ "> Note: the example uses Soft Actor Critic (SAC) which is one of the state of the art algorithm for off-policy RL.\n",
300
+ "\n"
301
+ ]
302
+ },
303
+ {
304
+ "cell_type": "code",
305
+ "metadata": {
306
+ "id": "3BUeaAnqMNLq"
307
+ },
308
+ "source": [
309
+ "import gym\n",
310
+ "import numpy as np\n",
311
+ "from stable_baselines3 import SAC\n",
312
+ "\n",
313
+ "new_env_cfg = {**cfg.env}\n",
314
+ "new_env_cfg[\"tasks\"] = cfg.tasks\n",
315
+ "new_env_cfg.pop('_target_', None)\n",
316
+ "new_env_cfg.pop('_recursive_', None)\n",
317
+ "env = SlideEnv(**new_env_cfg)\n",
318
+ "model = SAC(\"MlpPolicy\", env, verbose=1)\n",
319
+ "model.learn(total_timesteps=10000, log_interval=4)\n"
320
+ ],
321
+ "execution_count": null,
322
+ "outputs": []
323
+ }
324
+ ]
325
+ }
aloha_robot_project/calvin/calvin_env/.flake8 ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [flake8]
2
+ exclude = .git
3
+ # Default is 79 in PEP 8
4
+ max-line-length = 120
5
+ select = E,F,W,C
6
+ ignore=W503, # line break before binary operator, need for black
7
+ E203, # whitespace before ':'. Opposite convention enforced by black
8
+ E731, # do not assign a lambda expression, use a def
9
+ E722,
10
+ F401,
11
+ F841,
12
+ E402, # module level import not at top of file
13
+ E741, # ambiguous variable name
14
+ E501, # line too long. Handled by black
15
+ C406, # Unnecessary list literal - rewrite as a dict literal
aloha_robot_project/calvin/calvin_env/.gitignore ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ pip-wheel-metadata/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py,cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # IPython
81
+ profile_default/
82
+ ipython_config.py
83
+
84
+ # pyenv
85
+ .python-version
86
+
87
+ # pipenv
88
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
90
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
91
+ # install all needed dependencies.
92
+ #Pipfile.lock
93
+
94
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95
+ __pypackages__/
96
+
97
+ # Celery stuff
98
+ celerybeat-schedule
99
+ celerybeat.pid
100
+
101
+ # SageMath parsed files
102
+ *.sage.py
103
+
104
+ # Environments
105
+ .env
106
+ .venv
107
+ env/
108
+ venv/
109
+ ENV/
110
+ env.bak/
111
+ venv.bak/
112
+
113
+ # Spyder project settings
114
+ .spyderproject
115
+ .spyproject
116
+
117
+ # Rope project settings
118
+ .ropeproject
119
+
120
+ # mkdocs documentation
121
+ /site
122
+
123
+ # mypy
124
+ .mypy_cache/
125
+ .dmypy.json
126
+ dmypy.json
127
+
128
+ # Pyre type checker
129
+ .pyre/
130
+
131
+
132
+ # NumPy
133
+ *.npy
134
+ *.npz
135
+
136
+ # Pickles
137
+ *.pickle
138
+
139
+ # gzip
140
+ *.gzip
141
+
142
+ # Json
143
+ #*.json
144
+
145
+ # VSCode
146
+ .vscode/*
147
+
148
+ # Own playground area
149
+ **/playground/*
150
+
151
+ # tensorboard
152
+ events.out*
153
+ *.svg
154
+
155
+ # pdfs
156
+ *.pdf
157
+
158
+ *.egg-info/*
159
+ /.idea/
160
+
161
+ egl_check/EGL_options.o
aloha_robot_project/calvin/calvin_env/.gitmodules ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ [submodule "tacto"]
2
+ path = tacto
3
+ url = https://github.com/lukashermann/tacto.git
aloha_robot_project/calvin/calvin_env/.pre-commit-config.yaml ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ default_language_version:
2
+ python: python3.8
3
+ repos:
4
+ - repo: https://github.com/psf/black
5
+ rev: 22.1.0
6
+ hooks:
7
+ - id: black
8
+ language_version: python3.8
9
+
10
+ - repo: https://gitlab.com/pycqa/flake8
11
+ rev: 3.8.4
12
+ hooks:
13
+ - id: flake8
14
+ additional_dependencies: [-e, "git+git://github.com/pycqa/pyflakes.git@c72d6cf#egg=pyflakes"]
15
+
16
+ - repo: https://github.com/pre-commit/mirrors-isort
17
+ rev: v5.6.4
18
+ hooks:
19
+ - id: isort
20
+
21
+ - repo: https://github.com/pre-commit/mirrors-mypy
22
+ rev: v0.790
23
+ hooks:
24
+ - id: mypy
25
+ args: [--ignore-missing-imports, --warn-no-return, --warn-redundant-casts, --disallow-incomplete-defs]
26
+
27
+ - repo: https://github.com/pre-commit/pre-commit-hooks
28
+ rev: v3.4.0
29
+ hooks:
30
+ - id: check-yaml
31
+ - id: trailing-whitespace
32
+ - id: end-of-file-fixer
aloha_robot_project/calvin/calvin_env/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Oier Mees
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
aloha_robot_project/calvin/calvin_env/README.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # calvin_env
2
+
3
+
4
+
5
+ ## Installation
6
+ ```bash
7
+ git clone --recursive https://github.com/mees/calvin_env.git
8
+ cd calvin_env/tacto
9
+ pip install -e .
10
+ cd ..
11
+ pip install -e .
12
+ ```
aloha_robot_project/calvin/calvin_env/calvin_env/__init__.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ """'VR Data Collection and Rendering
2
+ :copyright: 2019 by Oier Mees, Lukas Hermann, Wolfram Burgard
3
+ :license: GPLv3, see LICENSE for more details.
4
+ """
5
+
6
+ __version__ = "0.0.1"
7
+ __project__ = "calvin_env"
8
+ __author__ = "Oier Mees, Lukas Hermann"
9
+ __license__ = "GPLv3"
10
+ __email__ = "meeso@informatik.uni-freiburg.de, hermannl@informatik.uni-freiburg.de,"
aloha_robot_project/calvin/calvin_env/calvin_env/camera/camera.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+
3
+ import numpy as np
4
+
5
+
6
+ class Camera:
7
+ def __init__(self, *args, **kwargs):
8
+ raise NotImplementedError
9
+
10
+ def render(self):
11
+ raise NotImplementedError
12
+
13
+ def distance_map_to_point_cloud(self, distances, fov, width, height):
14
+ """Converts from a depth map to a point cloud.
15
+ Args:
16
+ distances: An numpy array which has the shape of (height, width) that
17
+ denotes a distance map. The unit is meter.
18
+ fov: The field of view of the camera in the vertical direction. The unit
19
+ is radian.
20
+ width: The width of the image resolution of the camera.
21
+ height: The height of the image resolution of the camera.
22
+ Returns:
23
+ point_cloud: The converted point cloud from the distance map. It is a numpy
24
+ array of shape (height, width, 3).
25
+ """
26
+ f = height / (2 * math.tan(fov / 2.0))
27
+ px = np.tile(np.arange(width), [height, 1])
28
+ x = (2 * (px + 0.5) - width) / f * distances / 2
29
+ py = np.tile(np.arange(height), [width, 1]).T
30
+ y = (2 * (py + 0.5) - height) / f * distances / 2
31
+ point_cloud = np.stack((x, y, distances), axis=-1)
32
+ return point_cloud
33
+
34
+ def z_buffer_to_real_distance(self, z_buffer, far, near):
35
+ """Function to transform depth buffer values to distances in camera space"""
36
+ return 1.0 * far * near / (far - (far - near) * z_buffer)
37
+
38
+ def process_rgbd(self, obs, nearval, farval):
39
+ (width, height, rgbPixels, depthPixels, segmentationMaskBuffer) = obs
40
+ rgb = np.reshape(rgbPixels, (height, width, 4))
41
+ rgb_img = rgb[:, :, :3]
42
+ depth_buffer = np.reshape(depthPixels, [height, width])
43
+ depth = self.z_buffer_to_real_distance(z_buffer=depth_buffer, far=farval, near=nearval)
44
+ return rgb_img, depth
45
+
46
+ # Reference: world2pixel
47
+ # https://github.com/bulletphysics/bullet3/issues/1952
48
+ def project(self, point):
49
+ """
50
+ Projects a world point in homogeneous coordinates to pixel coordinates
51
+ Args
52
+ point: np.array of len 4; indicates the desired point to project
53
+ Output
54
+ (x, y): tuple (u, v); pixel coordinates of the projected point
55
+ """
56
+
57
+ # reshape to get homogeneus transform
58
+ persp_m = np.array(self.projectionMatrix).reshape((4, 4)).T
59
+ view_m = np.array(self.viewMatrix).reshape((4, 4)).T
60
+
61
+ # Perspective proj matrix
62
+ world_pix_tran = persp_m @ view_m @ point
63
+ world_pix_tran = world_pix_tran / world_pix_tran[-1] # divide by w
64
+ world_pix_tran[:3] = (world_pix_tran[:3] + 1) / 2
65
+ x, y = world_pix_tran[0] * self.width, (1 - world_pix_tran[1]) * self.height
66
+ x, y = np.floor(x).astype(int), np.floor(y).astype(int)
67
+ return (x, y)
68
+
69
+ def deproject(self, point, depth_img, homogeneous=False):
70
+ """
71
+ Deprojects a pixel point to 3D coordinates
72
+ Args
73
+ point: tuple (u, v); pixel coordinates of point to deproject
74
+ depth_img: np.array; depth image used as reference to generate 3D coordinates
75
+ homogeneous: bool; if true it returns the 3D point in homogeneous coordinates,
76
+ else returns the world coordinates (x, y, z) position
77
+ Output
78
+ (x, y): np.array; world coordinates of the deprojected point
79
+ """
80
+ T_world_cam = np.linalg.inv(np.array(self.viewMatrix).reshape((4, 4)).T)
81
+
82
+ u, v = point
83
+ z = depth_img[v, u]
84
+ foc = self.height / (2 * np.tan(np.deg2rad(self.fov) / 2))
85
+ x = (u - self.width // 2) * z / foc
86
+ y = -(v - self.height // 2) * z / foc
87
+ z = -z
88
+ world_pos = T_world_cam @ np.array([x, y, z, 1])
89
+ if not homogeneous:
90
+ world_pos = world_pos[:3]
91
+ return world_pos
aloha_robot_project/calvin/calvin_env/calvin_env/camera/gripper_camera.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import pybullet as p
3
+
4
+ from calvin_env.camera.camera import Camera
5
+
6
+
7
+ class GripperCamera(Camera):
8
+ def __init__(self, fov, aspect, nearval, farval, width, height, robot_id, cid, name, objects=None):
9
+ self.cid = cid
10
+ self.robot_uid = robot_id
11
+ links = {
12
+ p.getJointInfo(self.robot_uid, i, physicsClientId=self.cid)[12].decode("utf-8"): i
13
+ for i in range(p.getNumJoints(self.robot_uid, physicsClientId=self.cid))
14
+ }
15
+ self.gripper_cam_link = links["gripper_cam"]
16
+ self.fov = fov
17
+ self.aspect = aspect
18
+ self.nearval = nearval
19
+ self.farval = farval
20
+ self.width = width
21
+ self.height = height
22
+
23
+ self.name = name
24
+
25
+ def render(self):
26
+ camera_ls = p.getLinkState(
27
+ bodyUniqueId=self.robot_uid, linkIndex=self.gripper_cam_link, physicsClientId=self.cid
28
+ )
29
+ camera_pos, camera_orn = camera_ls[:2]
30
+ cam_rot = p.getMatrixFromQuaternion(camera_orn)
31
+ cam_rot = np.array(cam_rot).reshape(3, 3)
32
+ cam_rot_y, cam_rot_z = cam_rot[:, 1], cam_rot[:, 2]
33
+ # camera: eye position, target position, up vector
34
+ self.view_matrix = p.computeViewMatrix(camera_pos, camera_pos + cam_rot_y, -cam_rot_z)
35
+ self.projection_matrix = p.computeProjectionMatrixFOV(
36
+ fov=self.fov, aspect=self.aspect, nearVal=self.nearval, farVal=self.farval
37
+ )
38
+ image = p.getCameraImage(
39
+ width=self.width,
40
+ height=self.height,
41
+ viewMatrix=self.view_matrix,
42
+ projectionMatrix=self.projection_matrix,
43
+ physicsClientId=self.cid,
44
+ )
45
+ rgb_img, depth_img = self.process_rgbd(image, self.nearval, self.farval)
46
+ return rgb_img, depth_img
aloha_robot_project/calvin/calvin_env/calvin_env/camera/static_camera.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import pybullet as p
3
+
4
+ from calvin_env.camera.camera import Camera
5
+
6
+
7
+ class StaticCamera(Camera):
8
+ def __init__(
9
+ self,
10
+ fov,
11
+ aspect,
12
+ nearval,
13
+ farval,
14
+ width,
15
+ height,
16
+ look_at,
17
+ look_from,
18
+ up_vector,
19
+ cid,
20
+ name,
21
+ robot_id=None,
22
+ objects=None,
23
+ ):
24
+ """
25
+ Initialize the camera
26
+ Args:
27
+ argument_group: initialize the camera and add needed arguments to argparse
28
+
29
+ Returns:
30
+ None
31
+ """
32
+ self.nearval = nearval
33
+ self.farval = farval
34
+ self.fov = fov
35
+ self.aspect = aspect
36
+ self.look_from = look_from
37
+ self.look_at = look_at
38
+ self.up_vector = up_vector
39
+ self.width = width
40
+ self.height = height
41
+ self.viewMatrix = p.computeViewMatrix(
42
+ cameraEyePosition=look_from, cameraTargetPosition=look_at, cameraUpVector=self.up_vector
43
+ )
44
+ self.projectionMatrix = p.computeProjectionMatrixFOV(
45
+ fov=fov, aspect=aspect, nearVal=self.nearval, farVal=self.farval
46
+ )
47
+ self.cid = cid
48
+ self.name = name
49
+
50
+ def set_position_from_gui(self):
51
+ info = p.getDebugVisualizerCamera(physicsClientId=self.cid)
52
+ look_at = np.array(info[-1])
53
+ dist = info[-2]
54
+ forward = np.array(info[5])
55
+ look_from = look_at - dist * forward
56
+ self.viewMatrix = p.computeViewMatrix(
57
+ cameraEyePosition=look_from, cameraTargetPosition=look_at, cameraUpVector=self.up_vector
58
+ )
59
+ look_from = [float(x) for x in look_from]
60
+ look_at = [float(x) for x in look_at]
61
+ return look_from, look_at
62
+
63
+ def render(self):
64
+ image = p.getCameraImage(
65
+ width=self.width,
66
+ height=self.height,
67
+ viewMatrix=self.viewMatrix,
68
+ projectionMatrix=self.projectionMatrix,
69
+ physicsClientId=self.cid,
70
+ )
71
+ rgb_img, depth_img = self.process_rgbd(image, self.nearval, self.farval)
72
+ return rgb_img, depth_img
aloha_robot_project/calvin/calvin_env/calvin_env/camera/tactile_sensor.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ import numpy as np
4
+
5
+ from calvin_env.camera.camera import Camera
6
+ import tacto
7
+
8
+ REPO_BASE = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
9
+
10
+
11
+ class TactileSensor(Camera):
12
+ def __init__(
13
+ self, width, height, digit_link_ids, visualize_gui, cid, name, config_path, robot_id=None, objects=None
14
+ ):
15
+ """
16
+ Initialize the camera
17
+ Args:
18
+ argument_group: initialize the camera and add needed arguments to argparse
19
+
20
+ Returns:
21
+ None
22
+ """
23
+ self.cid = cid
24
+ self.name = name
25
+ self.robot_uid = robot_id
26
+ self.digits = tacto.Sensor(
27
+ width=width, height=height, visualize_gui=visualize_gui, config_path=os.path.join(REPO_BASE, config_path)
28
+ )
29
+ self.digits.add_camera(robot_id, digit_link_ids) # env.robot.digit_links()
30
+ for obj in objects:
31
+ # self.digits.add_body(obj)
32
+ self.digits.add_object(obj.file.as_posix(), obj.uid, obj.global_scaling)
33
+ self.visualize_gui = visualize_gui
34
+
35
+ def render(self):
36
+ rgb, depth = self.digits.render()
37
+ if self.visualize_gui:
38
+ self.digits.updateGUI(rgb, depth)
39
+ rgb = np.concatenate(rgb, axis=2)
40
+ depth = np.stack(depth, axis=2)
41
+ return rgb, depth
aloha_robot_project/calvin/calvin_env/calvin_env/datarenderer.py ADDED
@@ -0,0 +1,299 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python3
2
+
3
+ from collections import deque
4
+ import logging
5
+ from multiprocessing import Process
6
+ import os
7
+ from pathlib import Path
8
+
9
+ import hydra
10
+ import numpy as np
11
+ import omegaconf
12
+ import pybullet as p
13
+ from scipy.spatial.transform.rotation import Rotation as R
14
+
15
+ from calvin_env.utils.utils import count_frames, get_episode_lengths, set_egl_device, to_relative_action
16
+
17
+ # A logger for this file
18
+ log = logging.getLogger(__name__)
19
+
20
+
21
+ @hydra.main(config_path="../conf", config_name="config_rendering")
22
+ def main(cfg):
23
+ log.info("pyBullet Data Renderer")
24
+ log.info("Determining maximum frame")
25
+
26
+ recording_dir = (Path(hydra.utils.get_original_cwd()) / cfg.load_dir).absolute()
27
+ max_frames = count_frames(recording_dir)
28
+ log.info(f"Found continuous interval of {max_frames} frames without gaps")
29
+
30
+ num_prev_rendered_episodes = num_previously_rendered_episodes()
31
+ if num_prev_rendered_episodes == 0:
32
+ playback_cfg = build_rendering_config(recording_dir, rendering_config=cfg)
33
+ else:
34
+ playback_cfg = load_rendering_config(cfg)
35
+
36
+ log.info("Initialization done!")
37
+ log.info(f"Starting {cfg.processes} processes")
38
+
39
+ if playback_cfg.set_static_cam:
40
+ playback_cfg = set_static_cams_from_gui(playback_cfg, recording_dir, max_frames)
41
+
42
+ if cfg.processes != 1 and playback_cfg.show_gui:
43
+ log.warning("Multiprocess rendering requires headless mode, setting cfg.show_gui = False")
44
+ playback_cfg.show_gui = False
45
+ # in order to distribute the rendering to multiple processes, predetermine the lengths of the
46
+ # (rendered) episodes and to which (recording) file ids the episode start and end correspond
47
+ # a rendered episode does not contain the done frame, thus length(render_episode) = length(recording_episode) -1
48
+ episode_lengths, render_start_end_ids = get_episode_lengths(cfg.load_dir, max_frames)
49
+ # episode_lengths = episode_lengths[:1]
50
+ # render_start_end_ids = render_start_end_ids[:1]
51
+
52
+ if cfg.processes > len(episode_lengths):
53
+ log.warning(f"Trying to use more processes ({cfg.processes}) than episodes ({len(episode_lengths)}).")
54
+ log.warning(f"Reducing number of processes to {len(episode_lengths)}.")
55
+ cfg.processes = len(episode_lengths)
56
+ # distribute the episodes equally to processes
57
+ split_indices = np.array_split(np.array(render_start_end_ids), cfg.processes, axis=0)
58
+ # every process renders the interval [proc_start_ids, proc_end_ids)
59
+ proc_start_ids = [split_indices[proc_num][0][0] for proc_num in range(cfg.processes)]
60
+ proc_end_ids = [split_indices[proc_num][-1][1] for proc_num in range(cfg.processes)]
61
+ # predetermine starting episode indices for multiple processes
62
+ proc_ep_ids = np.cumsum(
63
+ [0] + list(map(np.sum, np.array_split(np.array(episode_lengths), cfg.processes, axis=0)))[:-1]
64
+ )
65
+ proc_ep_ids += num_prev_rendered_episodes
66
+ if cfg.processes > 1:
67
+ processes = [
68
+ Process(
69
+ target=worker_run,
70
+ args=(
71
+ recording_dir,
72
+ playback_cfg,
73
+ proc_num,
74
+ proc_start_ids[proc_num],
75
+ proc_end_ids[proc_num],
76
+ proc_ep_ids[proc_num],
77
+ ),
78
+ name=f"Worker {proc_num}",
79
+ )
80
+ for proc_num in range(cfg.processes)
81
+ ]
82
+ deque(map(lambda proc: proc.start(), processes))
83
+ deque(map(lambda proc: proc.join(), processes))
84
+ else:
85
+ worker_run(recording_dir, playback_cfg, 0, 0, max_frames, num_prev_rendered_episodes)
86
+ save_ep_lens(episode_lengths, num_prev_rendered_episodes)
87
+
88
+ log.info("All workers done")
89
+
90
+
91
+ def build_rendering_config(recording_dir, rendering_config):
92
+ merged_conf = omegaconf.OmegaConf.load(Path(recording_dir) / ".hydra" / "config.yaml")
93
+ merged_conf = omegaconf.OmegaConf.merge(merged_conf, rendering_config)
94
+ hydra.core.utils._save_config(merged_conf, "merged_config.yaml", Path(os.getcwd(), ".hydra"))
95
+ return merged_conf
96
+
97
+
98
+ def load_rendering_config(rendering_config):
99
+ conf = omegaconf.OmegaConf.load(Path(os.getcwd()) / ".hydra" / "merged_config.yaml")
100
+ override_conf = omegaconf.OmegaConf.select(rendering_config, "scene")
101
+ omegaconf.OmegaConf.update(conf, "scene", override_conf, merge=False)
102
+ conf.set_static_cam = False
103
+ return conf
104
+
105
+
106
+ def num_previously_rendered_episodes():
107
+ return len(list(Path(os.getcwd()).glob("*.npz")))
108
+
109
+
110
+ def save_ep_lens(episode_lengths, num_prev_episodes):
111
+ if num_prev_episodes > 0:
112
+ previous_ep_lens = np.load("ep_lens.npy")
113
+ episode_lengths = np.concatenate((previous_ep_lens, episode_lengths))
114
+ np.save("ep_lens.npy", episode_lengths)
115
+ end_ids = np.cumsum(episode_lengths) - 1
116
+ start_ids = [0] + list(end_ids + 1)[:-1]
117
+ ep_start_end_ids = list(zip(start_ids, end_ids))
118
+ np.save("ep_start_end_ids.npy", ep_start_end_ids)
119
+
120
+
121
+ def save_step(counter, rgbs, depths, actions, robot_obs, scene_obs, cam_names, **additional_infos):
122
+ rgb_entries = {f"rgb_{cam_name}": rgbs[f"rgb_{cam_name}"] for i, cam_name in enumerate(cam_names)}
123
+ depths_entries = {f"depth_{cam_name}": depths[f"depth_{cam_name}"] for i, cam_name in enumerate(cam_names)}
124
+ if actions[-1] == 0:
125
+ actions[-1] = -1
126
+ np.savez_compressed(
127
+ f"episode_{counter:07d}.npz",
128
+ actions=actions,
129
+ rel_actions=to_relative_action(actions, robot_obs),
130
+ robot_obs=robot_obs,
131
+ scene_obs=scene_obs,
132
+ **rgb_entries,
133
+ **depths_entries,
134
+ **additional_infos,
135
+ )
136
+
137
+
138
+ def state_to_action(info):
139
+ """
140
+ save action as [tcp_pos, tcp_orn_quaternion, gripper_action]
141
+ """
142
+ tcp_pos = info["robot_info"]["tcp_pos"]
143
+ tcp_orn = info["robot_info"]["tcp_orn"]
144
+ gripper_action = info["robot_info"]["gripper_action"]
145
+ action = np.concatenate([tcp_pos, tcp_orn, [gripper_action]])
146
+ return action
147
+
148
+
149
+ def set_static_cams_from_gui(cfg, load_dir, max_frames):
150
+ import cv2
151
+
152
+ assert cfg.env.show_gui
153
+ env = hydra.utils.instantiate(cfg.env)
154
+ env.reset()
155
+ frame = 0
156
+ log.info("--------------------------------------------------")
157
+ log.info("Use Debug GUI to change the position of the camera")
158
+ log.info("Use Render_view_window for keyboard input")
159
+ log.info("Press A or D to move through frames")
160
+ log.info("Press Q or E to skip through frames")
161
+ log.info("Press S to set camera position")
162
+ log.info("Press ENTER to save the set camera position")
163
+ log.info("Press ESC to skip setting position for current camera")
164
+ for cam_index, (cam_name, cam) in enumerate(cfg.cameras.items()):
165
+ if "static" in cam._target_:
166
+ # initialize variables
167
+ look_from = cam.look_from
168
+ look_at = cam.look_at
169
+ up_vector = cam.up_vector
170
+ fov = cam.fov
171
+ while True:
172
+ file_path = load_dir / f"{frame:012d}.pickle"
173
+ _, _, _ = env.reset_from_storage(file_path)
174
+ env.p.stepSimulation()
175
+ frame_rgbs, frame_depths = env.get_camera_obs()
176
+ rgb_static = frame_rgbs[cam_index]
177
+
178
+ cv2.imshow("Render_view_window", cv2.resize(rgb_static, (500, 500))[:, :, ::-1])
179
+ k = cv2.waitKey(10) % 256
180
+ if k == ord("a"):
181
+ frame -= 1
182
+ frame = np.clip(frame, 0, max_frames - 1)
183
+ if k == ord("d"):
184
+ frame += 1
185
+ frame = np.clip(frame, 0, max_frames - 1)
186
+ if k == ord("q"):
187
+ frame -= 100
188
+ frame = np.clip(frame, 0, max_frames - 1)
189
+ if k == ord("e"):
190
+ frame += 100
191
+ frame = np.clip(frame, 0, max_frames - 1)
192
+ if k == ord("z"):
193
+ c = env.cameras[cam_index]
194
+ c.fov -= 1
195
+ c.projectionMatrix = p.computeProjectionMatrixFOV(
196
+ fov=c.fov, aspect=c.aspect, nearVal=c.nearval, farVal=c.farval
197
+ )
198
+ print(c.fov)
199
+ fov = c.fov
200
+ if k == ord("x"):
201
+ c = env.cameras[cam_index]
202
+ c.fov += 1
203
+ c.projectionMatrix = p.computeProjectionMatrixFOV(
204
+ fov=c.fov, aspect=c.aspect, nearVal=c.nearval, farVal=c.farval
205
+ )
206
+ print(c.fov)
207
+ fov = c.fov
208
+ if k == ord("r"):
209
+ c = env.cameras[cam_index]
210
+ direction_vector = np.array(c.look_at) - np.array(c.look_from)
211
+ c.up_vector = (
212
+ R.from_rotvec(0.1 * direction_vector / np.linalg.norm(direction_vector)).as_matrix()
213
+ @ c.up_vector
214
+ )
215
+ up_vector = c.up_vector
216
+ if k == ord("f"):
217
+ c = env.cameras[cam_index]
218
+ direction_vector = np.array(c.look_at) - np.array(c.look_from)
219
+ c.up_vector = (
220
+ R.from_rotvec(-0.1 * direction_vector / np.linalg.norm(direction_vector)).as_matrix()
221
+ @ c.up_vector
222
+ )
223
+ up_vector = c.up_vector
224
+ if k == 13: # Enter
225
+ cam.look_from = look_from
226
+ cam.look_at = look_at
227
+ log.info(f"Set look_from of camera {cam_index} to {look_from}")
228
+ log.info(f"Set look_at of camera {cam_index} to {look_at}")
229
+ cam.up_vector = np.array(up_vector).tolist()
230
+ log.info(f"Set up_vector of camera {cam_index} to {up_vector}")
231
+ cam.fov = fov
232
+ log.info(f"Set fov of camera {cam_index} to {fov}")
233
+ break
234
+ if k == 27: # ESC
235
+ log.info(f"Do no change position of camera {cam_index}")
236
+ break
237
+ # if k == ord("s"):
238
+ look_from, look_at = env.cameras[cam_index].set_position_from_gui()
239
+ hydra.core.utils._save_config(cfg, "merged_config.yaml", Path(os.getcwd(), ".hydra"))
240
+ env.close()
241
+ return cfg
242
+
243
+
244
+ def worker_run(load_dir, rendering_cfg, proc_num, start_frame, stop_frame, episode_index):
245
+ log.info(f"[{proc_num}] Starting worker {proc_num}")
246
+ set_egl_device(0)
247
+ env = hydra.utils.instantiate(rendering_cfg.env)
248
+
249
+ log.info(f"[{proc_num}] Entering Loop")
250
+ frame_counter = 0
251
+ rgbs, depths, actions, robot_obs, scene_obs, = (
252
+ [],
253
+ [],
254
+ [],
255
+ [],
256
+ [],
257
+ )
258
+ for frame in range(start_frame, stop_frame):
259
+ file_path = load_dir / f"{frame:012d}.pickle"
260
+ state_ob, done, info = env.reset_from_storage(file_path)
261
+ action = state_to_action(info)
262
+ robot_obs.append(state_ob["robot_obs"])
263
+ scene_obs.append(state_ob["scene_obs"])
264
+
265
+ # action is robot state of next frame
266
+ if frame_counter > 0:
267
+ actions.append(action)
268
+ frame_rgbs, frame_depths = env.get_camera_obs()
269
+ rgbs.append(frame_rgbs)
270
+ depths.append(frame_depths)
271
+ # for terminal states save current robot state as action
272
+ frame_counter += 1
273
+ log.debug(f"episode counter {episode_index} frame counter {frame_counter} done {done}")
274
+
275
+ if frame_counter > 1:
276
+ save_step(
277
+ episode_index,
278
+ rgbs.pop(0),
279
+ depths.pop(0),
280
+ actions.pop(0),
281
+ robot_obs.pop(0),
282
+ scene_obs.pop(0),
283
+ cam_names=[cam.name for cam in env.cameras],
284
+ )
285
+ episode_index += 1
286
+ if done:
287
+ frame_counter = 0
288
+ rgbs, depths, actions, robot_obs, scene_obs = [], [], [], [], []
289
+
290
+ log.debug(f"[{proc_num}] Rendered frame {frame}")
291
+
292
+ assert done
293
+
294
+ env.close()
295
+ log.info(f"[{proc_num}] Finishing worker {proc_num}")
296
+
297
+
298
+ if __name__ == "__main__":
299
+ main()
aloha_robot_project/calvin/calvin_env/calvin_env/envs/play_lmp_wrapper.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import os
3
+ from typing import Any, Dict, Tuple, Union
4
+
5
+ from calvin_agent.datasets.utils.episode_utils import process_depth, process_rgb, process_state
6
+ import gym
7
+ import numpy as np
8
+ import torch
9
+
10
+ from calvin_env.envs.play_table_env import get_env
11
+ from calvin_env.utils.utils import EglDeviceNotFoundError, get_egl_device_id
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class PlayLMPWrapper(gym.Wrapper):
17
+ def __init__(self, dataset_loader, device, show_gui=False, **kwargs):
18
+ self.set_egl_device(device)
19
+ env = get_env(
20
+ dataset_loader.abs_datasets_dir, show_gui=show_gui, obs_space=dataset_loader.observation_space, **kwargs
21
+ )
22
+ super(PlayLMPWrapper, self).__init__(env)
23
+ self.observation_space_keys = dataset_loader.observation_space
24
+ self.transforms = dataset_loader.transforms
25
+ self.proprio_state = dataset_loader.proprio_state
26
+ self.device = device
27
+ self.relative_actions = "rel_actions" in self.observation_space_keys["actions"]
28
+ logger.info(f"Initialized PlayTableEnv for device {self.device}")
29
+
30
+ @staticmethod
31
+ def set_egl_device(device):
32
+ if "EGL_VISIBLE_DEVICES" in os.environ:
33
+ logger.warning("Environment variable EGL_VISIBLE_DEVICES is already set. Is this intended?")
34
+ cuda_id = device.index if device.type == "cuda" else 0
35
+ try:
36
+ egl_id = get_egl_device_id(cuda_id)
37
+ except EglDeviceNotFoundError:
38
+ logger.warning(
39
+ "Couldn't find correct EGL device. Setting EGL_VISIBLE_DEVICE=0. "
40
+ "When using DDP with many GPUs this can lead to OOM errors. "
41
+ "Did you install PyBullet correctly? Please refer to calvin env README"
42
+ )
43
+ egl_id = 0
44
+ os.environ["EGL_VISIBLE_DEVICES"] = str(egl_id)
45
+ logger.info(f"EGL_DEVICE_ID {egl_id} <==> CUDA_DEVICE_ID {cuda_id}")
46
+
47
+ def transform_observation(self, obs: Dict[str, Any]) -> Dict[str, Union[torch.Tensor, Dict[str, torch.Tensor]]]:
48
+ state_obs = process_state(obs, self.observation_space_keys, self.transforms, self.proprio_state)
49
+ rgb_obs = process_rgb(obs["rgb_obs"], self.observation_space_keys, self.transforms)
50
+ depth_obs = process_depth(obs["depth_obs"], self.observation_space_keys, self.transforms)
51
+
52
+ state_obs["robot_obs"] = state_obs["robot_obs"].to(self.device).unsqueeze(0)
53
+ rgb_obs.update({"rgb_obs": {k: v.to(self.device).unsqueeze(0) for k, v in rgb_obs["rgb_obs"].items()}})
54
+ depth_obs.update({"depth_obs": {k: v.to(self.device).unsqueeze(0) for k, v in depth_obs["depth_obs"].items()}})
55
+
56
+ obs_dict = {**rgb_obs, **state_obs, **depth_obs}
57
+ obs_dict["robot_obs_raw"] = torch.from_numpy(obs["robot_obs"]).to(self.device)
58
+ return obs_dict
59
+
60
+ def step(
61
+ self, action_tensor: torch.Tensor
62
+ ) -> Tuple[Dict[str, Union[torch.Tensor, Tuple[torch.Tensor, ...]]], int, bool, Dict]:
63
+ if self.relative_actions:
64
+ action = action_tensor.squeeze().cpu().detach().numpy()
65
+ assert len(action) == 7
66
+ else:
67
+ if action_tensor.shape[-1] == 7:
68
+ slice_ids = [3, 6]
69
+ elif action_tensor.shape[-1] == 8:
70
+ slice_ids = [3, 7]
71
+ else:
72
+ logger.error("actions are required to have length 8 (for euler angles) or 9 (for quaternions)")
73
+ raise NotImplementedError
74
+ action = np.split(action_tensor.squeeze().cpu().detach().numpy(), slice_ids)
75
+ action[-1] = 1 if action[-1] > 0 else -1
76
+ o, r, d, i = self.env.step(action)
77
+
78
+ obs = self.transform_observation(o)
79
+ return obs, r, d, i
80
+
81
+ def reset(
82
+ self,
83
+ reset_info: Dict[str, Any] = None,
84
+ batch_idx: int = 0,
85
+ seq_idx: int = 0,
86
+ scene_obs: Any = None,
87
+ robot_obs: Any = None,
88
+ ) -> Dict[str, Union[torch.Tensor, Tuple[torch.Tensor, ...]]]:
89
+ if reset_info is not None:
90
+ obs = self.env.reset(
91
+ robot_obs=reset_info["robot_obs"][batch_idx, seq_idx],
92
+ scene_obs=reset_info["scene_obs"][batch_idx, seq_idx],
93
+ )
94
+ elif scene_obs is not None or robot_obs is not None:
95
+ obs = self.env.reset(scene_obs=scene_obs, robot_obs=robot_obs)
96
+ else:
97
+ obs = self.env.reset()
98
+
99
+ return self.transform_observation(obs)
100
+
101
+ def get_info(self):
102
+ return self.env.get_info()
103
+
104
+ def get_obs(self):
105
+ obs = self.env.get_obs()
106
+ return self.transform_observation(obs)
aloha_robot_project/calvin/calvin_env/calvin_env/envs/play_table_env.py ADDED
@@ -0,0 +1,304 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ from math import pi
3
+ import os
4
+ from pathlib import Path
5
+ import pickle
6
+ import pkgutil
7
+ import re
8
+ import sys
9
+ import time
10
+
11
+ import cv2
12
+ import gym
13
+ import gym.utils
14
+ import gym.utils.seeding
15
+ import hydra
16
+ import numpy as np
17
+ import pybullet as p
18
+ import pybullet_utils.bullet_client as bc
19
+
20
+ import calvin_env
21
+ from calvin_env.utils.utils import FpsController, get_git_commit_hash
22
+
23
+ # A logger for this file
24
+ log = logging.getLogger(__name__)
25
+ from rich.traceback import install
26
+
27
+ install(show_locals=True)
28
+
29
+
30
+ class PlayTableSimEnv(gym.Env):
31
+ def __init__(
32
+ self,
33
+ robot_cfg,
34
+ seed,
35
+ use_vr,
36
+ bullet_time_step,
37
+ cameras,
38
+ show_gui,
39
+ scene_cfg,
40
+ use_scene_info,
41
+ use_egl,
42
+ control_freq=30,
43
+ ):
44
+ self.p = p
45
+ # for calculation of FPS
46
+ self.t = time.time()
47
+ self.prev_time = time.time()
48
+ self.fps_controller = FpsController(bullet_time_step)
49
+ self.use_vr = use_vr
50
+ self.show_gui = show_gui
51
+ self.use_scene_info = use_scene_info
52
+ self.cid = -1
53
+ self.ownsPhysicsClient = False
54
+ self.use_egl = use_egl
55
+ self.control_freq = control_freq
56
+ self.action_repeat = int(bullet_time_step // control_freq)
57
+ render_width = max([cameras[cam].width for cam in cameras]) if cameras else None
58
+ render_height = max([cameras[cam].height for cam in cameras]) if cameras else None
59
+ self.initialize_bullet(bullet_time_step, render_width, render_height)
60
+ self.np_random = None
61
+ self.seed(seed)
62
+ self.robot = hydra.utils.instantiate(robot_cfg, cid=self.cid)
63
+ self.scene = hydra.utils.instantiate(scene_cfg, p=self.p, cid=self.cid, np_random=self.np_random)
64
+
65
+ # Load Env
66
+ self.load()
67
+
68
+ # init cameras after scene is loaded to have robot id available
69
+ self.cameras = [
70
+ hydra.utils.instantiate(
71
+ cameras[name], cid=self.cid, robot_id=self.robot.robot_uid, objects=self.scene.get_objects()
72
+ )
73
+ for name in cameras
74
+ ]
75
+ log.info(f"Using calvin_env with commit {get_git_commit_hash(Path(calvin_env.__file__))}.")
76
+
77
+ def __del__(self):
78
+ self.close()
79
+
80
+ # From pybullet gym_manipulator_envs code
81
+ # https://github.com/bulletphysics/bullet3/blob/master/examples/pybullet/gym/pybullet_envs/gym_manipulator_envs.py
82
+ def initialize_bullet(self, bullet_time_step, render_width, render_height):
83
+ if self.cid < 0:
84
+ self.ownsPhysicsClient = True
85
+ if self.use_vr:
86
+ self.p = bc.BulletClient(connection_mode=p.SHARED_MEMORY)
87
+ cid = self.p._client
88
+ if cid < 0:
89
+ log.error("Failed to connect to SHARED_MEMORY bullet server.\n" " Is it running?")
90
+ sys.exit(1)
91
+ self.p.setRealTimeSimulation(enableRealTimeSimulation=1, physicsClientId=cid)
92
+ elif self.show_gui:
93
+ self.p = bc.BulletClient(connection_mode=p.GUI)
94
+ cid = self.p._client
95
+ if cid < 0:
96
+ log.error("Failed to connect to GUI.")
97
+ elif self.use_egl:
98
+ options = f"--width={render_width} --height={render_height}"
99
+ self.p = p
100
+ cid = self.p.connect(p.DIRECT, options=options)
101
+ p.configureDebugVisualizer(p.COV_ENABLE_GUI, 0, physicsClientId=cid)
102
+ p.configureDebugVisualizer(p.COV_ENABLE_SEGMENTATION_MARK_PREVIEW, 0, physicsClientId=cid)
103
+ p.configureDebugVisualizer(p.COV_ENABLE_DEPTH_BUFFER_PREVIEW, 0, physicsClientId=cid)
104
+ p.configureDebugVisualizer(p.COV_ENABLE_RGB_BUFFER_PREVIEW, 0, physicsClientId=cid)
105
+ egl = pkgutil.get_loader("eglRenderer")
106
+ log.info("Loading EGL plugin (may segfault on misconfigured systems)...")
107
+ if egl:
108
+ plugin = p.loadPlugin(egl.get_filename(), "_eglRendererPlugin")
109
+ else:
110
+ plugin = p.loadPlugin("eglRendererPlugin")
111
+ if plugin < 0:
112
+ log.error("\nPlugin Failed to load!\n")
113
+ sys.exit()
114
+ # set environment variable for tacto renderer
115
+ os.environ["PYOPENGL_PLATFORM"] = "egl"
116
+ log.info("Successfully loaded egl plugin")
117
+ else:
118
+ self.p = bc.BulletClient(connection_mode=p.DIRECT)
119
+ cid = self.p._client
120
+ if cid < 0:
121
+ log.error("Failed to start DIRECT bullet mode.")
122
+ log.info(f"Connected to server with id: {cid}")
123
+
124
+ self.cid = cid
125
+ self.p.resetSimulation(physicsClientId=self.cid)
126
+ self.p.setPhysicsEngineParameter(deterministicOverlappingPairs=1, physicsClientId=self.cid)
127
+ self.p.configureDebugVisualizer(self.p.COV_ENABLE_GUI, 0)
128
+ log.info(f"Connected to server with id: {self.cid}")
129
+ self.p.setTimeStep(1.0 / bullet_time_step, physicsClientId=self.cid)
130
+ return cid
131
+
132
+ def load(self):
133
+ log.info("Resetting simulation")
134
+ self.p.resetSimulation(physicsClientId=self.cid)
135
+ log.info("Setting gravity")
136
+ self.p.setGravity(0, 0, -9.8, physicsClientId=self.cid)
137
+
138
+ self.robot.load()
139
+ self.scene.load()
140
+
141
+ def close(self):
142
+ if self.ownsPhysicsClient:
143
+ print("disconnecting id %d from server" % self.cid)
144
+ if self.cid >= 0 and self.p is not None:
145
+ try:
146
+ self.p.disconnect(physicsClientId=self.cid)
147
+ except TypeError:
148
+ pass
149
+
150
+ else:
151
+ print("does not own physics client id")
152
+
153
+ def render(self, mode="human"):
154
+ """render is gym compatibility function"""
155
+ rgb_obs, depth_obs = self.get_camera_obs()
156
+ if mode == "human":
157
+ if "rgb_static" in rgb_obs:
158
+ img = rgb_obs["rgb_static"][:, :, ::-1]
159
+ cv2.imshow("simulation cam", cv2.resize(img, (500, 500)))
160
+ if "rgb_gripper" in rgb_obs:
161
+ img2 = rgb_obs["rgb_gripper"][:, :, ::-1]
162
+ cv2.imshow("gripper cam", cv2.resize(img2, (500, 500)))
163
+ cv2.waitKey(1)
164
+ elif mode == "rgb_array":
165
+ assert "rgb_static" in rgb_obs, "Environment does not have static camera"
166
+ return rgb_obs["rgb_static"]
167
+ else:
168
+ raise NotImplementedError
169
+
170
+ def get_scene_info(self):
171
+ return self.scene.get_info()
172
+
173
+ def reset(self, robot_obs=None, scene_obs=None):
174
+ self.scene.reset(scene_obs)
175
+ self.robot.reset(robot_obs)
176
+ self.p.stepSimulation(physicsClientId=self.cid)
177
+ return self.get_obs()
178
+
179
+ def seed(self, seed=None):
180
+ self.np_random, seed = gym.utils.seeding.np_random(seed)
181
+ # self.robot.np_random = self.np_random # use the same np_randomizer for robot as for env
182
+ return [seed]
183
+
184
+ def get_camera_obs(self):
185
+ assert self.cameras is not None
186
+ rgb_obs = {}
187
+ depth_obs = {}
188
+ for cam in self.cameras:
189
+ rgb, depth = cam.render()
190
+ rgb_obs[f"rgb_{cam.name}"] = rgb
191
+ depth_obs[f"depth_{cam.name}"] = depth
192
+ return rgb_obs, depth_obs
193
+
194
+ def get_obs(self):
195
+ """Collect camera, robot and scene observations."""
196
+ rgb_obs, depth_obs = self.get_camera_obs()
197
+ obs = {"rgb_obs": rgb_obs, "depth_obs": depth_obs}
198
+ obs.update(self.get_state_obs())
199
+ return obs
200
+
201
+ def get_state_obs(self):
202
+ """
203
+ Collect state observation dict
204
+ --state_obs
205
+ --robot_obs
206
+ --robot_state_full
207
+ -- [tcp_pos, tcp_orn, gripper_opening_width]
208
+ --gripper_opening_width
209
+ --arm_joint_states
210
+ --gripper_action}
211
+ --scene_obs
212
+ """
213
+ robot_obs, robot_info = self.robot.get_observation()
214
+ scene_obs = self.scene.get_obs()
215
+ obs = {"robot_obs": robot_obs, "scene_obs": scene_obs}
216
+ return obs
217
+
218
+ def get_info(self):
219
+ _, robot_info = self.robot.get_observation()
220
+ info = {"robot_info": robot_info}
221
+ if self.use_scene_info:
222
+ info["scene_info"] = self.scene.get_info()
223
+ return info
224
+
225
+ def step(self, action):
226
+ # in vr mode real time simulation is enabled, thus p.stepSimulation() does not have to be called manually
227
+ if self.use_vr:
228
+ log.debug(f"SIM FPS: {(1 / (time.time() - self.t)):.0f}")
229
+ self.t = time.time()
230
+ current_time = time.time()
231
+ delta_t = current_time - self.prev_time
232
+ if delta_t >= (1.0 / self.control_freq):
233
+ log.debug(f"Act FPS: {1 / delta_t:.0f}")
234
+ self.prev_time = time.time()
235
+ self.robot.apply_action(action)
236
+ self.fps_controller.step()
237
+ # for RL call step simulation repeat
238
+ else:
239
+ self.robot.apply_action(action)
240
+ for i in range(self.action_repeat):
241
+ self.p.stepSimulation(physicsClientId=self.cid)
242
+ self.scene.step()
243
+ obs = self.get_obs()
244
+ info = self.get_info()
245
+ # obs, reward, done, info
246
+ return obs, 0, False, info
247
+
248
+ def reset_from_storage(self, filename):
249
+ """
250
+ Args:
251
+ filename: file to load from.
252
+ Returns:
253
+ observation
254
+ """
255
+ with open(filename, "rb") as file:
256
+ data = pickle.load(file)
257
+
258
+ self.robot.reset_from_storage(data["robot"])
259
+ self.scene.reset_from_storage(data["scene"])
260
+
261
+ self.p.stepSimulation(physicsClientId=self.cid)
262
+
263
+ return data["state_obs"], data["done"], data["info"]
264
+
265
+ def serialize(self):
266
+ data = {"time": time.time_ns() / (10**9), "robot": self.robot.serialize(), "scene": self.scene.serialize()}
267
+ return data
268
+
269
+
270
+ def get_env(dataset_path, obs_space=None, show_gui=True, **kwargs):
271
+ from pathlib import Path
272
+
273
+ from omegaconf import OmegaConf
274
+
275
+ render_conf = OmegaConf.load(Path(dataset_path) / ".hydra" / "merged_config.yaml")
276
+
277
+ if obs_space is not None:
278
+ exclude_keys = set(render_conf.cameras.keys()) - {
279
+ re.split("_", key)[1] for key in obs_space["rgb_obs"] + obs_space["depth_obs"]
280
+ }
281
+ for k in exclude_keys:
282
+ del render_conf.cameras[k]
283
+ if "scene" in kwargs:
284
+ scene_cfg = OmegaConf.load(Path(calvin_env.__file__).parents[1] / "conf/scene" / f"{kwargs['scene']}.yaml")
285
+ OmegaConf.merge(render_conf, scene_cfg)
286
+ if not hydra.core.global_hydra.GlobalHydra.instance().is_initialized():
287
+ hydra.initialize(".")
288
+ env = hydra.utils.instantiate(render_conf.env, show_gui=show_gui, use_vr=False, use_scene_info=True)
289
+ return env
290
+
291
+
292
+ @hydra.main(config_path="../../conf", config_name="config_data_collection")
293
+ def run_env(cfg):
294
+ env = hydra.utils.instantiate(cfg.env, show_gui=True, use_vr=False, use_scene_info=True)
295
+
296
+ env.reset()
297
+ while True:
298
+ env.step(np.array((0.0, 0, 0, 0, 0, 1)))
299
+ # env.render()
300
+ time.sleep(0.01)
301
+
302
+
303
+ if __name__ == "__main__":
304
+ run_env()
aloha_robot_project/calvin/calvin_env/calvin_env/envs/tasks.py ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from functools import partial
2
+ from typing import Dict, Set
3
+
4
+ import numpy as np
5
+ from omegaconf import ListConfig
6
+ from scipy.spatial.transform import Rotation as R
7
+
8
+
9
+ class Tasks:
10
+ def __init__(self, tasks):
11
+ """
12
+ A task is defined as a specific change between the start_info and end_info dictionaries.
13
+ Use config file in conf/tasks/ to define tasks using the base task functions defined in this class
14
+ """
15
+ # register task functions from config file
16
+ self.tasks = {name: partial(getattr(self, args[0]), *args[1:]) for name, args in dict(tasks).items()}
17
+ # dictionary mapping from task name to task id
18
+ self.task_to_id = {name: i for i, name in enumerate(self.tasks.keys())}
19
+ # dictionary mapping from task id to task name
20
+ self.id_to_task = {i: name for i, name in enumerate(self.tasks.keys())}
21
+
22
+ def get_task_info(self, start_info: Dict, end_info: Dict) -> Set:
23
+ """
24
+ start_info: dict with scene info and robot info
25
+ end_info: dict with scene info and robot info
26
+ returns set with achieved tasks
27
+ """
28
+ # call functions that are registered in self.tasks
29
+ return {
30
+ task_name
31
+ for task_name, function in self.tasks.items()
32
+ if function(start_info=start_info, end_info=end_info)
33
+ }
34
+
35
+ def get_task_info_for_set(self, start_info: Dict, end_info: Dict, task_filter: Set) -> Set:
36
+ """
37
+ start_info: dict with scene info and robot info
38
+ end_info: dict with scene info and robot info
39
+ task_filter: set with task names to check
40
+ returns set with achieved tasks
41
+ """
42
+ # call functions that are registered in self.tasks
43
+ return {
44
+ task_name
45
+ for task_name, function in self.tasks.items()
46
+ if task_name in task_filter and function(start_info=start_info, end_info=end_info)
47
+ }
48
+
49
+ @property
50
+ def num_tasks(self):
51
+ return len(self.tasks)
52
+
53
+ @staticmethod
54
+ def rotate_object(
55
+ obj_name, z_degrees, x_y_threshold=30, z_threshold=180, movement_threshold=0.1, start_info=None, end_info=None
56
+ ):
57
+ """
58
+ Returns True if the object with obj_name was rotated more than z_degrees degrees around the z-axis while not
59
+ being rotated more than x_y_threshold degrees around the x or y axis.
60
+ z_degrees is negative for clockwise rotations and positive for counter-clockwise rotations.
61
+ """
62
+ obj_start_info = start_info["scene_info"]["movable_objects"][obj_name]
63
+ obj_end_info = end_info["scene_info"]["movable_objects"][obj_name]
64
+ start_orn = R.from_quat(obj_start_info["current_orn"])
65
+ end_orn = R.from_quat(obj_end_info["current_orn"])
66
+ rotation = end_orn * start_orn.inv()
67
+ x, y, z = rotation.as_euler("xyz", degrees=True)
68
+
69
+ start_pos = np.array(obj_start_info["current_pos"])
70
+ end_pos = np.array(obj_end_info["current_pos"])
71
+ pos_diff = end_pos - start_pos
72
+ if np.linalg.norm(pos_diff) > movement_threshold:
73
+ return False
74
+
75
+ end_contacts = set(c[2] for c in obj_end_info["contacts"])
76
+ robot_uid = {start_info["robot_info"]["uid"]}
77
+ if len(end_contacts - robot_uid) == 0:
78
+ return False
79
+
80
+ if z_degrees > 0:
81
+ return z_degrees < z < z_threshold and abs(x) < x_y_threshold and abs(y) < x_y_threshold
82
+ else:
83
+ return z_degrees > z > -z_threshold and abs(x) < x_y_threshold and abs(y) < x_y_threshold
84
+
85
+ @staticmethod
86
+ def push_object(obj_name, x_direction, y_direction, start_info, end_info):
87
+ """
88
+ Returns True if the object with 'obj_name' was moved more than 'x_direction' meters in x direction
89
+ (or 'y_direction' meters in y direction analogously).
90
+ Note that currently x and y pushes are mutually exclusive, meaning that one of the arguments has to be 0.
91
+ The sign matters, e.g. pushing an object to the right when facing the table coincides with a movement in
92
+ positive x-direction.
93
+ """
94
+ assert x_direction * y_direction == 0 and x_direction + y_direction != 0
95
+ obj_start_info = start_info["scene_info"]["movable_objects"][obj_name]
96
+ obj_end_info = end_info["scene_info"]["movable_objects"][obj_name]
97
+ start_pos = np.array(obj_start_info["current_pos"])
98
+ end_pos = np.array(obj_end_info["current_pos"])
99
+ pos_diff = end_pos - start_pos
100
+
101
+ robot_uid = start_info["robot_info"]["uid"]
102
+ # contacts excluding robot
103
+ start_contacts = set((c[2], c[4]) for c in obj_start_info["contacts"] if c[2] != robot_uid)
104
+ end_contacts = set((c[2], c[4]) for c in obj_end_info["contacts"] if c[2] != robot_uid)
105
+
106
+ # computing set difference to check if object had surface contact (excluding robot) at both times
107
+ surface_contact = len(start_contacts) > 0 and len(end_contacts) > 0 and start_contacts <= end_contacts
108
+ if not surface_contact:
109
+ return False
110
+
111
+ if x_direction > 0:
112
+ return pos_diff[0] > x_direction
113
+ elif x_direction < 0:
114
+ return pos_diff[0] < x_direction
115
+
116
+ if y_direction > 0:
117
+ return pos_diff[1] > y_direction
118
+ elif y_direction < 0:
119
+ return pos_diff[1] < y_direction
120
+
121
+ @staticmethod
122
+ def lift_object(obj_name, z_direction, surface_body=None, surface_link=None, start_info=None, end_info=None):
123
+ """
124
+ Returns True if the object with 'obj_name' was grasped by the robot and lifted more than 'z_direction' meters.
125
+ """
126
+ assert z_direction > 0
127
+ obj_start_info = start_info["scene_info"]["movable_objects"][obj_name]
128
+ obj_end_info = end_info["scene_info"]["movable_objects"][obj_name]
129
+
130
+ start_pos = np.array(obj_start_info["current_pos"])
131
+ end_pos = np.array(obj_end_info["current_pos"])
132
+ pos_diff = end_pos - start_pos
133
+ z_diff = pos_diff[2]
134
+
135
+ robot_uid = start_info["robot_info"]["uid"]
136
+ start_contacts = set(c[2] for c in obj_start_info["contacts"])
137
+ end_contacts = set(c[2] for c in obj_end_info["contacts"])
138
+
139
+ surface_criterion = True
140
+ if surface_body and surface_link is None:
141
+ surface_uid = start_info["scene_info"]["fixed_objects"][surface_body]["uid"]
142
+ surface_criterion = surface_uid in start_contacts
143
+ elif surface_body and surface_link:
144
+ surface_uid = start_info["scene_info"]["fixed_objects"][surface_body]["uid"]
145
+ surface_link_id = start_info["scene_info"]["fixed_objects"][surface_body]["links"][surface_link]
146
+ start_contacts_links = set((c[2], c[4]) for c in obj_start_info["contacts"])
147
+ surface_criterion = (surface_uid, surface_link_id) in start_contacts_links
148
+
149
+ return (
150
+ z_diff > z_direction
151
+ # and robot_uid not in start_contacts
152
+ and robot_uid in end_contacts
153
+ and len(end_contacts) == 1
154
+ and surface_criterion
155
+ )
156
+
157
+ @staticmethod
158
+ def place_object(dest_body, dest_link=None, start_info=None, end_info=None):
159
+ """
160
+ Returns True if the object that the robot has currently lifted is placed on the body 'dest_body'
161
+ (on 'dest_link' if provided).
162
+ The robot may not touch the object after placing.
163
+ """
164
+ robot_uid = start_info["robot_info"]["uid"]
165
+
166
+ robot_contacts_start = set(c[2] for c in start_info["robot_info"]["contacts"])
167
+ robot_contacts_end = set(c[2] for c in end_info["robot_info"]["contacts"])
168
+ if not len(robot_contacts_start) == 1:
169
+ return False
170
+ obj_uid = list(robot_contacts_start)[0]
171
+
172
+ if obj_uid in robot_contacts_end:
173
+ return False
174
+ _obj_name = [k for k, v in start_info["scene_info"]["movable_objects"].items() if v["uid"] == obj_uid]
175
+ if not len(_obj_name) == 1:
176
+ return False
177
+ obj_name = _obj_name[0]
178
+
179
+ dest_uid = end_info["scene_info"]["fixed_objects"][dest_body]["uid"]
180
+
181
+ object_contacts_start = set(c[2] for c in start_info["scene_info"]["movable_objects"][obj_name]["contacts"])
182
+ if dest_link is None:
183
+ object_contacts_end = set(c[2] for c in end_info["scene_info"]["movable_objects"][obj_name]["contacts"])
184
+ return (
185
+ robot_uid in object_contacts_start
186
+ and len(object_contacts_start) == 1
187
+ and dest_uid in object_contacts_end
188
+ )
189
+ else:
190
+ dest_link_id = end_info["scene_info"]["fixed_objects"][dest_body]["links"][dest_link]
191
+ end_contacts_links = set(
192
+ (c[2], c[4]) for c in end_info["scene_info"]["movable_objects"][obj_name]["contacts"]
193
+ )
194
+ return (
195
+ robot_uid in object_contacts_start
196
+ and len(object_contacts_start) == 1
197
+ and (dest_uid, dest_link_id) in end_contacts_links
198
+ )
199
+
200
+ @staticmethod
201
+ def push_object_into(obj_name, src_body, src_link, dest_body, dest_link, start_info=None, end_info=None):
202
+ """
203
+ obj_name is either a list of object names or a string
204
+ Returns True if the object / any of the objects changes contact from src_body to dest_body.
205
+ The robot may neither touch the object at start nor end.
206
+ """
207
+ if isinstance(obj_name, (list, ListConfig)):
208
+ return any(
209
+ Tasks.push_object_into(ob, src_body, src_link, dest_body, dest_link, start_info, end_info)
210
+ for ob in obj_name
211
+ )
212
+ robot_uid = start_info["robot_info"]["uid"]
213
+
214
+ src_uid = start_info["scene_info"]["fixed_objects"][src_body]["uid"]
215
+ src_link_id = start_info["scene_info"]["fixed_objects"][src_body]["links"][src_link]
216
+ dest_uid = end_info["scene_info"]["fixed_objects"][dest_body]["uid"]
217
+ dest_link_id = end_info["scene_info"]["fixed_objects"][dest_body]["links"][dest_link]
218
+
219
+ start_contacts = set((c[2], c[4]) for c in start_info["scene_info"]["movable_objects"][obj_name]["contacts"])
220
+ end_contacts = set((c[2], c[4]) for c in end_info["scene_info"]["movable_objects"][obj_name]["contacts"])
221
+ return (
222
+ robot_uid not in start_contacts | end_contacts
223
+ and len(start_contacts) == 1
224
+ and (src_uid, src_link_id) in start_contacts
225
+ and (dest_uid, dest_link_id) in end_contacts
226
+ )
227
+
228
+ @staticmethod
229
+ def move_door_abs(joint_name, start_threshold, end_threshold, start_info, end_info):
230
+ """
231
+ Returns True if the joint specified by 'obj_name' and 'joint_name' (e.g. a door or drawer)
232
+ is moved from at least 'start_threshold' to 'end_threshold'.
233
+ """
234
+ start_joint_state = start_info["scene_info"]["doors"][joint_name]["current_state"][0]
235
+ end_joint_state = end_info["scene_info"]["doors"][joint_name]["current_state"][0]
236
+
237
+ if start_threshold < end_threshold:
238
+ return start_joint_state < start_threshold < end_threshold < end_joint_state
239
+ elif start_threshold > end_threshold:
240
+ return start_joint_state > start_threshold > end_threshold > end_joint_state
241
+ else:
242
+ raise ValueError
243
+
244
+ @staticmethod
245
+ def move_door_rel(joint_name, threshold, start_info, end_info):
246
+ """
247
+ Returns True if the joint specified by 'obj_name' and 'joint_name' (e.g. a door or drawer)
248
+ is moved from at least 'start_threshold' to 'end_threshold'.
249
+ """
250
+ start_joint_state = start_info["scene_info"]["doors"][joint_name]["current_state"]
251
+ end_joint_state = end_info["scene_info"]["doors"][joint_name]["current_state"]
252
+
253
+ return (
254
+ 0 < threshold < end_joint_state - start_joint_state or 0 > threshold > end_joint_state - start_joint_state
255
+ )
256
+
257
+ @staticmethod
258
+ def toggle_light(light_name, start_state, end_state, start_info, end_info):
259
+ return (
260
+ start_info["scene_info"]["lights"][light_name]["logical_state"] == start_state
261
+ and end_info["scene_info"]["lights"][light_name]["logical_state"] == end_state
262
+ )
263
+
264
+ @staticmethod
265
+ def stack_objects(max_vel=1, start_info=None, end_info=None):
266
+ obj_uids = set(obj["uid"] for obj in start_info["scene_info"]["movable_objects"].values())
267
+
268
+ for obj_name in start_info["scene_info"]["movable_objects"]:
269
+ obj_start_info = start_info["scene_info"]["movable_objects"][obj_name]
270
+ obj_end_info = end_info["scene_info"]["movable_objects"][obj_name]
271
+ obj_start_contacts = set(c[2] for c in obj_start_info["contacts"])
272
+ obj_end_contacts = set(c[2] for c in obj_end_info["contacts"])
273
+
274
+ if (
275
+ not len(obj_uids & obj_start_contacts)
276
+ and len(obj_uids & obj_end_contacts)
277
+ and not len(obj_end_contacts - obj_uids)
278
+ ):
279
+ # object velocity may not exceed max_vel for successful stack
280
+ if np.all(np.abs(obj_end_info["current_lin_vel"]) < max_vel) and np.all(
281
+ np.abs(obj_end_info["current_ang_vel"]) < max_vel
282
+ ):
283
+ return True
284
+ return False
285
+
286
+ @staticmethod
287
+ def unstack_objects(max_vel=1, start_info=None, end_info=None):
288
+ obj_uids = set(obj["uid"] for obj in start_info["scene_info"]["movable_objects"].values())
289
+
290
+ for obj_name in start_info["scene_info"]["movable_objects"]:
291
+ obj_start_info = start_info["scene_info"]["movable_objects"][obj_name]
292
+ obj_end_info = end_info["scene_info"]["movable_objects"][obj_name]
293
+ obj_start_contacts = set(c[2] for c in obj_start_info["contacts"])
294
+ obj_end_contacts = set(c[2] for c in obj_end_info["contacts"])
295
+
296
+ if (
297
+ len(obj_uids & obj_start_contacts)
298
+ and not len(obj_start_contacts - obj_uids)
299
+ and not len(obj_uids & obj_end_contacts)
300
+ ):
301
+ # object velocity may not exceed max_vel for successful stack
302
+ if np.all(np.abs(obj_start_info["current_lin_vel"]) < max_vel) and np.all(
303
+ np.abs(obj_start_info["current_ang_vel"]) < max_vel
304
+ ):
305
+ return True
306
+ return False
aloha_robot_project/calvin/calvin_env/calvin_env/io_utils/data_recorder.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import multiprocessing as mp
3
+ import os
4
+ import pickle
5
+ import time
6
+
7
+ # A logger for this file
8
+ log = logging.getLogger(__name__)
9
+
10
+
11
+ class DataRecorder:
12
+ """
13
+ Collects frame information to file in output-dir with
14
+ filename: <TIMESTAMP>/<FRAME>.pickle
15
+ Saving facility with separate worker thread.
16
+ """
17
+
18
+ def __init__(self, env, record_fps, enable_tts):
19
+ """
20
+ Setup MultiprocessingStorage
21
+ """
22
+ self.env = env
23
+ self.queue = mp.Queue()
24
+ self.process = mp.Process(target=self.process_queue, name="MultiprocessingStorageWorker")
25
+ self.process.start()
26
+ self.running = True
27
+ self.save_frame_cnt = 0
28
+ log.info("Starting serialization worker process")
29
+ self.prev_time = time.time()
30
+ self.loop_time = 1.0 / record_fps
31
+ self._unsaved_vr_events = []
32
+ self.enable_tts = enable_tts
33
+ if enable_tts:
34
+ import pyttsx3
35
+
36
+ self.tts = pyttsx3.init()
37
+ self.tts.setProperty("rate", 175)
38
+ self.prev_done = False
39
+ self.current_episode_filenames = []
40
+
41
+ def step(self, prev_vr_event, state_obs, done, info):
42
+ self._unsaved_vr_events.extend(prev_vr_event)
43
+ current_time = time.time()
44
+ delta_t = current_time - self.prev_time
45
+ if delta_t >= self.loop_time or done:
46
+ log.debug(f"Record FPS: {1 / delta_t:.0f}")
47
+ self.prev_time = time.time()
48
+ file_path = f"{str(self.save_frame_cnt).zfill(12)}.pickle"
49
+ self.save(file_path, self._unsaved_vr_events, state_obs, done, info)
50
+ if self.prev_done and not done:
51
+ self.current_episode_filenames = []
52
+ self.current_episode_filenames.append(file_path)
53
+
54
+ # file_path_state = f"{str(self.save_frame_cnt).zfill(12)}_state.pickle"
55
+ # with open(file_path_state, 'wb') as file:
56
+ # pickle.dump(state_obs, file)
57
+
58
+ self._unsaved_vr_events = []
59
+ self.save_frame_cnt += 1
60
+ self.prev_done = done
61
+
62
+ def save(self, filename, vr_events, state_obs, done, info):
63
+ """
64
+ Extract dataFrame from pybullet and enqueue for worker thread.
65
+
66
+ Args:
67
+ filename: path to file
68
+ vr_events: vrEvents to attach to data
69
+ state_obs: state observations
70
+ done: true if episode ends
71
+ info: info dict
72
+
73
+ Returns:
74
+ None
75
+ """
76
+ data = self.env.serialize()
77
+ data["vr_events"] = vr_events
78
+ data["state_obs"] = state_obs
79
+ data["done"] = done
80
+ data["info"] = info
81
+ self.queue.put((filename, data))
82
+
83
+ def delete_episode(self):
84
+ num_frames = len(self.current_episode_filenames)
85
+ if self.enable_tts:
86
+ self.tts.say(f"Deleting last episode with {num_frames} frames")
87
+ self.tts.runAndWait()
88
+ for filename in self.current_episode_filenames:
89
+ os.remove(filename)
90
+ if self.enable_tts:
91
+ self.tts.say("Finished deleting")
92
+ self.tts.runAndWait()
93
+ self.save_frame_cnt -= num_frames
94
+ self.current_episode_filenames = []
95
+
96
+ def process_queue(self):
97
+ """
98
+ Process function for queue.
99
+ Returns:
100
+ None
101
+ """
102
+ while True:
103
+ msg = self.queue.get()
104
+ if msg == "QUIT":
105
+ self.running = False
106
+ break
107
+ (filename, data) = msg
108
+ with open(filename, "wb") as file:
109
+ pickle.dump(data, file)
110
+
111
+ def close(self):
112
+ """
113
+ Tell Worker to shut down.
114
+ Returns:
115
+ None
116
+ """
117
+ if self.running:
118
+ self.queue.put("QUIT")
119
+ self.process.join()
120
+
121
+ def __enter__(self):
122
+ """
123
+ with ... as ... : logic
124
+ Returns:
125
+ None
126
+ """
127
+ return self
128
+
129
+ def __exit__(self, exc_type, exc_val, exc_tb):
130
+ """
131
+ with ... as ... : logic
132
+ Returns:
133
+ None
134
+ """
135
+ self.close()
aloha_robot_project/calvin/calvin_env/calvin_env/io_utils/vr_input.py ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import collections
2
+ import logging
3
+
4
+ import numpy as np
5
+ import pybullet as p
6
+ import quaternion # noqa
7
+
8
+ import calvin_env.utils.utils as utils
9
+
10
+ # A logger for this file
11
+ log = logging.getLogger(__name__)
12
+
13
+
14
+ # identical for both controllers
15
+ RELEVANT_BUTTONS = {
16
+ "button_a": 7,
17
+ "button_b": 1,
18
+ "thumb_trigger": 2, # on the left of the (right) controller; also 34 sent
19
+ "index_trigger": 33,
20
+ }
21
+
22
+
23
+ class ButtonState(collections.namedtuple("ButtonState", ("button_name", "is_down", "was_triggered", "was_released"))):
24
+ __slots__ = ()
25
+
26
+ @classmethod
27
+ def from_flag(cls, button_name, flag):
28
+ return cls(
29
+ button_name,
30
+ bool(flag & p.VR_BUTTON_IS_DOWN),
31
+ bool(flag & p.VR_BUTTON_WAS_TRIGGERED),
32
+ bool(flag & p.VR_BUTTON_WAS_RELEASED),
33
+ )
34
+
35
+
36
+ class VrEvent(
37
+ collections.namedtuple(
38
+ "VrEvent",
39
+ [
40
+ "controller_id",
41
+ "position",
42
+ "orientation",
43
+ "analog_axis",
44
+ "n_button_events",
45
+ "n_move_events",
46
+ "buttons",
47
+ "device_type_flag",
48
+ ],
49
+ )
50
+ ):
51
+ __slots__ = ()
52
+
53
+ @property
54
+ def button_dicts(self):
55
+ return {
56
+ button_name: ButtonState.from_flag(button_name, self.buttons[button_idx])
57
+ for button_name, button_idx in RELEVANT_BUTTONS.items()
58
+ }
59
+ # overall 64 buttons according to OpenVR
60
+ # enumerate([f'button_{i}' for i in range(64)])}
61
+
62
+ @property
63
+ def device_type(self):
64
+ return {p.VR_DEVICE_HMD: "hmd", p.VR_DEVICE_CONTROLLER: "controller", p.VR_DEVICE_GENERIC_TRACKER: "generic"}[
65
+ self.device_type_flag
66
+ ]
67
+
68
+
69
+ class VrInput:
70
+ """
71
+ pyBullet VR Data Collector
72
+ """
73
+
74
+ def __init__(self, vr_controller, limit_angle, visualize_vr_pos, reset_button_queue_len):
75
+ self.vr_controller_id = vr_controller.vr_controller_id
76
+ self.vr_controller = vr_controller
77
+ self.POSITION = vr_controller.POSITION
78
+ self.ORIENTATION = vr_controller.ORIENTATION
79
+ self.ANALOG = vr_controller.ANALOG
80
+ self.BUTTONS = vr_controller.BUTTONS
81
+ self.BUTTON_A = vr_controller.BUTTON_A
82
+ self.BUTTON_B = vr_controller.BUTTON_B
83
+ if limit_angle is not None:
84
+ self.limit_angle = limit_angle[0]
85
+ self.limit_vector = limit_angle[1:]
86
+ else:
87
+ self.limit_angle = None
88
+ self.gripper_position_offset = np.array(vr_controller.gripper_position_offset)
89
+ self.gripper_orientation_offset = quaternion.from_euler_angles(vr_controller.gripper_orientation_offset)
90
+ self.visualize_vr_pos = visualize_vr_pos
91
+ self.vr_pos_uid = None
92
+ if visualize_vr_pos:
93
+ self.vr_pos_uid = self.create_vr_pos_visualization_shape()
94
+ log.info("Disable Picking")
95
+ p.configureDebugVisualizer(p.COV_ENABLE_VR_PICKING, 0)
96
+ p.configureDebugVisualizer(p.COV_ENABLE_VR_RENDER_CONTROLLERS, 0)
97
+ self._prev_vr_events = None
98
+ self.prev_action = None
99
+ self._reset_button_pressed = False
100
+ self._start_button_pressed = False
101
+ self._prev_reset_button_pressed = False
102
+ self._prev_start_button_pressed = False
103
+ self.reset_button_press_counter = 0
104
+ self.reset_button_queue_len = reset_button_queue_len
105
+ # wait until first vr action event arrives
106
+ while self.prev_action is None:
107
+ _ = self.get_vr_action()
108
+
109
+ def create_vr_pos_visualization_shape(self):
110
+ visual_shape_id = p.createVisualShape(shapeType=p.GEOM_SPHERE, rgbaColor=[1, 0, 0, 1], radius=0.005)
111
+ return p.createMultiBody(baseMass=0, baseVisualShapeIndex=visual_shape_id, basePosition=[0, 0, 0])
112
+
113
+ def get_vr_action(self):
114
+ # self._reset_button_pressed = False
115
+ self._prev_reset_button_pressed = self._reset_button_pressed
116
+ self._prev_start_button_pressed = self._start_button_pressed
117
+ vr_events = p.getVREvents()
118
+ if vr_events != ():
119
+ self._prev_vr_events = vr_events
120
+ for event in vr_events:
121
+ # Only use one controller
122
+ # if event[0] == self.vr_controller_id:
123
+ action = (event[self.POSITION], event[self.ORIENTATION], event[self.ANALOG])
124
+
125
+ self._reset_button_pressed = event[self.BUTTONS][self.BUTTON_B] & p.VR_BUTTON_IS_DOWN > 0
126
+ self._start_button_pressed = event[self.BUTTONS][self.BUTTON_A] & p.VR_BUTTON_IS_DOWN > 0
127
+ robot_action = self.vr_action_to_robot_action(action)
128
+
129
+ self.update_reset_button_queue()
130
+ self.prev_action = robot_action
131
+ return robot_action
132
+
133
+ return self.prev_action
134
+
135
+ def vr_action_to_robot_action(self, action):
136
+ controller_pos, vr_controller_orientation, controller_analogue_axis = action
137
+ desired_ee_pos = controller_pos + self.gripper_position_offset
138
+ orientation = utils.xyzw_to_wxyz(vr_controller_orientation)
139
+ q1 = quaternion.from_float_array(orientation)
140
+ q2 = self.gripper_orientation_offset
141
+ q12 = q1 * q2
142
+ arr = quaternion.as_float_array(q12)
143
+ desired_ee_orn = utils.wxyz_to_xyzw(arr)
144
+
145
+ # v2 = quaternion.rotate_vectors(q12, [0, 0, 1])
146
+ # if self.limit_angle is not None:
147
+ # if utils.angle_between(self.limit_vector, v2) <= self.limit_angle / 180 * math.pi:
148
+ # self.prev_ee_orn = desired_ee_orn
149
+ # else:
150
+ # desired_ee_orn = self.prev_ee_orn
151
+
152
+ if controller_analogue_axis > 0.1:
153
+ gripper_action = -1
154
+ else:
155
+ gripper_action = 1
156
+
157
+ # change color of vr pos sphere when starting or ending recording
158
+ if self.visualize_vr_pos:
159
+ if self.start_button_pressed:
160
+ p.changeVisualShape(self.vr_pos_uid, -1, rgbaColor=[0, 1, 0, 1])
161
+ if self.reset_button_pressed:
162
+ p.changeVisualShape(self.vr_pos_uid, -1, rgbaColor=[1, 0, 0, 1])
163
+ p.resetBasePositionAndOrientation(self.vr_pos_uid, desired_ee_pos, desired_ee_orn)
164
+
165
+ return desired_ee_pos, desired_ee_orn, gripper_action
166
+
167
+ def update_reset_button_queue(self):
168
+ if self._reset_button_pressed:
169
+ self.reset_button_press_counter += 1
170
+ else:
171
+ self.reset_button_press_counter = 0
172
+
173
+ @property
174
+ def reset_button_hold(self):
175
+ return self.reset_button_press_counter >= self.reset_button_queue_len
176
+
177
+ @property
178
+ def reset_button_pressed(self):
179
+ return self._reset_button_pressed and not self._prev_reset_button_pressed
180
+
181
+ @property
182
+ def start_button_pressed(self):
183
+ return self._start_button_pressed and not self._prev_start_button_pressed
184
+
185
+ @property
186
+ def prev_vr_events(self):
187
+ return self._prev_vr_events
aloha_robot_project/calvin/calvin_env/calvin_env/robot/IKfast.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from ikfast_franka_panda import get_ik
2
+ import numpy as np
3
+ from scipy.spatial.transform import Rotation as R
4
+
5
+
6
+ class IKfast:
7
+ def __init__(
8
+ self,
9
+ robot_uid,
10
+ cid,
11
+ rp,
12
+ ll_real,
13
+ ul_real,
14
+ base_position,
15
+ base_orientation,
16
+ weights=[1, 1, 1, 1, 1, 1, 1],
17
+ num_angles=50,
18
+ ):
19
+ self.robot_uid = robot_uid
20
+ self.cid = cid
21
+ self.ll_real = ll_real
22
+ self.ul_real = ul_real
23
+ self.rp = rp
24
+ self.num_dof = len(self.ll_real)
25
+ self.weights = weights
26
+ self.num_angles = num_angles
27
+ T_world_robot = np.eye(4)
28
+ T_world_robot[:3, 3] = base_position
29
+ T_world_robot[:3, :3] = R.from_quat(base_orientation).as_matrix()
30
+ self.T_robot_world = np.linalg.inv(T_world_robot)
31
+
32
+ def world_to_robot(self, pos_w, orn_w):
33
+ """
34
+ pos, quat -> pos, Rot
35
+ """
36
+ pose_w = np.eye(4)
37
+ pose_w[:3, 3] = pos_w
38
+ pose_w[:3, :3] = R.from_quat(orn_w).as_matrix()
39
+ pose_r = self.T_robot_world @ pose_w
40
+ pos_r = list(pose_r[:3, 3])
41
+ orn_r = pose_r[:3, :3].tolist()
42
+ return pos_r, orn_r
43
+
44
+ def filter_solutions(self, sol):
45
+ test_sol = np.ones(self.num_dof) * 9999.0
46
+ for i in range(self.num_dof):
47
+ for add_ang in [-2.0 * np.pi, 0, 2.0 * np.pi]:
48
+ test_ang = sol[i] + add_ang
49
+ if self.ul_real[i] >= test_ang >= self.ll_real[i]:
50
+ test_sol[i] = test_ang
51
+ if np.all(test_sol != 9999.0):
52
+ return test_sol
53
+ return None
54
+
55
+ def take_closest_sol(self, sols, last_q, weights):
56
+ best_sol_ind = np.argmin(np.sum((weights * (sols - np.array(last_q))) ** 2, 1))
57
+ return sols[best_sol_ind]
58
+
59
+ def get_ik_solution(self, target_pos, target_orn):
60
+ target_pos_robot, target_orn_robot = self.world_to_robot(target_pos, target_orn)
61
+ sols = []
62
+ feasible_sols = []
63
+ for q_6 in np.linspace(self.ll_real[-1], self.ul_real[-1], self.num_angles):
64
+ sols += get_ik(target_pos_robot, target_orn_robot, [q_6])
65
+ for sol in sols:
66
+ sol = self.filter_solutions(sol)
67
+ if sol is not None:
68
+ feasible_sols.append(sol)
69
+ if len(feasible_sols) < 1:
70
+ return None
71
+ best_sol = self.take_closest_sol(feasible_sols, self.rp[:7], self.weights)
72
+ return best_sol
aloha_robot_project/calvin/calvin_env/calvin_env/robot/mixed_ik.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import pybullet as p
3
+ from scipy.spatial.transform import Rotation as R
4
+
5
+ from calvin_env.utils.utils import angle_between_quaternions
6
+
7
+
8
+ class MixedIK:
9
+ def __init__(
10
+ self,
11
+ robot_uid,
12
+ cid,
13
+ ll_real,
14
+ ul_real,
15
+ base_position,
16
+ base_orientation,
17
+ tcp_link_id,
18
+ ll,
19
+ ul,
20
+ jr,
21
+ rp,
22
+ use_ik_fast,
23
+ use_nullspace=True,
24
+ threshold_pos=0.01,
25
+ threshold_orn=0.05,
26
+ weights=(1, 1, 1, 1, 1, 1, 1),
27
+ num_angles=50,
28
+ ):
29
+ self.robot_uid = robot_uid
30
+ self.cid = cid
31
+ self.use_nullspace = use_nullspace
32
+ self.use_ik_fast = use_ik_fast
33
+ self.ik_fast = None
34
+ if self.use_ik_fast:
35
+ from ikfast_franka_panda import get_fk
36
+
37
+ from calvin_env.robot.IKfast import IKfast
38
+
39
+ self.get_fk = get_fk
40
+ self.ik_fast = IKfast(
41
+ robot_uid, cid, rp, ll_real, ul_real, base_position, base_orientation, weights, num_angles
42
+ )
43
+ self.tcp_link_id = tcp_link_id
44
+ self.ll = ll
45
+ self.ul = ul
46
+ self.jr = jr
47
+ self.ll_real = ll_real
48
+ self.ul_real = ul_real
49
+ self.rp = rp
50
+ self.num_dof = len(self.ll_real)
51
+ self.threshold_pos = threshold_pos
52
+ self.threshold_orn = threshold_orn
53
+ self.is_using_IK_fast = False
54
+
55
+ def get_bullet_ik(self, desired_ee_pos, desired_ee_orn):
56
+ if self.use_nullspace:
57
+ jnt_ps = p.calculateInverseKinematics(
58
+ self.robot_uid,
59
+ self.tcp_link_id,
60
+ desired_ee_pos,
61
+ desired_ee_orn,
62
+ self.ll,
63
+ self.ul,
64
+ self.jr,
65
+ self.rp,
66
+ physicsClientId=self.cid,
67
+ )
68
+ else:
69
+ jnt_ps = p.calculateInverseKinematics(
70
+ self.robot_uid, self.tcp_link_id, desired_ee_pos, desired_ee_orn, physicsClientId=self.cid
71
+ )
72
+ # clip joint positions outside the joint ranges
73
+ jnt_ps = np.clip(jnt_ps[: self.num_dof], self.ll_real, self.ul_real)
74
+ return jnt_ps
75
+
76
+ def robot_to_world(self, pos_r, orn_r):
77
+ """
78
+ pos, Rot -> pos, quat
79
+ """
80
+ pose_r = np.eye(4)
81
+ pose_r[:3, 3] = pos_r
82
+ pose_r[:3, :3] = orn_r
83
+ pose_w = np.linalg.inv(self.ik_fast.T_robot_world) @ pose_r
84
+ pos_r = pose_w[:3, 3]
85
+ orn_r = R.from_matrix(pose_w[:3, :3]).as_quat()
86
+ return pos_r, orn_r
87
+
88
+ def pose_within_threshold(self, target_pos, target_orn, q):
89
+ pos, orn = self.get_fk(q)
90
+ pos, orn = self.robot_to_world(pos, orn)
91
+ angular_diff = angle_between_quaternions(orn, target_orn)
92
+ threshold_pos_exceeded = np.linalg.norm(target_pos - pos) > self.threshold_pos
93
+ threshold_orn_exceeded = angular_diff > self.threshold_orn
94
+ return not (threshold_pos_exceeded or threshold_orn_exceeded)
95
+
96
+ def get_joint_states(self):
97
+ return list(zip(*p.getJointStates(self.robot_uid, range(self.num_dof))))[0]
98
+
99
+ def get_ik(self, target_pos, target_orn):
100
+ if self.is_using_IK_fast and not self.pose_within_threshold(target_pos, target_orn, self.get_joint_states()):
101
+ q_ik_fast = self.ik_fast.get_ik_solution(target_pos, target_orn)
102
+ if q_ik_fast is not None:
103
+ self.is_using_IK_fast = True
104
+ return q_ik_fast
105
+ else:
106
+ self.is_using_IK_fast = False
107
+ q_bullet = self.get_bullet_ik(target_pos, target_orn)
108
+ return q_bullet
109
+ self.is_using_IK_fast = False
110
+ q_bullet = self.get_bullet_ik(target_pos, target_orn)
111
+ if self.use_ik_fast and not self.pose_within_threshold(target_pos, target_orn, q_bullet):
112
+ q_ik_fast = self.ik_fast.get_ik_solution(target_pos, target_orn)
113
+ if q_ik_fast is not None:
114
+ self.is_using_IK_fast = True
115
+ return q_ik_fast
116
+ else:
117
+ return q_bullet
118
+ return q_bullet
aloha_robot_project/calvin/calvin_env/calvin_env/robot/robot.py ADDED
@@ -0,0 +1,412 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+
3
+ import numpy as np
4
+ import pybullet as p
5
+
6
+ from calvin_env.robot.mixed_ik import MixedIK
7
+
8
+ # A logger for this file
9
+ log = logging.getLogger(__name__)
10
+
11
+
12
+ class Robot:
13
+ def __init__(
14
+ self,
15
+ filename,
16
+ base_position,
17
+ base_orientation,
18
+ initial_joint_positions,
19
+ max_joint_force,
20
+ gripper_force,
21
+ arm_joint_ids,
22
+ gripper_joint_ids,
23
+ gripper_joint_limits,
24
+ tcp_link_id,
25
+ end_effector_link_id,
26
+ cid,
27
+ use_nullspace,
28
+ max_velocity,
29
+ use_ik_fast,
30
+ euler_obs,
31
+ lower_joint_limits=(-2.8973, -1.7628, -2.8973, -3.0718, -2.8973, -0.0175, -2.8973),
32
+ upper_joint_limits=(2.8973, 1.7628, 2.8973, -0.0698, 2.8973, 3.7525, 2.8973),
33
+ max_rel_pos=0.02,
34
+ max_rel_orn=0.05,
35
+ magic_scaling_factor_pos=1,
36
+ magic_scaling_factor_orn=1,
37
+ use_target_pose=True,
38
+ **kwargs,
39
+ ):
40
+ log.info("Loading robot")
41
+ self.cid = cid
42
+ self.filename = filename
43
+ self.use_nullspace = use_nullspace
44
+ self.max_velocity = max_velocity
45
+ self.use_ik_fast = use_ik_fast
46
+ self.base_position = base_position
47
+ self.base_orientation = p.getQuaternionFromEuler(base_orientation)
48
+ self.arm_joint_ids = arm_joint_ids
49
+ self.initial_joint_positions = np.array(initial_joint_positions)
50
+ self.gripper_joint_ids = gripper_joint_ids
51
+ self.max_joint_force = max_joint_force
52
+ self.gripper_force = gripper_force
53
+ self.gripper_joint_limits = gripper_joint_limits
54
+ self.tcp_link_id = tcp_link_id
55
+ # Setup constraint
56
+ self.prev_ee_orn = p.getQuaternionFromEuler([0, 0, 0])
57
+ self.robot_uid = None
58
+ self.end_effector_link_id = end_effector_link_id
59
+ self.gripper_action = 1
60
+ self.ll = self.ul = self.jr = self.rp = None
61
+ self.ll_real = np.array(lower_joint_limits)
62
+ self.ul_real = np.array(upper_joint_limits)
63
+ self.mixed_ik = None
64
+ self.euler_obs = euler_obs
65
+ self.max_rel_pos = max_rel_pos
66
+ self.max_rel_orn = max_rel_orn
67
+ self.magic_scaling_factor_pos = magic_scaling_factor_pos
68
+ self.magic_scaling_factor_orn = magic_scaling_factor_orn
69
+ self.target_pos = None
70
+ self.target_orn = None
71
+ self.use_target_pose = use_target_pose
72
+ # self.reconfigure = False
73
+
74
+ def load(self):
75
+ self.robot_uid = p.loadURDF(
76
+ fileName=self.filename,
77
+ basePosition=self.base_position,
78
+ baseOrientation=self.base_orientation,
79
+ useFixedBase=True,
80
+ physicsClientId=self.cid,
81
+ )
82
+ self.add_base_cylinder()
83
+ # create a constraint to keep the fingers centered
84
+ c = p.createConstraint(
85
+ self.robot_uid,
86
+ self.gripper_joint_ids[0],
87
+ self.robot_uid,
88
+ self.gripper_joint_ids[1],
89
+ jointType=p.JOINT_GEAR,
90
+ jointAxis=[1, 0, 0],
91
+ parentFramePosition=[0, 0, 0],
92
+ childFramePosition=[0, 0, 0],
93
+ physicsClientId=self.cid,
94
+ )
95
+ p.changeConstraint(c, gearRatio=-1, erp=0.1, maxForce=50, physicsClientId=self.cid)
96
+ num_dof = p.computeDofCount(self.robot_uid)
97
+ # lower limits for null space (todo: set them to proper range)
98
+ self.ll = [-7] * num_dof
99
+ # upper limits for null space (todo: set them to proper range)
100
+ self.ul = [7] * num_dof
101
+ # joint ranges for null space (todo: set them to proper range)
102
+ self.jr = [7] * num_dof
103
+ # restposes for null space
104
+ self.rp = list(self.initial_joint_positions) + [self.gripper_joint_limits[1]] * 2
105
+ self.reset()
106
+ self.mixed_ik = MixedIK(
107
+ self.robot_uid,
108
+ self.cid,
109
+ self.ll_real,
110
+ self.ul_real,
111
+ self.base_position,
112
+ self.base_orientation,
113
+ self.tcp_link_id,
114
+ self.ll,
115
+ self.ul,
116
+ self.jr,
117
+ self.rp,
118
+ self.use_ik_fast,
119
+ threshold_pos=0.03,
120
+ threshold_orn=0.1,
121
+ weights=(10, 8, 6, 6, 2, 2, 1),
122
+ num_angles=30,
123
+ )
124
+
125
+ def add_base_cylinder(self):
126
+ """
127
+ TODO: this should happen in load(), but that would break compatibility with old recorded data
128
+ """
129
+ pos = self.base_position.copy()
130
+ pos[2] /= 2
131
+ angle = p.getEulerFromQuaternion(self.base_orientation)[2]
132
+ pos[0] -= np.cos(angle) * 0.05
133
+ pos[1] -= np.sin(angle) * 0.05
134
+ cylinder = p.createVisualShape(
135
+ shapeType=p.GEOM_CYLINDER,
136
+ rgbaColor=[1, 1, 1, 1],
137
+ radius=0.13,
138
+ length=self.base_position[2],
139
+ visualFramePosition=pos,
140
+ )
141
+ p.createMultiBody(baseVisualShapeIndex=cylinder)
142
+
143
+ def reset(self, robot_state=None):
144
+ if robot_state is None:
145
+ gripper_state = self.gripper_joint_limits[1]
146
+ joint_states = self.initial_joint_positions
147
+ else:
148
+ joint_indices = [i for i, x in enumerate(self.get_observation_labels()) if x.startswith("robot_joint")]
149
+ joint_states = robot_state[joint_indices]
150
+ gripper_state = robot_state[self.get_observation_labels().index("gripper_opening_width")] / 2
151
+
152
+ assert len(joint_states) == len(self.arm_joint_ids)
153
+ for i, _id in enumerate(self.arm_joint_ids):
154
+ p.resetJointState(self.robot_uid, _id, joint_states[i], physicsClientId=self.cid)
155
+ p.setJointMotorControl2(
156
+ bodyIndex=self.robot_uid,
157
+ jointIndex=_id,
158
+ controlMode=p.POSITION_CONTROL,
159
+ force=self.max_joint_force,
160
+ targetPosition=joint_states[i],
161
+ maxVelocity=self.max_velocity,
162
+ physicsClientId=self.cid,
163
+ )
164
+ for i in self.gripper_joint_ids:
165
+ p.resetJointState(self.robot_uid, i, gripper_state, physicsClientId=self.cid)
166
+ p.setJointMotorControl2(
167
+ bodyIndex=self.robot_uid,
168
+ jointIndex=i,
169
+ controlMode=p.POSITION_CONTROL,
170
+ force=self.gripper_force,
171
+ targetPosition=gripper_state,
172
+ maxVelocity=1,
173
+ physicsClientId=self.cid,
174
+ )
175
+ tcp_pos, tcp_orn = p.getLinkState(self.robot_uid, self.tcp_link_id, physicsClientId=self.cid)[:2]
176
+ if self.euler_obs:
177
+ tcp_orn = p.getEulerFromQuaternion(tcp_orn)
178
+ self.target_pos = np.array(tcp_pos)
179
+ self.target_orn = np.array(tcp_orn)
180
+
181
+ def get_observation(self):
182
+ """
183
+ returns:
184
+ - robot_state: ndarray (16,)
185
+ - tcp_pos: robot_state[:3]
186
+ - tcp_orn: robot_state[3:7] (quat) / [3:6] (euler)
187
+ - gripper_opening_width: robot_state[7:8] (quat) / [6:7] (euler)
188
+ - arm_joint_states: robot_state[8:15] (quat) / [7:14] (euler)
189
+ - gripper_action: robot_state[15:] (quat) / [14:] (euler)
190
+ - robot_info: Dict
191
+ """
192
+ tcp_pos, tcp_orn = p.getLinkState(self.robot_uid, self.tcp_link_id, physicsClientId=self.cid)[:2]
193
+ if self.euler_obs:
194
+ tcp_orn = p.getEulerFromQuaternion(tcp_orn)
195
+ gripper_opening_width = (
196
+ p.getJointState(self.robot_uid, self.gripper_joint_ids[0], physicsClientId=self.cid)[0]
197
+ + p.getJointState(self.robot_uid, self.gripper_joint_ids[1], physicsClientId=self.cid)[0]
198
+ )
199
+ arm_joint_states = []
200
+ for i in self.arm_joint_ids:
201
+ arm_joint_states.append(p.getJointState(self.robot_uid, i, physicsClientId=self.cid)[0])
202
+ robot_state = np.array([*tcp_pos, *tcp_orn, gripper_opening_width, *arm_joint_states, self.gripper_action])
203
+ robot_info = {
204
+ "tcp_pos": tcp_pos,
205
+ "tcp_orn": tcp_orn,
206
+ "gripper_opening_width": gripper_opening_width,
207
+ "arm_joint_states": arm_joint_states,
208
+ "gripper_action": self.gripper_action,
209
+ "uid": self.robot_uid,
210
+ "contacts": p.getContactPoints(bodyA=self.robot_uid, physicsClientId=self.cid),
211
+ }
212
+ return robot_state, robot_info
213
+
214
+ def get_observation_labels(self):
215
+ tcp_pos_labels = [f"tcp_pos_{ax}" for ax in ("x", "y", "z")]
216
+ if self.euler_obs:
217
+ tcp_orn_labels = [f"tcp_orn_{ax}" for ax in ("x", "y", "z")]
218
+ else:
219
+ tcp_orn_labels = [f"tcp_orn_{ax}" for ax in ("x", "y", "z", "w")]
220
+ return [
221
+ *tcp_pos_labels,
222
+ *tcp_orn_labels,
223
+ "gripper_opening_width",
224
+ *[f"robot_joint_{i}" for i in self.arm_joint_ids],
225
+ "gripper_action",
226
+ ]
227
+
228
+ def relative_to_absolute(self, action):
229
+ assert len(action) == 7
230
+ rel_pos, rel_orn, gripper = np.split(action, [3, 6])
231
+ rel_pos *= self.max_rel_pos * self.magic_scaling_factor_pos
232
+ rel_orn *= self.max_rel_orn * self.magic_scaling_factor_orn
233
+ if self.use_target_pose:
234
+ self.target_pos += rel_pos
235
+ self.target_orn += rel_orn
236
+ return self.target_pos, self.target_orn, gripper
237
+ else:
238
+ tcp_pos, tcp_orn = p.getLinkState(self.robot_uid, self.tcp_link_id, physicsClientId=self.cid)[:2]
239
+ tcp_orn = p.getEulerFromQuaternion(tcp_orn)
240
+ abs_pos = np.array(tcp_pos) + rel_pos
241
+ abs_orn = np.array(tcp_orn) + rel_orn
242
+ return abs_pos, abs_orn, gripper
243
+
244
+ def apply_action(self, action):
245
+ # cv2.imshow("win", np.zeros((300,300)))
246
+ # k = cv2.waitKey(1) % 255
247
+ # if k == ord('w'):
248
+ # self.base_position[1] += 0.01
249
+ # elif k == ord('s'):
250
+ # self.base_position[1] -= 0.01
251
+ # elif k == ord('d'):
252
+ # self.base_position[0] += 0.01
253
+ # elif k == ord('a'):
254
+ # self.base_position[0] -= 0.01
255
+ # elif k == ord('e'):
256
+ # self.base_position[2] += 0.01
257
+ # elif k == ord('q'):
258
+ # self.base_position[2] -= 0.01
259
+ # elif k == ord('r'):
260
+ # self.initial_joint_positions[0] -= 0.1
261
+ # elif k == ord('f'):
262
+ # self.initial_joint_positions[0] += 0.1
263
+ # elif k == ord('t'):
264
+ # self.initial_joint_positions[1] -= 0.1
265
+ # elif k == ord('g'):
266
+ # self.initial_joint_positions[1] += 0.1
267
+ # elif k == ord('y'):
268
+ # self.initial_joint_positions[2] -= 0.1
269
+ # elif k == ord('h'):
270
+ # self.initial_joint_positions[2] += 0.1
271
+ # elif k == ord('u'):
272
+ # self.initial_joint_positions[3] -= 0.1
273
+ # elif k == ord('j'):
274
+ # self.initial_joint_positions[3] += 0.1
275
+ # elif k == ord('i'):
276
+ # self.initial_joint_positions[4] -= 0.1
277
+ # elif k == ord('k'):
278
+ # self.initial_joint_positions[4] += 0.1
279
+ # elif k == ord('o'):
280
+ # self.initial_joint_positions[5] -= 0.1
281
+ # elif k == ord('l'):
282
+ # self.initial_joint_positions[5] += 0.1
283
+ # elif k == ord('p'):
284
+ # self.initial_joint_positions[6] -= 0.1
285
+ # elif k == ord(';'):
286
+ # self.initial_joint_positions[6] += 0.1
287
+ # elif k == ord('z'):
288
+ # self.reconfigure = not self.reconfigure
289
+ # print(f"{self.initial_joint_positions=}")
290
+ # print(f"{self.base_position=}")
291
+ # if k != 254:
292
+ # self.initial_joint_positions = np.clip(self.initial_joint_positions, self.ll_real, self.ul_real)
293
+ # p.resetBasePositionAndOrientation(self.robot_uid, self.base_position, self.base_orientation, physicsClientId=self.cid)
294
+ # self.rp = list(self.initial_joint_positions) + [self.gripper_joint_limits[1]] * 2
295
+ # self.mixed_ik.rp = self.rp
296
+ # for i, _id in enumerate(self.arm_joint_ids):
297
+ # p.resetJointState(self.robot_uid, _id, self.initial_joint_positions[i], physicsClientId=self.cid)
298
+ # p.setJointMotorControl2(
299
+ # bodyIndex=self.robot_uid,
300
+ # jointIndex=_id,
301
+ # controlMode=p.POSITION_CONTROL,
302
+ # force=self.max_joint_force,
303
+ # targetPosition=self.initial_joint_positions[i],
304
+ # maxVelocity=self.max_velocity,
305
+ # physicsClientId=self.cid,
306
+ # )
307
+ # if self.reconfigure:
308
+ # return
309
+ #
310
+
311
+ if not len(action) == 3:
312
+ action = self.relative_to_absolute(action)
313
+ target_ee_pos, target_ee_orn, self.gripper_action = action
314
+
315
+ assert len(target_ee_pos) == 3
316
+ assert len(target_ee_orn) in (3, 4)
317
+ # automatically transform euler actions to quaternion
318
+ if len(target_ee_orn) == 3:
319
+ target_ee_orn = p.getQuaternionFromEuler(target_ee_orn)
320
+
321
+ if not isinstance(self.gripper_action, int) and len(self.gripper_action) == 1:
322
+ self.gripper_action = self.gripper_action[0]
323
+ assert self.gripper_action in (-1, 1)
324
+
325
+ # #
326
+ # cam_rot = p.getMatrixFromQuaternion(target_ee_orn)
327
+ # cam_rot = np.array(cam_rot).reshape(3, 3)
328
+ # cam_rot_x, cam_rot_y, cam_rot_z = cam_rot[:, 0], cam_rot[:, 1], cam_rot[:, 2]
329
+ # p.addUserDebugLine(target_ee_pos, target_ee_pos + cam_rot_x, lineWidth=3, lineColorRGB=[1,0,0])
330
+ # p.addUserDebugLine(target_ee_pos, target_ee_pos +cam_rot_y, lineWidth=3, lineColorRGB=[0,1,0])
331
+ # p.addUserDebugLine(target_ee_pos, target_ee_pos +cam_rot_z, lineWidth=3, lineColorRGB=[0,0,1])
332
+ #
333
+ # tcp_pos, tcp_orn = p.getLinkState(self.robotId, self.tcp_link_id)[:2]
334
+ # tcp_euler = p.getEulerFromQuaternion(tcp_orn)
335
+ # p.addUserDebugLine([0,0,0], target_ee_pos, lineWidth=8, lineColorRGB=[0,1,0])
336
+ # p.addUserDebugLine([0,0,0], p.getLinkState(self.robot_uid, 6)[4], lineWidth=3, lineColorRGB=[1,0,0])
337
+ # p.addUserDebugLine([0,0,0], p.getLinkState(self.robot_uid, 13)[4], lineWidth=3, lineColorRGB=[0,1,0])
338
+ # target_ee_pos, target_ee_orn = self.tcp_to_ee(target_ee_pos, target_ee_orn)
339
+ # p.addUserDebugLine([0,0,0], target_ee_pos, lineWidth=8, lineColorRGB=[1,0,0])
340
+ jnt_ps = self.mixed_ik.get_ik(target_ee_pos, target_ee_orn)
341
+ for i in range(self.end_effector_link_id):
342
+ # p.resetJointState(self.robot_uid, i, jnt_ps[i])
343
+ p.setJointMotorControl2(
344
+ bodyIndex=self.robot_uid,
345
+ jointIndex=i,
346
+ controlMode=p.POSITION_CONTROL,
347
+ force=self.max_joint_force,
348
+ targetPosition=jnt_ps[i],
349
+ maxVelocity=self.max_velocity,
350
+ physicsClientId=self.cid,
351
+ )
352
+
353
+ self.control_gripper(self.gripper_action)
354
+
355
+ def control_gripper(self, gripper_action):
356
+ if gripper_action == 1:
357
+ gripper_finger_position = self.gripper_joint_limits[1]
358
+ gripper_force = self.gripper_force / 100
359
+ else:
360
+ gripper_finger_position = self.gripper_joint_limits[0]
361
+ gripper_force = self.gripper_force
362
+ for id in self.gripper_joint_ids:
363
+ p.setJointMotorControl2(
364
+ bodyIndex=self.robot_uid,
365
+ jointIndex=id,
366
+ controlMode=p.POSITION_CONTROL,
367
+ targetPosition=gripper_finger_position,
368
+ force=gripper_force,
369
+ maxVelocity=1,
370
+ physicsClientId=self.cid,
371
+ )
372
+
373
+ def serialize(self):
374
+ return {
375
+ "uid": self.robot_uid,
376
+ "info": p.getBodyInfo(self.robot_uid, physicsClientId=self.cid),
377
+ "pose": p.getBasePositionAndOrientation(self.robot_uid, physicsClientId=self.cid),
378
+ "joints": p.getJointStates(
379
+ self.robot_uid,
380
+ list(range(p.getNumJoints(self.robot_uid, physicsClientId=self.cid))),
381
+ physicsClientId=self.cid,
382
+ ),
383
+ "gripper_action": self.gripper_action,
384
+ }
385
+
386
+ def reset_from_storage(self, data):
387
+ p.resetBasePositionAndOrientation(
388
+ bodyUniqueId=self.robot_uid, posObj=data["pose"][0], ornObj=data["pose"][1], physicsClientId=self.cid
389
+ )
390
+ num_joints = len(data["joints"])
391
+ assert num_joints == p.getNumJoints(self.robot_uid, physicsClientId=self.cid)
392
+ for i, (value, velocity, *_) in enumerate(data["joints"]):
393
+ p.resetJointState(
394
+ bodyUniqueId=self.robot_uid,
395
+ jointIndex=i,
396
+ targetValue=value,
397
+ targetVelocity=velocity,
398
+ physicsClientId=self.cid,
399
+ )
400
+ p.setJointMotorControl2(
401
+ bodyIndex=self.robot_uid,
402
+ jointIndex=i,
403
+ controlMode=p.POSITION_CONTROL,
404
+ force=self.max_joint_force,
405
+ targetPosition=value,
406
+ maxVelocity=self.max_velocity,
407
+ physicsClientId=self.cid,
408
+ )
409
+ self.control_gripper(data["gripper_action"])
410
+
411
+ def __str__(self):
412
+ return f"{self.filename} : {self.__dict__}"
aloha_robot_project/calvin/calvin_env/calvin_env/scene/objects/base_object.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class BaseObject:
2
+ def __init__(self, name, obj_cfg, p, cid, data_path, global_scaling):
3
+ self.p = p
4
+ self.cid = cid
5
+ self.name = name
6
+ self.file = data_path / obj_cfg["file"]
7
+ self.global_scaling = global_scaling
8
+
9
+ def reset(self, state):
10
+ pass
11
+
12
+ def get_info(self):
13
+ pass
aloha_robot_project/calvin/calvin_env/calvin_env/scene/objects/button.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from enum import Enum
2
+
3
+ MAX_FORCE = 4
4
+
5
+
6
+ class ButtonState(Enum):
7
+ ON = 1
8
+ OFF = 0
9
+
10
+
11
+ class Button:
12
+ def __init__(self, name, cfg, uid, p, cid):
13
+ self.name = name
14
+ self.p = p
15
+ self.cid = cid
16
+ # get joint_index by name (to prevent index errors when additional joints are added)
17
+ joint_index = next(
18
+ i
19
+ for i in range(self.p.getNumJoints(uid, physicsClientId=self.cid))
20
+ if self.p.getJointInfo(uid, i, physicsClientId=self.cid)[1].decode("utf-8") == name
21
+ )
22
+ self.joint_index = joint_index
23
+ self.uid = uid
24
+ self.initial_state = cfg["initial_state"]
25
+ self.effect = cfg["effect"]
26
+ self.ll, self.ul = self.p.getJointInfo(uid, joint_index, physicsClientId=self.cid)[8:10]
27
+ self.trigger_threshold = (self.ll + self.ul) / 2
28
+ self.p.setJointMotorControl2(
29
+ self.uid,
30
+ self.joint_index,
31
+ controlMode=self.p.POSITION_CONTROL,
32
+ targetPosition=self.initial_state,
33
+ force=MAX_FORCE,
34
+ physicsClientId=self.cid,
35
+ )
36
+ self.state = ButtonState.OFF
37
+ self.prev_is_pressed = self._is_pressed
38
+ self.light = None
39
+
40
+ def reset(self, state=None):
41
+ _state = self.initial_state if state is None else state
42
+ self.p.resetJointState(
43
+ self.uid,
44
+ self.joint_index,
45
+ _state,
46
+ physicsClientId=self.cid,
47
+ )
48
+ self.state = ButtonState.OFF
49
+
50
+ def step(self):
51
+ if self.state == ButtonState.OFF and not self.prev_is_pressed and self._is_pressed:
52
+ self.state = ButtonState.ON
53
+ if self.light is not None:
54
+ self.light.turn_on()
55
+ elif self.state == ButtonState.ON and not self.prev_is_pressed and self._is_pressed:
56
+ self.state = ButtonState.OFF
57
+ if self.light is not None:
58
+ self.light.turn_off()
59
+ self.prev_is_pressed = self._is_pressed
60
+
61
+ @property
62
+ def _is_pressed(self):
63
+ if self.initial_state <= self.trigger_threshold:
64
+ return self.get_state() > self.trigger_threshold
65
+ elif self.initial_state > self.trigger_threshold:
66
+ return self.get_state() < self.trigger_threshold
67
+
68
+ def get_state(self):
69
+ """return button joint state"""
70
+ return float(self.p.getJointState(self.uid, self.joint_index, physicsClientId=self.cid)[0])
71
+
72
+ def get_info(self):
73
+ return {"joint_state": self.get_state(), "logical_state": self.state.value}
74
+
75
+ def add_effect(self, light):
76
+ self.light = light
aloha_robot_project/calvin/calvin_env/calvin_env/scene/objects/door.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MAX_FORCE = 4
2
+
3
+
4
+ class Door:
5
+ def __init__(self, name, cfg, uid, p, cid):
6
+ self.name = name
7
+ self.p = p
8
+ self.cid = cid
9
+ # get joint_index by name (to prevent index errors when additional joints are added)
10
+ joint_index = next(
11
+ i
12
+ for i in range(self.p.getNumJoints(uid, physicsClientId=self.cid))
13
+ if self.p.getJointInfo(uid, i, physicsClientId=self.cid)[1].decode("utf-8") == name
14
+ )
15
+ self.joint_index = joint_index
16
+ self.uid = uid
17
+ self.initial_state = cfg["initial_state"]
18
+ self.p.setJointMotorControl2(
19
+ self.uid,
20
+ self.joint_index,
21
+ controlMode=p.VELOCITY_CONTROL,
22
+ force=MAX_FORCE,
23
+ physicsClientId=self.cid,
24
+ )
25
+
26
+ def reset(self, state=None):
27
+ _state = self.initial_state if state is None else state
28
+ self.p.resetJointState(
29
+ self.uid,
30
+ self.joint_index,
31
+ _state,
32
+ physicsClientId=self.cid,
33
+ )
34
+
35
+ def get_state(self):
36
+ joint_state = self.p.getJointState(self.uid, self.joint_index, physicsClientId=self.cid)
37
+ return float(joint_state[0])
38
+
39
+ def get_info(self):
40
+ return {"current_state": self.get_state()}
aloha_robot_project/calvin/calvin_env/calvin_env/scene/objects/fixed_object.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from calvin_env.scene.objects.base_object import BaseObject
2
+
3
+
4
+ class FixedObject(BaseObject):
5
+ def __init__(self, name, obj_cfg, p, cid, data_path, global_scaling):
6
+ super().__init__(name, obj_cfg, p, cid, data_path, global_scaling)
7
+ self.initial_pos = obj_cfg["initial_pos"]
8
+ self.initial_orn = self.p.getQuaternionFromEuler(obj_cfg["initial_orn"])
9
+
10
+ self.uid = self.p.loadURDF(
11
+ self.file.as_posix(),
12
+ self.initial_pos,
13
+ self.initial_orn,
14
+ globalScaling=global_scaling,
15
+ physicsClientId=self.cid,
16
+ )
17
+ self.info_dict = {"uid": self.uid}
18
+ self.num_joints = self.p.getNumJoints(self.uid, physicsClientId=self.cid)
19
+ if self.num_joints > 0:
20
+ # save link names and ids in dictionary
21
+ links = {
22
+ self.p.getJointInfo(self.uid, i, physicsClientId=self.cid)[12].decode("utf-8"): i
23
+ for i in range(self.num_joints)
24
+ }
25
+ links["base_link"] = -1
26
+ self.info_dict["links"] = links
27
+
28
+ def reset(self, state=None):
29
+ pass
30
+
31
+ def get_info(self):
32
+ obj_info = {**self.info_dict, "contacts": self.p.getContactPoints(bodyA=self.uid, physicsClientId=self.cid)}
33
+ return obj_info
34
+
35
+ def serialize(self):
36
+ joints = (
37
+ self.p.getJointStates(self.uid, list(range(self.num_joints)), physicsClientId=self.cid)
38
+ if self.num_joints > 0
39
+ else ()
40
+ )
41
+ return {"uid": self.uid, "info": self.p.getBodyInfo(self.uid, physicsClientId=self.cid), "joints": joints}
aloha_robot_project/calvin/calvin_env/calvin_env/scene/objects/light.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from enum import Enum
2
+
3
+
4
+ class LightState(Enum):
5
+ ON = 1
6
+ OFF = 0
7
+
8
+
9
+ class Light:
10
+ def __init__(self, name, cfg, uid, p, cid):
11
+ self.name = name
12
+ self.uid = uid
13
+ self.p = p
14
+ self.cid = cid
15
+ self.link = cfg["link"]
16
+ self.link_id = next(
17
+ i
18
+ for i in range(self.p.getNumJoints(uid, physicsClientId=self.cid))
19
+ if self.p.getJointInfo(uid, i, physicsClientId=self.cid)[12].decode("utf-8") == self.link
20
+ )
21
+ self.color_on = cfg["color"]
22
+ self.color_off = [1, 1, 1, 1]
23
+ self.state = LightState.OFF
24
+
25
+ def reset(self, state=None):
26
+ if state is None:
27
+ self.turn_off()
28
+ else:
29
+ if state == LightState.ON.value:
30
+ self.turn_on()
31
+ elif state == LightState.OFF.value:
32
+ self.turn_off()
33
+ else:
34
+ print("Light state can be only 0 or 1.")
35
+ raise ValueError
36
+
37
+ def get_state(self):
38
+ return self.state.value
39
+
40
+ def get_info(self):
41
+ return {"logical_state": self.get_state()}
42
+
43
+ def turn_on(self):
44
+ self.state = LightState.ON
45
+ self.p.changeVisualShape(self.uid, self.link_id, rgbaColor=self.color_on, physicsClientId=self.cid)
46
+
47
+ def turn_off(self):
48
+ self.state = LightState.OFF
49
+ self.p.changeVisualShape(self.uid, self.link_id, rgbaColor=self.color_off, physicsClientId=self.cid)
50
+
51
+ def serialize(self):
52
+ return self.get_info()
aloha_robot_project/calvin/calvin_env/calvin_env/scene/objects/movable_object.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+
3
+ import numpy as np
4
+ from omegaconf.errors import ConfigKeyError
5
+
6
+ from calvin_env.scene.objects.base_object import BaseObject
7
+
8
+ log = logging.getLogger(__name__)
9
+
10
+
11
+ class MovableObject(BaseObject):
12
+ def __init__(self, name, obj_cfg, p, cid, data_path, global_scaling, euler_obs, surfaces, np_random):
13
+ super().__init__(name, obj_cfg, p, cid, data_path, global_scaling)
14
+ self.initial_pos = obj_cfg["initial_pos"]
15
+ self.initial_orn = obj_cfg["initial_orn"]
16
+ if isinstance(self.initial_pos, list):
17
+ self.initial_pos = np.array(self.initial_pos)
18
+ if isinstance(self.initial_orn, list):
19
+ self.initial_orn = np.array(p.getQuaternionFromEuler(self.initial_orn))
20
+ self.euler_obs = euler_obs
21
+ self.surfaces = surfaces
22
+ self.np_random = np_random
23
+
24
+ initial_pos, initial_orn = self.sample_initial_pose()
25
+ self.uid = self.p.loadURDF(
26
+ self.file.as_posix(),
27
+ initial_pos,
28
+ initial_orn,
29
+ globalScaling=global_scaling,
30
+ physicsClientId=self.cid,
31
+ )
32
+
33
+ def reset(self, state=None):
34
+ if state is None:
35
+ initial_pos, initial_orn = self.sample_initial_pose()
36
+ else:
37
+ initial_pos, initial_orn = np.split(state, [3])
38
+ if len(initial_orn) == 3:
39
+ initial_orn = self.p.getQuaternionFromEuler(initial_orn)
40
+ self.p.resetBasePositionAndOrientation(
41
+ self.uid,
42
+ initial_pos,
43
+ initial_orn,
44
+ physicsClientId=self.cid,
45
+ )
46
+
47
+ def sample_initial_pose(self):
48
+ initial_pos = self.initial_pos
49
+ if isinstance(self.initial_pos, str):
50
+ if self.initial_pos == "any":
51
+ surface = self.np_random.choice(list(self.surfaces.keys()))
52
+ sampling_range = np.array(self.surfaces[surface])
53
+ else:
54
+ try:
55
+ sampling_range = np.array(self.surfaces[self.initial_pos])
56
+ except ConfigKeyError:
57
+ log.error(f"surface {self.initial_pos} not specified in scene config")
58
+ raise KeyError
59
+ initial_pos = self.np_random.uniform(sampling_range[0], sampling_range[1])
60
+ initial_orn = self.initial_orn
61
+ if isinstance(self.initial_orn, str):
62
+ if self.initial_orn == "any":
63
+ initial_orn = np.array(
64
+ self.p.getQuaternionFromEuler(self.np_random.uniform([0, 0, -np.pi], [0, 0, np.pi]))
65
+ )
66
+ else:
67
+ log.error("Only keyword 'any' supported at the moment")
68
+ raise ValueError
69
+ return initial_pos, initial_orn
70
+
71
+ def get_state(self):
72
+ pos, orn = self.p.getBasePositionAndOrientation(self.uid, physicsClientId=self.cid)
73
+ if self.euler_obs:
74
+ orn = self.p.getEulerFromQuaternion(orn)
75
+ return np.concatenate([pos, orn])
76
+
77
+ def get_info(self):
78
+ pos, orn = self.p.getBasePositionAndOrientation(self.uid, physicsClientId=self.cid)
79
+ lin_vel, ang_vel = self.p.getBaseVelocity(self.uid, physicsClientId=self.cid)
80
+ obj_info = {
81
+ "current_pos": pos,
82
+ "current_orn": orn,
83
+ "current_lin_vel": lin_vel,
84
+ "current_ang_vel": ang_vel,
85
+ "contacts": self.p.getContactPoints(bodyA=self.uid, physicsClientId=self.cid),
86
+ "uid": self.uid,
87
+ }
88
+ return obj_info
89
+
90
+ def serialize(self):
91
+ return {
92
+ "uid": self.uid,
93
+ "info": self.p.getBodyInfo(self.uid, physicsClientId=self.cid),
94
+ "pose": self.p.getBasePositionAndOrientation(self.uid, physicsClientId=self.cid),
95
+ }
aloha_robot_project/calvin/calvin_env/calvin_env/scene/objects/switch.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from enum import Enum
2
+
3
+ MAX_FORCE = 4
4
+
5
+
6
+ class ButtonState(Enum):
7
+ ON = 1
8
+ OFF = 0
9
+
10
+
11
+ class Switch:
12
+ def __init__(self, name, cfg, uid, p, cid):
13
+ self.name = name
14
+ self.p = p
15
+ self.cid = cid
16
+ # get joint_index by name (to prevent index errors when additional joints are added)
17
+ joint_index = next(
18
+ i
19
+ for i in range(self.p.getNumJoints(uid, physicsClientId=self.cid))
20
+ if self.p.getJointInfo(uid, i, physicsClientId=self.cid)[1].decode("utf-8") == name
21
+ )
22
+ self.joint_index = joint_index
23
+ self.uid = uid
24
+ self.initial_state = cfg["initial_state"]
25
+ self.effect = cfg["effect"]
26
+ self.ll, self.ul = self.p.getJointInfo(uid, joint_index, physicsClientId=self.cid)[8:10]
27
+ self.trigger_threshold = (self.ll + self.ul) / 2
28
+ self.p.setJointMotorControl2(
29
+ self.uid,
30
+ self.joint_index,
31
+ controlMode=p.VELOCITY_CONTROL,
32
+ force=MAX_FORCE,
33
+ physicsClientId=self.cid,
34
+ )
35
+ self.state = ButtonState.OFF
36
+ self.light = None
37
+
38
+ def reset(self, state=None):
39
+ _state = self.initial_state if state is None else state
40
+ self.p.resetJointState(
41
+ self.uid,
42
+ self.joint_index,
43
+ _state,
44
+ physicsClientId=self.cid,
45
+ )
46
+ self.state = ButtonState.OFF
47
+
48
+ def step(self):
49
+ if self.is_pressed:
50
+ if self.light is not None and self.state == ButtonState.OFF:
51
+ self.light.turn_on()
52
+ self.state = ButtonState.ON
53
+ else:
54
+ if self.light is not None and self.state == ButtonState.ON:
55
+ self.light.turn_off()
56
+ self.state = ButtonState.OFF
57
+
58
+ @property
59
+ def is_pressed(self):
60
+ if self.initial_state <= self.trigger_threshold:
61
+ return self.get_state() > self.trigger_threshold
62
+ elif self.initial_state > self.trigger_threshold:
63
+ return self.get_state() < self.trigger_threshold
64
+
65
+ def get_state(self):
66
+ """return button joint state"""
67
+ return float(self.p.getJointState(self.uid, self.joint_index, physicsClientId=self.cid)[0])
68
+
69
+ def get_info(self):
70
+ return {"joint_state": self.get_state(), "logical_state": self.state.value}
71
+
72
+ def add_effect(self, light):
73
+ self.light = light
aloha_robot_project/calvin/calvin_env/calvin_env/scene/play_table_scene.py ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import itertools
2
+ import logging
3
+ import os
4
+ from pathlib import Path
5
+
6
+ import numpy as np
7
+
8
+ # A logger for this file
9
+ from omegaconf import OmegaConf
10
+
11
+ from calvin_env.scene.objects.button import Button
12
+ from calvin_env.scene.objects.door import Door
13
+ from calvin_env.scene.objects.fixed_object import FixedObject
14
+ from calvin_env.scene.objects.light import Light
15
+ from calvin_env.scene.objects.movable_object import MovableObject
16
+ from calvin_env.scene.objects.switch import Switch
17
+
18
+ log = logging.getLogger(__name__)
19
+
20
+
21
+ REPO_BASE = Path(__file__).parents[2]
22
+
23
+
24
+ class PlayTableScene:
25
+ def __init__(self, objects, data_path, euler_obs, p, cid, global_scaling, surfaces, np_random, **kwargs):
26
+ self.p = p
27
+ self.cid = cid
28
+ self.global_scaling = global_scaling
29
+ self.euler_obs = euler_obs
30
+ self.surfaces = surfaces
31
+ self.np_random = np_random
32
+ if os.path.isabs(data_path):
33
+ self.data_path = Path(data_path)
34
+ else:
35
+ self.data_path = REPO_BASE / data_path
36
+ self.p.setAdditionalSearchPath(self.data_path.as_posix())
37
+ self.object_cfg = OmegaConf.to_container(objects)
38
+ self.fixed_objects, self.movable_objects = [], []
39
+ self.doors, self.buttons, self.switches, self.lights = [], [], [], []
40
+
41
+ def load(self):
42
+ self.fixed_objects, self.movable_objects = [], []
43
+ self.doors, self.buttons, self.switches, self.lights = [], [], [], []
44
+
45
+ for name, obj_cfg in self.object_cfg.get("movable_objects", {}).items():
46
+ self.movable_objects.append(
47
+ MovableObject(
48
+ name,
49
+ obj_cfg,
50
+ self.p,
51
+ self.cid,
52
+ self.data_path,
53
+ self.global_scaling,
54
+ self.euler_obs,
55
+ self.surfaces,
56
+ self.np_random,
57
+ )
58
+ )
59
+
60
+ for name, obj_cfg in self.object_cfg.get("fixed_objects", {}).items():
61
+ fixed_obj = FixedObject(name, obj_cfg, self.p, self.cid, self.data_path, self.global_scaling)
62
+
63
+ if "joints" in obj_cfg:
64
+ for joint_name, cfg in obj_cfg["joints"].items():
65
+ door = Door(joint_name, cfg, fixed_obj.uid, self.p, self.cid)
66
+ self.doors.append(door)
67
+ self.fixed_objects.append(fixed_obj)
68
+
69
+ if "buttons" in obj_cfg:
70
+ for button_name, cfg in obj_cfg["buttons"].items():
71
+ button = Button(button_name, cfg, fixed_obj.uid, self.p, self.cid)
72
+ self.buttons.append(button)
73
+
74
+ if "switches" in obj_cfg:
75
+ for switch_name, cfg in obj_cfg["switches"].items():
76
+ switch = Switch(switch_name, cfg, fixed_obj.uid, self.p, self.cid)
77
+ self.switches.append(switch)
78
+
79
+ if "lights" in obj_cfg:
80
+ for light_name, cfg in obj_cfg["lights"].items():
81
+ light = Light(light_name, cfg, fixed_obj.uid, self.p, self.cid)
82
+ self.lights.append(light)
83
+
84
+ for light in self.lights:
85
+ for button_switch in itertools.chain(self.buttons, self.switches):
86
+ if button_switch.effect == light.name:
87
+ button_switch.add_effect(light)
88
+
89
+ self.p.loadURDF(os.path.join(self.data_path, "plane/plane.urdf"), physicsClientId=self.cid)
90
+
91
+ def reset(self, scene_obs=None):
92
+ """Reset objects and doors to initial position."""
93
+ if scene_obs is None:
94
+ for obj in itertools.chain(self.doors, self.buttons, self.switches, self.lights):
95
+ obj.reset()
96
+ self.reset_movable_objects()
97
+ else:
98
+ door_info, button_info, switch_info, light_info, obj_info = self.parse_scene_obs(scene_obs)
99
+
100
+ for door, state in zip(self.doors, door_info):
101
+ door.reset(state)
102
+ for button, state in zip(self.buttons, button_info):
103
+ button.reset(state)
104
+ for switch, state in zip(self.switches, switch_info):
105
+ switch.reset(state)
106
+ for light, state in zip(self.lights, light_info):
107
+ light.reset(state)
108
+ for obj, state in zip(self.movable_objects, obj_info):
109
+ obj.reset(state)
110
+
111
+ def parse_scene_obs(self, scene_obs):
112
+ # an object pose is composed of position (3) and orientation (4 for quaternion) / (3 for euler)
113
+ n_obj = len(self.movable_objects)
114
+ n_doors = len(self.doors)
115
+ n_buttons = len(self.buttons)
116
+ n_switches = len(self.switches)
117
+ n_lights = len(self.lights)
118
+
119
+ split_ids = np.cumsum([n_doors, n_buttons, n_switches, n_lights])
120
+ door_info, button_info, switch_info, light_info, obj_info = np.split(scene_obs, split_ids)
121
+ assert len(door_info) == n_doors
122
+ assert len(button_info) == n_buttons
123
+ assert len(switch_info) == n_switches
124
+ assert len(light_info) == n_lights
125
+ assert len(obj_info) // n_obj in [6, 7] # depending on euler angles or quaternions
126
+
127
+ obj_info = np.split(obj_info, n_obj)
128
+
129
+ return door_info, button_info, switch_info, light_info, obj_info
130
+
131
+ def reset_movable_objects(self):
132
+ """reset movable objects such that there are no pairwise contacts"""
133
+ num_sampling_iterations = 1000
134
+ for i in range(num_sampling_iterations):
135
+ for obj in self.movable_objects:
136
+ obj.reset()
137
+ self.p.stepSimulation()
138
+ contact = False
139
+ for obj_a, obj_b in itertools.combinations(self.movable_objects, 2):
140
+ if np.any(len(self.p.getContactPoints(bodyA=obj_a.uid, bodyB=obj_b.uid, physicsClientId=self.cid))):
141
+ contact = True
142
+ break
143
+ if not contact:
144
+ return
145
+ log.error(f"Could not place objects in {num_sampling_iterations} iterations without contacts")
146
+ return
147
+
148
+ def step(self):
149
+ for button_switch in itertools.chain(self.buttons, self.switches):
150
+ button_switch.step()
151
+
152
+ def get_obs(self):
153
+ """Return state information of the doors, drawers and shelves."""
154
+ door_states = [door.get_state() for door in self.doors]
155
+ button_states = [button.get_state() for button in self.buttons]
156
+ switch_states = [switch.get_state() for switch in self.switches]
157
+ light_states = [light.get_state() for light in self.lights]
158
+ object_poses = list(itertools.chain(*[obj.get_state() for obj in self.movable_objects]))
159
+
160
+ return np.concatenate([door_states, button_states, switch_states, light_states, object_poses])
161
+
162
+ def get_info(self):
163
+ """
164
+ get dictionary of information about the objects in the scene
165
+ self.objects:
166
+ obj1:
167
+ joints:
168
+ joint1:
169
+ joint_index: int
170
+ initial_state: float # revolute
171
+ current_state: float
172
+ ...
173
+ current_pos: [x, y, z]
174
+ current_orn: [x, y, z, w] # quaternion
175
+ contacts: output of pybullet getContactPoints(...)
176
+ links: # key exists only if object has num_joints > 0
177
+ link1: link_id # name: id
178
+ ...
179
+ """
180
+ info = {}
181
+ info["fixed_objects"] = {}
182
+ info["movable_objects"] = {}
183
+ info["doors"] = {}
184
+ info["buttons"] = {}
185
+ info["switches"] = {}
186
+ info["lights"] = {}
187
+
188
+ for obj in self.fixed_objects:
189
+ info["fixed_objects"][obj.name] = obj.get_info()
190
+ for obj in self.movable_objects:
191
+ info["movable_objects"][obj.name] = obj.get_info()
192
+ for obj in self.doors:
193
+ info["doors"][obj.name] = obj.get_info()
194
+ for obj in self.buttons:
195
+ info["buttons"][obj.name] = obj.get_info()
196
+ for obj in self.switches:
197
+ info["switches"][obj.name] = obj.get_info()
198
+ for obj in self.lights:
199
+ info["lights"][obj.name] = obj.get_info()
200
+ return info
201
+
202
+ def get_scene_obs_labels(self):
203
+ raise NotImplementedError
204
+
205
+ def get_objects(self):
206
+ return itertools.chain(self.fixed_objects, self.movable_objects)
207
+
208
+ def serialize(self):
209
+ data = {
210
+ "fixed_objects": [obj.serialize() for obj in self.fixed_objects],
211
+ "movable_objects": [obj.serialize() for obj in self.movable_objects],
212
+ "lights": [obj.serialize() for obj in self.lights],
213
+ }
214
+ return data
215
+
216
+ def reset_from_storage(self, data):
217
+ for fixed_obj in data["fixed_objects"]:
218
+ for i, (value, velocity, *_) in enumerate(fixed_obj["joints"]):
219
+ self.p.resetJointState(
220
+ bodyUniqueId=fixed_obj["uid"],
221
+ jointIndex=i,
222
+ targetValue=value,
223
+ targetVelocity=velocity,
224
+ physicsClientId=self.cid,
225
+ )
226
+ for movable_obj in data["movable_objects"]:
227
+ self.p.resetBasePositionAndOrientation(
228
+ bodyUniqueId=movable_obj["uid"],
229
+ posObj=movable_obj["pose"][0],
230
+ ornObj=movable_obj["pose"][1],
231
+ physicsClientId=self.cid,
232
+ )
233
+ for light, state in zip(self.lights, data["lights"]):
234
+ light.reset(state["logical_state"])
aloha_robot_project/calvin/calvin_env/calvin_env/scripts/check_tasks.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+
3
+ import cv2
4
+ import hydra
5
+ import numpy as np
6
+ import pybullet as p
7
+
8
+ """
9
+ This script loads a rendered episode and replays it using the recorded actions.
10
+ Optionally, gaussian noise can be added to the actions.
11
+ """
12
+
13
+
14
+ def scale_depth(img):
15
+ img = np.clip(img, 0, 1.5)
16
+ img -= img.min()
17
+ img /= img.max()
18
+ return img
19
+
20
+
21
+ def noise(action, pos_std=0.01, rot_std=1):
22
+ """
23
+ adds gaussian noise to position and orientation.
24
+ units are m for pos and degree for rot
25
+ """
26
+ pos, orn, gripper = action
27
+ rot_std = np.radians(rot_std)
28
+ pos_noise = np.random.normal(0, pos_std, 3)
29
+ rot_noise = p.getQuaternionFromEuler(np.random.normal(0, rot_std, 3))
30
+ pos, orn = p.multiplyTransforms(pos, orn, pos_noise, rot_noise)
31
+ return pos, orn, gripper
32
+
33
+
34
+ @hydra.main(config_path="../../conf", config_name="config_data_collection")
35
+ def run_env(cfg):
36
+ env = hydra.utils.instantiate(cfg.env, show_gui=True, use_vr=False, use_scene_info=True)
37
+
38
+ root_dir = Path(__file__).parents[3] / "dataset/task_D_D/training"
39
+
40
+ ep_start_end_ids = np.sort(np.load(root_dir / "ep_start_end_ids.npy"), axis=0)
41
+
42
+ seq_len = 32
43
+ tasks = hydra.utils.instantiate(cfg.tasks)
44
+ for s, e in ep_start_end_ids:
45
+ i = s
46
+ while 1:
47
+
48
+ file = root_dir / f"episode_{i:07}.npz"
49
+ data = np.load(file)
50
+ # gripper_img = data["rgb_gripper"]
51
+ # cv2.imshow("gripper", gripper_img[:, :, ::-1])
52
+ # static_img = data["rgb_static"]
53
+ # cv2.imshow("static", static_img[:, :, ::-1])
54
+ # print(data["robot_obs"])
55
+ # env.render()
56
+ env.reset(scene_obs=data["scene_obs"], robot_obs=data["robot_obs"])
57
+ start_info = env.get_info()
58
+ cv2.imshow("keylistener", np.zeros((300, 300)))
59
+ k = cv2.waitKey(0) % 256
60
+ if k == ord("a"):
61
+ i -= 1
62
+ i = np.clip(i, s, e - seq_len)
63
+ if k == ord("d"):
64
+ i += 1
65
+ i = np.clip(i, s, e - seq_len)
66
+ if k == ord("q"):
67
+ i -= 100
68
+ i = np.clip(i, s, e - seq_len)
69
+ if k == ord("z"):
70
+ i -= seq_len
71
+ i = np.clip(i, s, e - seq_len)
72
+ if k == ord("e"):
73
+ i += 100
74
+ i = np.clip(i, s, e - seq_len)
75
+ if k == ord("r"):
76
+ for j in range(i + 1, i + seq_len):
77
+ file = root_dir / f"episode_{j:07d}.npz"
78
+ data = np.load(file)
79
+ env.reset(scene_obs=data["scene_obs"], robot_obs=data["robot_obs"])
80
+ gripper_img = data["rgb_gripper"]
81
+ cv2.imshow("gripper", gripper_img[:, :, ::-1])
82
+ static_img = data["rgb_static"]
83
+ cv2.imshow("static", static_img[:, :, ::-1])
84
+ cv2.waitKey(100)
85
+ end_info = env.get_info()
86
+ task_info = tasks.get_task_info(start_info, end_info)
87
+ if len(task_info):
88
+ print()
89
+ print()
90
+ print()
91
+ print(task_info)
92
+ else:
93
+ print()
94
+ print()
95
+ print()
96
+ print("No task detected.")
97
+ i = j
98
+ if k == ord("n"): # ESC
99
+ break
100
+
101
+
102
+ if __name__ == "__main__":
103
+ run_env()
aloha_robot_project/calvin/calvin_env/calvin_env/scripts/convert_gripper_actions.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ import sys
3
+
4
+ import numpy as np
5
+ from tqdm import tqdm
6
+
7
+ path = Path(sys.argv[-1])
8
+
9
+ for subdir in ["training", "validation"]:
10
+ for file in tqdm((path / subdir).glob("*.npz")):
11
+ data = np.load(file)
12
+ if data["rel_actions"][-1] == 0:
13
+ data = dict(data)
14
+ data["rel_actions"][-1] = -1
15
+ data["actions"][-1] = -1
16
+ np.savez(file, **data)
aloha_robot_project/calvin/calvin_env/calvin_env/scripts/dataset_to_euler.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ from shutil import copyfile, copytree
3
+
4
+ import numpy as np
5
+ import pybullet as p
6
+ from tqdm import tqdm
7
+
8
+ load_path = Path("/home/hermannl/phd/data/banana_dataset_01_29/validation")
9
+
10
+ save_path = Path("/home/hermannl/phd/data/banana_dataset_01_29_euler/validation")
11
+ save_path.mkdir(parents=True, exist_ok=True)
12
+
13
+ for file in tqdm(load_path.glob("*.npz")):
14
+ data = np.load(file)
15
+ robot_obs = data["robot_obs"]
16
+ robot_obs_euler = np.concatenate([robot_obs[:3], p.getEulerFromQuaternion(robot_obs[3:7]), robot_obs[7:]])
17
+ scene_obs = data["scene_obs"]
18
+ scene_obs_euler = scene_obs[:3]
19
+ for i in range(6):
20
+ scene_obs_euler = np.append(scene_obs_euler, scene_obs[3 + i * 7 : 3 + i * 7 + 3])
21
+ scene_obs_euler = np.append(scene_obs_euler, p.getEulerFromQuaternion(scene_obs[3 + i * 7 + 3 : 3 + i * 7 + 7]))
22
+ actions = data["actions"]
23
+ actions_euler = np.concatenate([actions[:3], p.getEulerFromQuaternion(actions[3:7]), actions[7:]])
24
+ data_euler = dict(data.items())
25
+ data_euler["robot_obs"] = robot_obs_euler
26
+ data_euler["scene_obs"] = scene_obs_euler
27
+ data_euler["actions"] = actions_euler
28
+ np.savez(save_path / file.name, **data_euler)
29
+
30
+ for file in set(load_path.glob("*")) - set(load_path.glob("*.npz")):
31
+ if file.is_dir():
32
+ copytree(file, save_path / file.name)
33
+ else:
34
+ copyfile(file, save_path / file.name)
aloha_robot_project/calvin/calvin_env/calvin_env/scripts/record_video_icra.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from copy import deepcopy
2
+ from pathlib import Path
3
+ import time
4
+
5
+ import cv2
6
+ import hydra
7
+ import matplotlib.pyplot as plt
8
+ import numpy as np
9
+ import pybullet as p
10
+
11
+ from calvin_env.utils import utils
12
+
13
+ """
14
+ This script loads a rendered episode and replays it using the recorded actions.
15
+ Optionally, gaussian noise can be added to the actions.
16
+ """
17
+
18
+
19
+ def noise(action, pos_std=0.01, rot_std=1):
20
+ """
21
+ adds gaussian noise to position and orientation.
22
+ units are m for pos and degree for rot
23
+ """
24
+ pos, orn, gripper = action
25
+ rot_std = np.radians(rot_std)
26
+ pos_noise = np.random.normal(0, pos_std, 3)
27
+ rot_noise = p.getQuaternionFromEuler(np.random.normal(0, rot_std, 3))
28
+ pos, orn = p.multiplyTransforms(pos, orn, pos_noise, rot_noise)
29
+ return pos, orn, gripper
30
+
31
+
32
+ def depth2rgb(img, minval=0, maxval=1):
33
+ img -= minval
34
+ img /= maxval - minval
35
+ img *= 255
36
+ img = np.clip(img, 0.0, 255.0)
37
+ img = img.astype(np.uint8)
38
+ img = np.tile(np.expand_dims(img, axis=2), 3)
39
+ return img
40
+
41
+
42
+ @hydra.main(config_path="../../conf", config_name="config_data_collection")
43
+ def run_env(cfg):
44
+ env = hydra.utils.instantiate(cfg.env, show_gui=False, use_vr=False, use_scene_info=True)
45
+
46
+ root_dir = Path("/home/hermannl/data/calvin_abcd_example")
47
+
48
+ ep_start_end_ids = [[100000, 104999]]
49
+ rel_actions = []
50
+ tasks = hydra.utils.instantiate(cfg.tasks)
51
+ prev_info = None
52
+ t1 = time.time()
53
+
54
+ video = cv2.VideoWriter(
55
+ "/home/hermannl/Documents/calvin/env_A_tactile.avi", cv2.VideoWriter_fourcc(*"XVID"), 30, (240, 160)
56
+ )
57
+ video_static = cv2.VideoWriter(
58
+ "/home/hermannl/Documents/calvin/env_A_static_depth.avi", cv2.VideoWriter_fourcc(*"XVID"), 30, (200, 200)
59
+ )
60
+ video_gripper = cv2.VideoWriter(
61
+ "/home/hermannl/Documents/calvin/env_A_gripper_depth.avi", cv2.VideoWriter_fourcc(*"XVID"), 30, (100, 100)
62
+ )
63
+ for s, e in ep_start_end_ids:
64
+ print("new_episode")
65
+ for i in range(s, e + 1):
66
+ file = root_dir / f"episode_{i:07d}.npz"
67
+ data = np.load(file)
68
+ # img = data["rgb_static"]
69
+ # cv2.imshow("win2", cv2.resize(img[:, :, ::-1], (500, 500)))
70
+ # cv2.waitKey(0)
71
+
72
+ # if (i - s) % 32 == 0:
73
+ # print(f"reset {i}")
74
+ obs = env.reset(scene_obs=data["scene_obs"], robot_obs=data["robot_obs"])
75
+
76
+ im = obs["rgb_obs"][0]
77
+ im = np.concatenate([im[:, :, :3], im[:, :, 3:6]], axis=1)
78
+ cv2.imshow("im", im)
79
+ cv2.waitKey(1)
80
+ video.write(im[:, :, ::-1])
81
+ video_gripper.write(depth2rgb(obs["depth_obs"][1], minval=0.1, maxval=0.5)[:, :, ::-1])
82
+ video_static.write(depth2rgb(obs["depth_obs"][0], minval=3.5, maxval=5)[:, :, ::-1])
83
+ # action = data["rel_actions"]
84
+ action = np.split(data["actions"], [3, 6])
85
+ action = noise(action)
86
+
87
+ rel_actions.append(utils.to_relative_action(data["actions"], data["robot_obs"][:6]))
88
+ # action = utils.to_relative_action(data["actions"], data["robot_obs"], max_pos=0.04, max_orn=0.1)
89
+ # tcp_pos, tcp_orn = p.getLinkState(env.robot.robot_uid, env.robot.tcp_link_id, physicsClientId=env.cid)[:2]
90
+ # tcp_orn = p.getEulerFromQuaternion(tcp_orn)
91
+ # action2 = utils.to_relative_action(data["actions"], np.concatenate([tcp_pos, tcp_orn]))
92
+ o, _, _, info = env.step(action)
93
+ print(info["scene_info"]["lights"]["led"]["logical_state"])
94
+ if (i - s) % 32 != 0:
95
+ print(tasks.get_task_info(prev_info, info))
96
+ else:
97
+ prev_info = deepcopy(info)
98
+ time.sleep(0.01)
99
+ video.release()
100
+ video_static.release()
101
+ video_gripper.release()
102
+ print(time.time() - t1)
103
+ rel_actions = np.array(rel_actions)
104
+ for j in range(rel_actions.shape[1]):
105
+ plt.figure(j)
106
+ plt.hist(rel_actions[:, j], bins=10)
107
+ plt.plot()
108
+ plt.show()
109
+
110
+
111
+ if __name__ == "__main__":
112
+ run_env()
aloha_robot_project/calvin/calvin_env/calvin_env/scripts/render_low_freq.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import itertools
3
+ import os
4
+ from pathlib import Path
5
+ import shutil
6
+ import sys
7
+
8
+ import numpy as np
9
+ from omegaconf import OmegaConf
10
+ from tqdm import tqdm
11
+
12
+ from calvin_env.utils import utils
13
+
14
+
15
+ def pairwise(iterable):
16
+ "s -> (s0,s1), (s1,s2), (s2, s3), ..."
17
+ a, b = itertools.tee(iterable)
18
+ next(b, None)
19
+ return zip(a, b)
20
+
21
+
22
+ parser = argparse.ArgumentParser(description="convert dataset to 15 hz (leave one step out)")
23
+ parser.add_argument("src", type=str)
24
+ parser.add_argument("dest", type=str)
25
+ parser.add_argument("--max_rel_pos", type=float, default=0.04)
26
+ parser.add_argument("--max_rel_orn", type=float, default=0.1)
27
+ args = parser.parse_args()
28
+ src_path = Path(args.src)
29
+ dest_path = Path(args.dest)
30
+
31
+ os.mkdir(dest_path)
32
+ os.mkdir(dest_path / "training")
33
+ os.mkdir(dest_path / "validation")
34
+
35
+ new_i = 0
36
+
37
+ for subdir in ["training", "validation"]:
38
+ ep_lens = np.load(src_path / subdir / "ep_lens.npy")
39
+ ep_start_end_ids = np.load(src_path / subdir / "ep_start_end_ids.npy")
40
+
41
+ new_ep_lens = []
42
+ new_ep_start_end_ids = []
43
+
44
+ for start, end in tqdm(ep_start_end_ids):
45
+
46
+ ep_len = end - start + 1
47
+ for offset in (0, 1):
48
+ new_start = new_i
49
+ for old_i in range(start + offset, end + 1, 2):
50
+ old_data = np.load(src_path / subdir / f"episode_{old_i:06d}.npz")
51
+ data = dict(old_data)
52
+ if old_i < end:
53
+ next_old_data = np.load(src_path / subdir / f"episode_{old_i + 1:06d}.npz")
54
+ next_data = dict(next_old_data)
55
+ data["actions"] = next_data["actions"]
56
+ data["rel_actions"] = utils.to_relative_action(
57
+ data["actions"], data["robot_obs"], max_pos=args.max_rel_pos, max_orn=args.max_rel_orn
58
+ )
59
+ np.savez(dest_path / subdir / f"episode_{new_i:06d}.npz", **data)
60
+ new_i += 1
61
+ new_end = new_i - 1
62
+ new_ep_len = new_end - new_start + 1
63
+ new_ep_start_end_ids.append((new_start, new_end))
64
+ new_ep_lens.append(new_ep_len)
65
+ np.save(dest_path / subdir / "ep_lens.npy", new_ep_lens)
66
+ np.save(dest_path / subdir / "ep_start_end_ids.npy", new_ep_start_end_ids)
67
+ shutil.copy(src_path / subdir / "statistics.yaml", dest_path / subdir)
68
+ os.makedirs(dest_path / subdir / ".hydra")
69
+ shutil.copytree(src_path / subdir / ".hydra", dest_path / subdir / ".hydra", dirs_exist_ok=True)
70
+ cfg = OmegaConf.load(dest_path / subdir / ".hydra/merged_config.yaml")
71
+ cfg.robot.max_rel_pos = args.max_rel_pos
72
+ cfg.robot.max_rel_orn = args.max_rel_orn
73
+ cfg.env.control_freq = 15
74
+ OmegaConf.save(cfg, dest_path / subdir / ".hydra/merged_config.yaml")
aloha_robot_project/calvin/calvin_env/calvin_env/scripts/reset_env_rendered_episode.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from copy import deepcopy
2
+ import glob
3
+ import os
4
+ from pathlib import Path
5
+ import time
6
+
7
+ import cv2
8
+ import hydra
9
+ import matplotlib.pyplot as plt
10
+ import numpy as np
11
+ import pybullet as p
12
+
13
+ from calvin_env.envs.tasks import Tasks
14
+ from calvin_env.utils import utils
15
+
16
+ """
17
+ This script loads a rendered episode and replays it using the recorded actions.
18
+ Optionally, gaussian noise can be added to the actions.
19
+ """
20
+
21
+
22
+ def noise(action, pos_std=0.01, rot_std=1):
23
+ """
24
+ adds gaussian noise to position and orientation.
25
+ units are m for pos and degree for rot
26
+ """
27
+ pos, orn, gripper = action
28
+ rot_std = np.radians(rot_std)
29
+ pos_noise = np.random.normal(0, pos_std, 3)
30
+ rot_noise = p.getQuaternionFromEuler(np.random.normal(0, rot_std, 3))
31
+ pos, orn = p.multiplyTransforms(pos, orn, pos_noise, rot_noise)
32
+ return pos, orn, gripper
33
+
34
+
35
+ @hydra.main(config_path="../../conf", config_name="config_data_collection")
36
+ def run_env(cfg):
37
+ env = hydra.utils.instantiate(cfg.env, show_gui=False, use_vr=False, use_scene_info=True)
38
+
39
+ root_dir = Path("/tmp/test_render/2021-10-05/16-51-11")
40
+
41
+ ep_start_end_ids = np.sort(np.load(root_dir / "ep_start_end_ids.npy"), axis=0)
42
+ rel_actions = []
43
+ tasks = hydra.utils.instantiate(cfg.tasks)
44
+ prev_info = None
45
+ t1 = time.time()
46
+ for s, e in ep_start_end_ids:
47
+ print("new_episode")
48
+ for i in range(s, e + 1):
49
+ file = root_dir / f"episode_{i:07d}.npz"
50
+ data = np.load(file)
51
+ img = data["rgb_static"]
52
+ cv2.imshow("win2", cv2.resize(img[:, :, ::-1], (500, 500)))
53
+ cv2.waitKey(1)
54
+
55
+ if (i - s) % 32 == 0:
56
+ print(f"reset {i}")
57
+ env.reset(scene_obs=data["scene_obs"], robot_obs=data["robot_obs"])
58
+ action = data["rel_actions"]
59
+ # action = np.split(data["actions"], [3, 6])
60
+ # action = noise(action)
61
+
62
+ # rel_actions.append(create_relative_action(data["actions"], data["robot_obs"][:6]))
63
+ # action = utils.to_relative_action(data["actions"], data["robot_obs"], max_pos=0.04, max_orn=0.1)
64
+ # tcp_pos, tcp_orn = p.getLinkState(env.robot.robot_uid, env.robot.tcp_link_id, physicsClientId=env.cid)[:2]
65
+ # tcp_orn = p.getEulerFromQuaternion(tcp_orn)
66
+ # action2 = create_relative_action(data["actions"], np.concatenate([tcp_pos, tcp_orn]))
67
+ o, _, _, info = env.step(action)
68
+ print(info["scene_info"]["lights"]["led"]["logical_state"])
69
+ if (i - s) % 32 != 0:
70
+ print(tasks.get_task_info(prev_info, info))
71
+ else:
72
+ prev_info = deepcopy(info)
73
+ time.sleep(0.01)
74
+ print(time.time() - t1)
75
+ # rel_actions = np.array(rel_actions)
76
+ # for j in range(rel_actions.shape[1]):
77
+ # plt.figure(j)
78
+ # plt.hist(rel_actions[:, j], bins=10)
79
+ # plt.plot()
80
+ # plt.show()
81
+
82
+
83
+ if __name__ == "__main__":
84
+ run_env()
aloha_robot_project/calvin/calvin_env/calvin_env/scripts/unnormalize_depth.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ from shutil import copyfile, copytree
3
+
4
+ import numpy as np
5
+ from tqdm import tqdm
6
+
7
+ load_path = Path("/home/meeso/expert_demos_03_10/training")
8
+
9
+ save_path = Path("/home/meeso/expert_demos_03_10/training_unnormalized_depth")
10
+ save_path.mkdir(parents=True, exist_ok=True)
11
+
12
+ for file in tqdm(load_path.glob("*.npz")):
13
+ data = np.load(file)
14
+ corrected_data = dict(data.items())
15
+ corrected_data["depth_static"] = data["depth_static"] * 2.0
16
+ corrected_data["depth_gripper"] = data["depth_gripper"] * 2.0
17
+ np.savez(save_path / file.name, **corrected_data)
18
+
19
+
20
+ for file in set(load_path.glob("*")) - set(load_path.glob("*.npz")):
21
+ if file.is_dir():
22
+ copytree(file, save_path / file.name)
23
+ else:
24
+ copyfile(file, save_path / file.name)
aloha_robot_project/calvin/calvin_env/calvin_env/utils/utils.py ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import itertools
2
+ import logging
3
+ import os
4
+ from pathlib import Path
5
+ import pickle
6
+ import re
7
+ import subprocess
8
+ import time
9
+ from typing import Union
10
+
11
+ import git
12
+ import numpy as np
13
+ import quaternion
14
+
15
+ # A logger for this file
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ def timeit(method):
20
+ def timed(*args, **kw):
21
+ ts = time.time()
22
+ result = method(*args, **kw)
23
+ te = time.time()
24
+ if "log_time" in kw:
25
+ name = kw.get("log_name", method.__name__.upper())
26
+ kw["log_time"][name] = int((te - ts) * 1000)
27
+ else:
28
+ print("%r %2.2f ms" % (method.__name__, (te - ts) * 1000))
29
+ return result
30
+
31
+ return timed
32
+
33
+
34
+ class FpsController:
35
+ def __init__(self, freq):
36
+ self.loop_time = (1.0 / freq) * 10**9
37
+ self.prev_time = time.time_ns()
38
+
39
+ def step(self):
40
+ current_time = time.time_ns()
41
+ delta_t = current_time - self.prev_time
42
+ if delta_t < self.loop_time:
43
+ nano_sleep(self.loop_time - delta_t)
44
+ self.prev_time = time.time_ns()
45
+
46
+
47
+ def xyzw_to_wxyz(arr):
48
+ """
49
+ Convert quaternions from pyBullet to numpy.
50
+ """
51
+ return [arr[3], arr[0], arr[1], arr[2]]
52
+
53
+
54
+ def wxyz_to_xyzw(arr):
55
+ """
56
+ Convert quaternions from numpy to pyBullet.
57
+ """
58
+ return [arr[1], arr[2], arr[3], arr[0]]
59
+
60
+
61
+ def nano_sleep(time_ns):
62
+ """
63
+ Spinlock style sleep function. Burns cpu power on purpose
64
+ equivalent to time.sleep(time_ns / (10 ** 9)).
65
+
66
+ Should be more precise, especially on Windows.
67
+
68
+ Args:
69
+ time_ns: time to sleep in ns
70
+
71
+ Returns:
72
+
73
+ """
74
+ wait_until = time.time_ns() + time_ns
75
+ while time.time_ns() < wait_until:
76
+ pass
77
+
78
+
79
+ def unit_vector(vector):
80
+ """Returns the unit vector of the vector."""
81
+ return vector / np.linalg.norm(vector)
82
+
83
+
84
+ def angle_between_quaternions(q1, q2):
85
+ """
86
+ Returns the minimum rotation angle between to orientations expressed as quaternions
87
+ quaternions use X,Y,Z,W convention
88
+ """
89
+ q1 = xyzw_to_wxyz(q1)
90
+ q2 = xyzw_to_wxyz(q2)
91
+ q1 = quaternion.from_float_array(q1)
92
+ q2 = quaternion.from_float_array(q2)
93
+
94
+ theta = 2 * np.arcsin(np.linalg.norm((q1 * q2.conjugate()).vec))
95
+ return theta
96
+
97
+
98
+ def angle_between(v1, v2):
99
+ """Returns the angle in radians between vectors 'v1' and 'v2'::
100
+
101
+ >>> angle_between((1, 0, 0), (0, 1, 0))
102
+ 1.5707963267948966
103
+ >>> angle_between((1, 0, 0), (1, 0, 0))
104
+ 0.0
105
+ >>> angle_between((1, 0, 0), (-1, 0, 0))
106
+ 3.141592653589793
107
+ """
108
+ v1_u = unit_vector(v1)
109
+ v2_u = unit_vector(v2)
110
+ return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0))
111
+
112
+
113
+ def get_git_commit_hash(repo_path: Path) -> str:
114
+ repo = git.Repo(search_parent_directories=True, path=repo_path.parent)
115
+ assert repo, "not a repo"
116
+ changed_files = [item.a_path for item in repo.index.diff(None)]
117
+ if changed_files:
118
+ print("WARNING uncommitted modified files: {}".format(",".join(changed_files)))
119
+ return repo.head.object.hexsha
120
+
121
+
122
+ class EglDeviceNotFoundError(Exception):
123
+ """Raised when EGL device cannot be found"""
124
+
125
+
126
+ def get_egl_device_id(cuda_id: int) -> Union[int]:
127
+ """
128
+ >>> i = get_egl_device_id(0)
129
+ >>> isinstance(i, int)
130
+ True
131
+ """
132
+ assert isinstance(cuda_id, int), "cuda_id has to be integer"
133
+ dir_path = Path(__file__).absolute().parents[2] / "egl_check"
134
+ if not os.path.isfile(dir_path / "EGL_options.o"):
135
+ if os.environ.get("LOCAL_RANK", "0") == "0":
136
+ print("Building EGL_options.o")
137
+ subprocess.call(["bash", "build.sh"], cwd=dir_path)
138
+ else:
139
+ # In case EGL_options.o has to be built and multiprocessing is used, give rank 0 process time to build
140
+ time.sleep(5)
141
+ result = subprocess.run(["./EGL_options.o"], capture_output=True, cwd=dir_path)
142
+ n = int(result.stderr.decode("utf-8").split(" of ")[1].split(".")[0])
143
+ for egl_id in range(n):
144
+ my_env = os.environ.copy()
145
+ my_env["EGL_VISIBLE_DEVICE"] = str(egl_id)
146
+ result = subprocess.run(["./EGL_options.o"], capture_output=True, cwd=dir_path, env=my_env)
147
+ match = re.search(r"CUDA_DEVICE=[0-9]+", result.stdout.decode("utf-8"))
148
+ if match:
149
+ current_cuda_id = int(match[0].split("=")[1])
150
+ if cuda_id == current_cuda_id:
151
+ return egl_id
152
+ raise EglDeviceNotFoundError
153
+
154
+
155
+ def angle_between_angles(a, b):
156
+ diff = b - a
157
+ return (diff + np.pi) % (2 * np.pi) - np.pi
158
+
159
+
160
+ def to_relative_action(actions, robot_obs, max_pos=0.02, max_orn=0.05):
161
+ assert isinstance(actions, np.ndarray)
162
+ assert isinstance(robot_obs, np.ndarray)
163
+
164
+ rel_pos = actions[:3] - robot_obs[:3]
165
+ rel_pos = np.clip(rel_pos, -max_pos, max_pos) / max_pos
166
+
167
+ rel_orn = angle_between_angles(robot_obs[3:6], actions[3:6])
168
+ rel_orn = np.clip(rel_orn, -max_orn, max_orn) / max_orn
169
+
170
+ gripper = actions[-1:]
171
+ return np.concatenate([rel_pos, rel_orn, gripper])
172
+
173
+
174
+ def set_egl_device(device):
175
+ assert "EGL_VISIBLE_DEVICES" not in os.environ, "Do not manually set EGL_VISIBLE_DEVICES"
176
+ try:
177
+ cuda_id = device.index if device.type == "cuda" else 0
178
+ except AttributeError:
179
+ cuda_id = device
180
+ try:
181
+ egl_id = get_egl_device_id(cuda_id)
182
+ except EglDeviceNotFoundError:
183
+ logger.warning(
184
+ "Couldn't find correct EGL device. Setting EGL_VISIBLE_DEVICE=0. "
185
+ "When using DDP with many GPUs this can lead to OOM errors. "
186
+ "Did you install PyBullet correctly? Please refer to VREnv README"
187
+ )
188
+ egl_id = 0
189
+ os.environ["EGL_VISIBLE_DEVICES"] = str(egl_id)
190
+ logger.info(f"EGL_DEVICE_ID {egl_id} <==> CUDA_DEVICE_ID {cuda_id}")
191
+
192
+
193
+ def count_frames(directory):
194
+ """
195
+ counts the number of consecutive pickled frames in directory
196
+
197
+ Args:
198
+ directory: str of directory
199
+
200
+ Returns:
201
+ 0 for none, otherwise >0
202
+ """
203
+
204
+ for i in itertools.count(start=0):
205
+ pickle_file = os.path.join(directory, f"{str(i).zfill(12)}.pickle")
206
+ if not os.path.isfile(pickle_file):
207
+ return i
208
+
209
+
210
+ def get_episode_lengths(load_dir, num_frames):
211
+ episode_lengths = []
212
+ render_start_end_ids = [[0]]
213
+ i = 0
214
+ for frame in range(num_frames):
215
+ file_path = os.path.abspath(os.path.join(load_dir, f"{str(frame).zfill(12)}.pickle"))
216
+ with open(file_path, "rb") as file:
217
+ data = pickle.load(file)
218
+ done = data["done"]
219
+ if not done:
220
+ i += 1
221
+ else:
222
+ episode_lengths.append(i)
223
+ render_start_end_ids[-1].append(frame + 1)
224
+ render_start_end_ids.append([frame + 1])
225
+ i = 0
226
+ render_start_end_ids = render_start_end_ids[:-1]
227
+ return episode_lengths, render_start_end_ids
228
+
229
+
230
+ if __name__ == "__main__":
231
+ import doctest
232
+
233
+ doctest.testmod()
aloha_robot_project/calvin/calvin_env/calvin_env/vrdatacollector.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python3
2
+ from copy import deepcopy
3
+ import logging
4
+ import os
5
+ import sys
6
+
7
+ import hydra
8
+ import pybullet as p
9
+ import quaternion # noqa
10
+
11
+ from calvin_env.io_utils.data_recorder import DataRecorder
12
+ from calvin_env.io_utils.vr_input import VrInput
13
+
14
+ # A logger for this file
15
+ log = logging.getLogger(__name__)
16
+
17
+
18
+ @hydra.main(config_path="../conf", config_name="config_data_collection")
19
+ def main(cfg):
20
+ # Load Scene
21
+ env = hydra.utils.instantiate(cfg.env)
22
+ vr_input = hydra.utils.instantiate(cfg.vr_input)
23
+
24
+ data_recorder = None
25
+ if cfg.recorder.record:
26
+ data_recorder = DataRecorder(env, cfg.recorder.record_fps, cfg.recorder.enable_tts)
27
+
28
+ log.info("Initialization done!")
29
+ log.info("Entering Loop")
30
+
31
+ record = False
32
+
33
+ while 1:
34
+ # get input events
35
+ action = vr_input.get_vr_action()
36
+ obs, _, _, info = env.step(action)
37
+ done = False
38
+ if vr_input.reset_button_pressed:
39
+ done = True
40
+ if vr_input.start_button_pressed:
41
+ record = True
42
+ if vr_input.reset_button_hold:
43
+ data_recorder.delete_episode()
44
+ if record and cfg.recorder.record:
45
+ data_recorder.step(vr_input.prev_vr_events, obs, done, info)
46
+ if done:
47
+ record = False
48
+ env.reset()
49
+
50
+
51
+ if __name__ == "__main__":
52
+ main()
aloha_robot_project/calvin/calvin_env/conf/cameras/cameras/gripper.yaml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ _target_: calvin_env.camera.gripper_camera.GripperCamera
2
+ name: gripper
3
+ fov: 75
4
+ aspect: 1
5
+ nearval: 0.01
6
+ farval: 2
7
+ width: 84
8
+ height: 84
aloha_robot_project/calvin/calvin_env/conf/cameras/cameras/opposing.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ _target_: calvin_env.camera.static_camera.StaticCamera
2
+ name: opposing
3
+ fov: 75
4
+ aspect: 1
5
+ nearval: 0.01
6
+ farval: 2
7
+ width: 200
8
+ height: 200
9
+ look_at: [ 0.4, 0.5, 0.6 ]
10
+ look_from: [ 0.4, 1.5, 0.9 ]
aloha_robot_project/calvin/calvin_env/conf/cameras/cameras/static.yaml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ _target_: calvin_env.camera.static_camera.StaticCamera
2
+ name: static
3
+ fov: 10
4
+ aspect: 1
5
+ nearval: 0.01
6
+ farval: 10
7
+ width: 200
8
+ height: 200
9
+ look_at: [ -0.026242351159453392, -0.0302329882979393, 0.3920000493526459]
10
+ look_from: [ 2.871459009488717, -2.166602199425597, 2.555159848480571]
11
+ up_vector: [ 0.4041403970338857, 0.22629790978217404, 0.8862616969685161]