mhsnar commited on
Commit
0ea5594
·
verified ·
1 Parent(s): f8faa82

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. applications/avoiding/avoiding_baselines/DiRecT/.gitignore +28 -0
  2. applications/avoiding/avoiding_baselines/DiRecT/README.md +155 -0
  3. applications/avoiding/avoiding_baselines/DiRecT/d3il/__init__.py +1 -0
  4. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/__init__.py +0 -0
  5. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/__init__.py +0 -0
  6. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/__init__.py +0 -0
  7. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/Config/fictive_robot_controller_config.gin +19 -0
  8. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/Config/mujoco_controller_config.gin +48 -0
  9. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/Config/pybullet_controller_config.gin +34 -0
  10. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/Controller.py +253 -0
  11. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/GainsInterface.py +90 -0
  12. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/IKControllers.py +386 -0
  13. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/TrajectoryTracking.py +416 -0
  14. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/__init__.py +3 -0
  15. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/executor.py +48 -0
  16. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/Camera.py +205 -0
  17. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/Model.py +91 -0
  18. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/Robots.py +491 -0
  19. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/Scene.py +319 -0
  20. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/__init__.py +4 -0
  21. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/logger.py +867 -0
  22. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/sim_object/__init__.py +2 -0
  23. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/sim_object/sim_obj_repo.py +46 -0
  24. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/sim_object/sim_object.py +49 -0
  25. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/time_keeper.py +13 -0
  26. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/gyms/__init__.py +0 -0
  27. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/gyms/gym_controllers.py +162 -0
  28. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/gyms/gym_env_wrapper.py +119 -0
  29. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/gyms/gym_utils/__init__.py +0 -0
  30. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/gyms/gym_utils/helpers.py +7 -0
  31. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/gyms/gym_utils/rewards.py +13 -0
  32. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/SimFactory.py +81 -0
  33. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/__init__.py +6 -0
  34. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/MjCamera.py +196 -0
  35. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/MjFactory.py +50 -0
  36. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/MjLoadable.py +86 -0
  37. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/MjPrimLoader.py +38 -0
  38. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/MjRobot.py +287 -0
  39. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/MjScene.py +282 -0
  40. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/__init__.py +14 -0
  41. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/mj_utils/__init__.py +0 -0
  42. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/mj_utils/mj_helper.py +75 -0
  43. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/mj_utils/mj_render_singleton.py +44 -0
  44. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/mj_utils/mj_renderer.py +593 -0
  45. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/mj_utils/mj_scene_object.py +262 -0
  46. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/mj_utils/mj_scene_parser.py +94 -0
  47. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/universal_sim/PrimitiveObjects.py +144 -0
  48. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/universal_sim/__init__.py +0 -0
  49. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/utils/__init__.py +1 -0
  50. applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/utils/geometric_transformation.py +319 -0
applications/avoiding/avoiding_baselines/DiRecT/.gitignore ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Caches
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+
6
+ # Python packaging
7
+ *.egg-info/
8
+ *.so
9
+ *.o
10
+
11
+ # Experiments, logs, and run outputs
12
+ logs/
13
+ slurm_logs/
14
+
15
+ # Mujoco
16
+ MUJOCO_LOG.TXT
17
+ panda_tmp_*.xml
18
+
19
+ # Notebooks
20
+ .ipynb_checkpoints/
21
+ *.ipynb
22
+
23
+ # Slurm
24
+ *.out
25
+ *.err
26
+
27
+ # Wandb
28
+ wandb/
applications/avoiding/avoiding_baselines/DiRecT/README.md ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Safe robotic manipulation in D3IL avoiding
2
+
3
+ This folder presents the benchmarks for _DiRecT_ and relevant baselines on the [D3IL](https://github.com/ALRhub/d3il) `avoiding-v0` navigation task with dynamics constraints. The agent must navigate upward through 6 circular pillar obstacles to reach a goal region while satisfying linearized dynamics and obstacle-avoidance constraints.
4
+ ![D3IL avoiding-v0 visualization](assets/d3il-grid.gif)
5
+
6
+ **Table of Contents**:
7
+ - [Installation](#installation)
8
+ - [Fit the linearized dynamics](#fit-the-linearized-dynamics)
9
+ - [Train the model](#train-the-model)
10
+ - [Evaluation](#evaluation)
11
+ - [Results](#results)
12
+ - [Code structure](#code-structure)
13
+ - [References](#references)
14
+
15
+ ## Installation
16
+ > [!NOTE]
17
+ > The `avoiding-v0` environment uses MuJoCo 2.3.x via the `mujoco` Python bindings — no separate system-wide MuJoCo install is required. CasADi / IPOPT and Pinocchio are pulled in through conda-forge.
18
+
19
+ 1. Change the CUDA and torch versions in `environment.yml` to ones compatible with your system requirements (default is CUDA 12.6 + torch 2.11).
20
+ 2. Create and activate the conda environment. The provided `setup_env.sh` script handles environment creation, the `qpth` install (which needs `--no-build-isolation` due to a broken numpy specifier), and the `LD_LIBRARY_PATH` activation hook:
21
+ ```bash
22
+ bash setup_env.sh
23
+ conda activate direct-d3il
24
+ ```
25
+
26
+ ## Fit the linearized dynamics
27
+ Fit a linear dynamics model `s_{t+1} = A·s_t + B·a_t + c` from the D3IL `avoiding-v0` expert trajectories (96 episodes). The fitted matrices are later imposed as linear constraints during planning.
28
+
29
+ ```bash
30
+ python fit_dynamics.py \
31
+ --env avoiding-v0 # gym env id (defaults to avoiding-v0)
32
+ ```
33
+ Outputs (written to `logs/avoiding-v0/dynamics/`):
34
+ - `linear_model.npz` — fitted `A`, `B`, `c`, metadata, and normalizer (consumed by `eval.py`).
35
+ - `linear_model_predictions.png` — per-dimension true-vs-predicted scatter plot.
36
+ - `dynamics_verification.png` — single-step comparison against the real environment.
37
+ - `all_trajectories.png` — overlay of the expert dataset.
38
+
39
+ ## Train the model
40
+ Train the unconstrained diffusion planner (Temporal U-Net, x_0-prediction parameterization with a cosine noise schedule) on the same D3IL dataset. Weights & Biases is used for logging (project `direct-d3il`).
41
+
42
+ ```bash
43
+ python train.py \
44
+ --exp-name x0pred \ # subfolder under <log-folder>/<env>/diffusion/
45
+ --seed 0 \
46
+ --batch-size 32 \ # overrides default 32
47
+ --n-train-steps 1000001 # default 1M steps
48
+ ```
49
+
50
+ Resume from the latest checkpoint with `--resume`. Checkpoints (raw + EMA weights), sample previews, and the resolved config are written to `logs/avoiding-v0/diffusion/<exp-name>/`:
51
+ - `model_*.pth`, `model_ema_*.pth` — saved every `--save-freq` steps (default 50k).
52
+ - `samples/step_*.png` — periodic sample previews from the EMA model.
53
+ - `tensorboard_logs/` — TensorBoard event files.
54
+ - `config.yaml` — snapshot of the fully-resolved config.
55
+
56
+ To submit as a SLURM job (edit the `#SBATCH` directives and conda env name first):
57
+ ```bash
58
+ sbatch run.sbatch
59
+ ```
60
+
61
+ ## Evaluation
62
+ Evaluate any of the planning policies on the constrained `avoiding-v0` task. The trained diffusion weights and fitted dynamics are both required.
63
+
64
+ ```bash
65
+ python eval.py \
66
+ --diffusion-exp-name x0pred \ # which trained model to load
67
+ --diffusion-cp 10 \ # checkpoint index (model_ema_<cp>.pth)
68
+ --guidance-method direct \ # one of the methods listed below
69
+ --constraints \ # enable the obstacle constraint set
70
+ --random-repeat 100 \ # number of evaluation rollouts
71
+ --exp-name direct \ # subfolder under <log-folder>/<env>/eval/
72
+ --seed 0 \
73
+ --device cuda:0
74
+ ```
75
+
76
+ Available planning policies (selected via `--guidance-method`): `no` (unconditional), `gradient`, `classifier`, `projection`, `safediffuser` (with `--cbf-algorithm {RoS,ReS,TVS}`), `primal-dual`, `augmented-lagrangian`, `direct`. The DiRecT method additionally supports `--pred-objective distance` to add a goal-distance objective in clean x_0 space.
77
+
78
+ To run the full sweep over every policy (dynamics constraint always on, 100 episodes each), use the provided SLURM script (edit the `#SBATCH` directives and conda env name first):
79
+ ```bash
80
+ sbatch eval_all.sbatch
81
+ ```
82
+
83
+ ## Results
84
+ For each evaluation, results are written under `logs/avoiding-v0/eval/<exp-name>/`:
85
+ - `config.yaml` — resolved config used for the run.
86
+ - `runs.csv` — one row per rollout with per-run metrics (success, safety, steps, total constraint violations, total reward, average computation time per replan).
87
+ - `summary.json` — aggregated statistics (success rate, safety rate, average steps / violations / rewards / compute time).
88
+ - `all_real.png` — overlay of every closed-loop rollout on the obstacle field.
89
+ - `predictions/ep_*.png` — per-episode plot overlaying the diffused plans and the executed rollout.
90
+ - `trajectories.npz` — raw rollout state arrays (suppressed by `--no-trajectories`).
91
+
92
+ ## Code structure
93
+ ```
94
+ d3il/
95
+ ├── d3il/ # ported D3IL `avoiding-v0` environment + expert data (96 episodes)
96
+ │ └── environments/
97
+ ├── datasets/
98
+ │ ├── sequence.py # `SequenceDataset` (H=16 windows, LimitsNormalizer)
99
+ │ ├── buffer.py # replay buffer over expert episodes
100
+ │ ├── normalization.py # observation / action normalizers
101
+ │ └── preprocessing.py
102
+ ├── policy/ # planning policies (one file per method)
103
+ │ ├── unconditional.py # baseline DDIM sampling
104
+ │ ├── gradient_guidance.py # DPS-style posterior sampling
105
+ │ ├── classifier_guidance.py # classifier guidance on noisy trajectory
106
+ │ ├── projected_diffusion.py # IPOPT projection per denoising step (noisy space)
107
+ │ ├── safediffuser.py # CBF-guided QP (RoS / ReS / TVS)
108
+ │ ├── augmented_lagrangian.py # primal-dual + augmented Lagrangian
109
+ │ ├── direct.py # DiRecT: IPOPT projection in clean x_0 space
110
+ │ └── value_model.py # differentiable proxy value function (obstacles + dynamics)
111
+ ├── model.py # `TemporalUnet` + `CosineScheduleDiffusion` (x_0 parameterization)
112
+ ├── projector.py # `IpoptProjector` — CasADi/IPOPT constraint projection
113
+ ├── obstacles.py # circular & planar obstacles, constraint sets, violation checks
114
+ ├── fit_dynamics.py # fit `s_{t+1} = A s_t + B a_t + c` from offline data
115
+ ├── train.py # train the diffusion planner
116
+ ├── eval.py # rollout + metric aggregation for a chosen policy
117
+ ├── utils/ # rendering, array helpers, training utilities
118
+ ├── run.sbatch # SLURM script for training
119
+ ├── eval_all.sbatch # SLURM script sweeping all 11 policies
120
+ ├── setup_env.sh # conda env bootstrap (incl. qpth + LD_LIBRARY_PATH hook)
121
+ └── environment.yml # conda environment spec
122
+ ```
123
+
124
+ ## ✏️ Citation
125
+ If you find our code or paper useful for your research, please consider citing our work:
126
+ ```
127
+ @misc{giaretta2026directsafediffusionbasedplanning,
128
+ title={DiRecT: Safe Diffusion-Based Planning via Receding-Horizon Denoising},
129
+ author={Paolo Giaretta and Zeyang Li and Navid Azizan},
130
+ year={2026},
131
+ eprint={2606.15359},
132
+ archivePrefix={arXiv},
133
+ primaryClass={cs.LG},
134
+ url={https://arxiv.org/abs/2606.15359},
135
+ }
136
+ ```
137
+
138
+ The `avoiding-v0` environment and expert data come from the D3IL benchmark:
139
+ ```bibtex
140
+ @inproceedings{jia2024towards,
141
+ title={Towards Diverse Behaviors: A Benchmark for Imitation Learning with Human Demonstrations},
142
+ author={Xiaogang Jia and Denis Blessing and Xinkai Jiang and Moritz Reuss and Atalay Donat and Rudolf Lioutikov and Gerhard Neumann},
143
+ booktitle={The Twelfth International Conference on Learning Representations},
144
+ year={2024},
145
+ url={https://openreview.net/forum?id=6pPYRXKPpw}
146
+ }
147
+ ```
148
+
149
+ ## References
150
+ - Michael Janner, Yilun Du, Joshua B. Tenenbaum, and Sergey Levine. Planning with diffusion for flexible behavior synthesis. In Proceedings of the 39th International Conference on Machine Learning, volume 162 of Proceedings of Machine Learning Research, pages 9902–9915, 2022.
151
+ - Prafulla Dhariwal and Alexander Nichol. Diffusion models beat gans on image synthesis. In Advances in Neural Information Processing Systems, volume 34, pages 8780–8794, 2021.
152
+ - Jacob K Christopher, Stephen Baek, and Ferdinando Fioretto. Constrained synthesis with projected diffusion models. Advances in Neural Information Processing Systems, 37:89307–89333, 2024.
153
+ - Wei Xiao, Tsun-Hsuan Wang, Chuang Gan, Ramin Hasani, Mathias Lechner, and Daniela Rus. Safediffuser: Safe planning with diffusion probabilistic models. In The Thirteenth International Conference on Learning Representations, 2025. URL https://openreview.net/forum?id=ig2wk7kK9J
154
+ - Jichen Zhang, Liqun Zhao, Antonis Papachristodoulou, and Jack Umenberger. Constrained diffusers for safe planning and control, 2025. URL https://arxiv.org/abs/2506.12544.
155
+ - Xiaogang Jia, Denis Blessing, Xinkai Jiang, Moritz Reuss, Atalay Donat, Rudolf Lioutikov, and Gerhard Neumann. Towards diverse behaviors: A benchmark for imitation learning with human demonstrations. In The Twelfth International Conference on Learning Representations, 2024.
applications/avoiding/avoiding_baselines/DiRecT/d3il/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from .environments.d3il.envs.gym_avoiding_env.gym_avoiding import envs
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/__init__.py ADDED
File without changes
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/__init__.py ADDED
File without changes
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/__init__.py ADDED
File without changes
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/Config/fictive_robot_controller_config.gin ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Joint PD Controller
2
+ environments.d3il.d3il_sim.controllers.GainsInterface.JointPDGains.pgain = [1200.0, 1200.0, 1200.0, 1200.0, 1200.0, 300.0, 100.0]
3
+ environments.d3il.d3il_sim.controllers.GainsInterface.JointPDGains.dgain = [25.0, 25.0, 25.0, 25.0, 15.0, 12.5, 7.5]
4
+
5
+ # Damping Controller
6
+ environments.d3il.d3il_sim.controllers.GainsInterface.DampingGains.dgain = [5. , 5. , 5. , 5. , 3. , 2.5, 1.5]
7
+
8
+ # Cartesian Position Impedance Controller
9
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosPDGains.pgain = [1000.0, 1000.0, 1000.0]
10
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosPDGains.dgain = [31.622776601683793, 31.622776601683793, 31.622776601683793]
11
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosPDGains.pgain_null = [1.2, 1.2, 1.2, 1.2, 0.5, 0.3, 0.1]
12
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosPDGains.dgain_null = [0.1 , 0.1 , 0.1 , 0.1 , 0.06, 0.05, 0.03]
13
+
14
+ # Cartesian Position and Orientation Impedance Controller
15
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatPDGains.pgain = [33.13189603604459, 187.9403713446798, 31.0064033017648, 27.69370238555632, 33.98706171459314, 180.9185531893281]
16
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatPDGains.dgain = [16.329377526884908, 7.672464154315535, 19.307738014214987, 19.369027815549774, 14.709666893271407, 13.529185054450448]
17
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatPDGains.pgain_null = [7.675519770796831, 2.676935478437176, 8.539040163444975, 1.270446361314313, 8.87752182480855, 2.186782233762969, 4.414432577659688]
18
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatPDGains.dgain_null = [0.35158682223052035,0.03532768494155088,0.9812676349486628,0.791470915462905,0.00066062504055376,0.9520533614689963,0.04623941774486632]
19
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatPDGains.dgain_velcontroller = [25.0, 25.0, 25.0, 25.0, 15.0, 12.5, 7.5]
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/Config/mujoco_controller_config.gin ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Joint PD Controller
2
+ # ##these gains seem to be too high ...
3
+ #environments.d3il.d3il_sim.controllers.GainsInterface.JointPDGains.pgain = [600.0, 600.0, 600.0, 600.0, 250.0, 150.0, 50.0]
4
+ #environments.d3il.d3il_sim.controllers.GainsInterface.JointPDGains.dgain = [50.0, 50.0, 50.0, 50.0, 30.0, 25.0, 15.0]
5
+
6
+ environments.d3il.d3il_sim.controllers.GainsInterface.JointPDGains.pgain = [120.0, 120.0, 120.0, 120.0, 50.0, 30.0, 10.0]
7
+ environments.d3il.d3il_sim.controllers.GainsInterface.JointPDGains.dgain = [10.0, 10.0, 10.0, 10.0, 6.0, 5.0, 3.0]
8
+
9
+ # Damping Controller
10
+ environments.d3il.d3il_sim.controllers.GainsInterface.DampingGains.dgain = [5. , 5. , 5. , 5. , 3. , 2.5, 1.5]
11
+
12
+ # Cartesian Position Impedance Controller
13
+ #environments.d3il.d3il_sim.controllers.GainsInterface.CartPosPDGains.pgain = [80.0, 80.0, 80.0]
14
+ #environments.d3il.d3il_sim.controllers.GainsInterface.CartPosPDGains.dgain = [18.973665961010276, 18.973665961010276, 18.973665961010276]
15
+ #environments.d3il.d3il_sim.controllers.GainsInterface.CartPosPDGains.pgain_null = [1.2, 1.2, 1.2, 1.2, 0.5, 0.3, 0.1]
16
+ #environments.d3il.d3il_sim.controllers.GainsInterface.CartPosPDGains.dgain_null = [0.1 , 0.1 , 0.1 , 0.1 , 0.06, 0.05, 0.03]
17
+
18
+ # Cartesian Position Impedance Controller
19
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosControllerConfig.pgain_pos = [160.0, 160.0, 160.0]
20
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosControllerConfig.pgain_null = [1.2, 1.2, 1.2, 1.2, 0.5, 0.3, 0.1]
21
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosControllerConfig.J_reg = 1e-6
22
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosControllerConfig.W = [1, 1, 1, 1, 1, 1, 1]
23
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosControllerConfig.rest_posture = [0, 0.174, 0, -0.872, 0, 1.222, 0.785]
24
+
25
+ # Cartesian Position Impedance Controller And Orientation
26
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.pgain_pos = [200.0, 200.0, 800.0]
27
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.pgain_null = [40, 40, 40, 40, 40, 40, 40]
28
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.J_reg = 1e-12
29
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.W = [1, 1, 1, 1, 1, 1, 1]
30
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.rest_posture = [0, 0.174, 0, -0.872, 0, 1.222, 0.785]
31
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.pgain_quat = [30.0, 30.0, 30.0]
32
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.ddgain = [0.4, 0.4, 0.4, 0.4 ,0.4, 0.4, 0.4]
33
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.joint_filter_coefficient = 1.0
34
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.min_svd_values = 1e-2
35
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.max_svd_values = 1e2
36
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.num_iter = 3
37
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.learningRate = 0.001
38
+
39
+
40
+ # Cartesian Position Jacobian Transpose Impedance Controller And Orientation
41
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatJacTransposeControllerConfig.pgain_pos = [450.0, 450.0, 450.0]
42
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatJacTransposeControllerConfig.dgain = [25.0, 25.0, 25.0, 25.0, 25.0, 25.0]
43
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatJacTransposeControllerConfig.pgain_null = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
44
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatJacTransposeControllerConfig.dgain_null = [0.25 , 0.25 , 0.25 , 0.25 , 0.25, 0.25, 0.25]
45
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatJacTransposeControllerConfig.J_reg = 1e-3
46
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatJacTransposeControllerConfig.W = [1, 1, 1, 10, 1, 1, 1]
47
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatJacTransposeControllerConfig.rest_posture = [0, 0.174, 0, -0.872, 0, 1.222, 0.785]
48
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatJacTransposeControllerConfig.pgain_quat = [250.0, 250.0, 250.0]
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/Config/pybullet_controller_config.gin ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Joint PD Controller
2
+
3
+ environments.d3il.d3il_sim.controllers.GainsInterface.JointPDGains.pgain = [1200.0, 1200.0, 1200.0, 1200.0, 1200.0, 300.0, 100.0]
4
+ environments.d3il.d3il_sim.controllers.GainsInterface.JointPDGains.dgain = [25.0, 25.0, 25.0, 25.0, 25.0, 15.0, 10.0]
5
+
6
+ # Damping Controller
7
+ environments.d3il.d3il_sim.controllers.GainsInterface.DampingGains.dgain = [5. , 5. , 5. , 5. , 3. , 2.5, 1.5]
8
+
9
+ # Cartesian Position Impedance Controller
10
+ #environments.d3il.d3il_sim.controllers.GainsInterface.CartPosPDGains.pgain = [80.0, 80.0, 80.0]
11
+ #environments.d3il.d3il_sim.controllers.GainsInterface.CartPosPDGains.dgain = [18.973665961010276, 18.973665961010276, 18.973665961010276]
12
+ #environments.d3il.d3il_sim.controllers.GainsInterface.CartPosPDGains.pgain_null = [1.2, 1.2, 1.2, 1.2, 0.5, 0.3, 0.1]
13
+ #environments.d3il.d3il_sim.controllers.GainsInterface.CartPosPDGains.dgain_null = [0.1 , 0.1 , 0.1 , 0.1 , 0.06, 0.05, 0.03]
14
+
15
+ # Cartesian Position Impedance Controller
16
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosControllerConfig.pgain_pos = [160.0, 160.0, 160.0]
17
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosControllerConfig.pgain_null = [1.2, 1.2, 1.2, 1.2, 0.5, 0.3, 0.1]
18
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosControllerConfig.J_reg = 1e-6
19
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosControllerConfig.W = [1, 1, 1, 1, 1, 1, 1]
20
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosControllerConfig.rest_posture = [0, 0.174, 0, -0.872, 0, 1.222, 0.785]
21
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.ddgain = [0.4, 0.4, 0.4, 0.4 ,0.4, 0.4, 0.4]
22
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.joint_filter_coefficient = 0.99
23
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.min_svd_values = 1e-2
24
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.max_svd_values = 1e2
25
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.num_iter = 3
26
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.learningRate = 0.001
27
+
28
+ # Cartesian Position Impedance Controller And Orientation
29
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.pgain_pos = [160.0, 160.0, 160.0]
30
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.pgain_null = [1.2, 1.2, 1.2, 1.2, 0.5, 0.3, 0.1]
31
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.J_reg = 1e-6
32
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.W = [1, 1, 1, 1, 1, 1, 1]
33
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.rest_posture = [0, 0.174, 0, -0.872, 0, 1.222, 0.785]
34
+ environments.d3il.d3il_sim.controllers.GainsInterface.CartPosQuatControllerConfig.pgain_quat = [800.0, 800.0, 800.0]
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/Controller.py ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import threading
2
+ from abc import abstractmethod
3
+
4
+ import numpy as np
5
+
6
+ import d3il.environments.d3il.d3il_sim.controllers.GainsInterface as gains
7
+
8
+
9
+ class ControllerBase:
10
+
11
+ def __init__(self):
12
+ self.paramsLock = threading.Lock()
13
+ self.last_control_timestamp = np.nan
14
+ self._max_duration = None
15
+ self._max_timesteps = None
16
+ self._controller_timer = None
17
+
18
+ def isFinished(self, robot):
19
+
20
+ if self._max_duration is not None:
21
+ return robot.time_stamp - self._controller_timer >= self._max_duration
22
+
23
+ if self._max_timesteps is not None:
24
+ return robot.step_count - self._controller_timer >= self._max_timesteps
25
+ return False
26
+
27
+ def initController(self, robot, maxDuration):
28
+ return
29
+
30
+ def getControl(self, robot):
31
+ self.last_control_timestamp = robot.time_stamp
32
+ return 0
33
+
34
+ def is_used(self, robot):
35
+ return (
36
+ not np.isnan(self.last_control_timestamp)
37
+ and robot.time_stamp - self.last_control_timestamp < 0.03
38
+ )
39
+
40
+ def setAction(self, action):
41
+ return 0
42
+
43
+ def run(self, robot, log=True):
44
+
45
+ while not self.isFinished(robot):
46
+ robot.nextStep(log)
47
+
48
+ def executeController(self, robot, maxDuration=10, block=True, log=True):
49
+
50
+ self._max_duration = maxDuration
51
+ self._max_timesteps = None
52
+ self._controller_timer = robot.time_stamp
53
+
54
+ self.initController(robot, maxDuration)
55
+ robot.activeController = self
56
+
57
+ if block:
58
+ self.run(robot, log=log)
59
+
60
+ def executeControllerTimeSteps(self, robot, timeSteps=10, block=True, log=True):
61
+
62
+ self._max_duration = None
63
+ self._max_timesteps = timeSteps
64
+ self._controller_timer = robot.step_count
65
+
66
+ self.initController(robot, timeSteps * robot.dt)
67
+ robot.activeController = self
68
+
69
+ if block:
70
+ self.run(robot, log)
71
+
72
+ @abstractmethod
73
+ def reset(self):
74
+ pass
75
+
76
+
77
+ class TorqueController(ControllerBase):
78
+
79
+ def __init__(self):
80
+ ControllerBase.__init__(self)
81
+ self.reset()
82
+
83
+ def getControl(self, robot):
84
+ super(TorqueController, self).getControl(robot)
85
+ return self.torque
86
+
87
+ def setAction(self, action):
88
+ self.torque = action.copy()
89
+
90
+ def reset(self):
91
+ self.torque = []
92
+
93
+
94
+ class TrackingController(ControllerBase):
95
+
96
+ def __init__(self, dimSetPoint):
97
+ ControllerBase.__init__(self)
98
+ self.dimSetPoint = dimSetPoint
99
+ self.tracking_error = False
100
+
101
+ def setSetPoint(self, desired_pos, desired_vel=None, desired_acc=None):
102
+ pass
103
+
104
+ def getCurrentPos(self, robot):
105
+ pass
106
+
107
+ def getDesiredPos(self, robot):
108
+ pass
109
+
110
+ @abstractmethod
111
+ def reset(self):
112
+ pass
113
+
114
+
115
+ class JointPDController(TrackingController, gains.JointPDGains):
116
+
117
+ def __init__(self):
118
+ TrackingController.__init__(self, dimSetPoint=7)
119
+ gains.JointPDGains.__init__(self)
120
+
121
+ self.reset()
122
+
123
+ def reset(self):
124
+ self.desired_joint_pos = np.array([0, 0, 0, -1.562, 0, 1.914, 0])
125
+ self.desired_joint_vel = np.zeros((7,))
126
+ self.desired_joint_acc = np.zeros((7,))
127
+
128
+ def getControl(self, robot):
129
+
130
+ super(JointPDController, self).getControl(robot)
131
+ self.paramsLock.acquire()
132
+ qd_d = self.desired_joint_pos - robot.current_j_pos
133
+ vd_d = self.desired_joint_vel - robot.current_j_vel
134
+
135
+ target_j_acc = self.pgain * qd_d + self.dgain * vd_d
136
+
137
+ robot.des_joint_pos = self.desired_joint_pos.copy()
138
+ robot.des_joint_vel = self.desired_joint_vel.copy()
139
+ robot.des_joint_acc = self.desired_joint_acc.copy()
140
+
141
+ self.paramsLock.release()
142
+ return target_j_acc
143
+
144
+ def setSetPoint(self, desired_pos, desired_vel=None, desired_acc=None):
145
+
146
+ self.paramsLock.acquire()
147
+ self.desired_joint_pos = desired_pos
148
+ if desired_vel is not None:
149
+ self.desired_joint_vel = desired_vel
150
+ if desired_acc is not None:
151
+ self.desired_joint_acc = desired_acc
152
+ self.paramsLock.release()
153
+
154
+ def getCurrentPos(self, robot):
155
+
156
+ return robot.current_j_pos
157
+
158
+ def getDesiredPos(self, robot):
159
+
160
+ return robot.des_joint_pos
161
+
162
+
163
+ class ModelBasedFeedforwardController(JointPDController):
164
+
165
+ def __init__(self):
166
+ JointPDController.__init__(self)
167
+
168
+ def getControl(self, robot):
169
+
170
+ super(ModelBasedFeedforwardController, self).getControl(robot)
171
+ self.paramsLock.acquire()
172
+ qd_d = self.desired_joint_pos - robot.current_j_pos
173
+ vd_d = self.desired_joint_vel - robot.current_j_vel
174
+
175
+ target_j_acc = self.pgain * qd_d + self.dgain * vd_d
176
+ uff = robot.get_mass_matrix(self.desired_joint_pos).dot(
177
+ self.desired_joint_acc
178
+ ) + robot.get_coriolis(self.desired_joint_pos, self.desired_joint_vel)
179
+
180
+ robot.des_joint_pos = self.desired_joint_pos.copy()
181
+ robot.des_joint_vel = self.desired_joint_vel.copy()
182
+ robot.des_joint_acc = self.desired_joint_acc.copy()
183
+
184
+ self.paramsLock.release()
185
+ return target_j_acc + uff
186
+
187
+
188
+ class ModelBasedFeedbackController(JointPDController):
189
+
190
+ def __init__(self):
191
+ JointPDController.__init__(self)
192
+
193
+ def getControl(self, robot):
194
+
195
+ super(ModelBasedFeedbackController, self).getControl(robot)
196
+ self.paramsLock.acquire()
197
+ qd_d = self.desired_joint_pos - robot.current_j_pos
198
+ vd_d = self.desired_joint_vel - robot.current_j_vel
199
+
200
+ target_j_acc = self.pgain * qd_d + self.dgain * vd_d + self.desired_joint_acc
201
+ uff = robot.get_mass_matrix(robot.current_j_pos).dot(
202
+ target_j_acc
203
+ ) + robot.get_coriolis(robot.current_j_pos, robot.current_j_vel)
204
+
205
+ robot.des_joint_pos = self.desired_joint_pos.copy()
206
+ robot.des_joint_vel = self.desired_joint_vel.copy()
207
+ robot.des_joint_acc = self.desired_joint_acc.copy()
208
+
209
+ self.paramsLock.release()
210
+ return uff
211
+
212
+
213
+ class JointPositionController(JointPDController):
214
+ def setAction(self, action):
215
+ self.desired_joint_pos = action
216
+
217
+
218
+ class JointVelocityController(JointPDController):
219
+ def __init__(self):
220
+ JointPDController.__init__(self)
221
+ self.pgain = np.zeros((self.dimSetPoint,))
222
+
223
+ def setAction(self, action):
224
+ self.desired_joint_vel = action
225
+
226
+
227
+ class ZeroTorqueController(TrackingController):
228
+
229
+ def __init__(self, dimSetPoint=7):
230
+ TrackingController.__init__(self, dimSetPoint=dimSetPoint)
231
+
232
+ def getControl(self, robot):
233
+ super().getControl(robot)
234
+ target_j_acc = np.zeros((self.dimSetPoint,))
235
+ return target_j_acc
236
+
237
+ def reset(self):
238
+ pass
239
+
240
+
241
+ class DampingController(ControllerBase, gains.DampingGains):
242
+
243
+ def __init__(self):
244
+ ControllerBase.__init__(self)
245
+ gains.DampingGains.__init__(self)
246
+
247
+ def getControl(self, robot):
248
+
249
+ super(DampingController, self).getControl(robot)
250
+ self.paramsLock.acquire()
251
+ target_j_acc = -self.dgain * robot.current_j_vel
252
+ self.paramsLock.release()
253
+ return target_j_acc
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/GainsInterface.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gin
2
+
3
+
4
+ class PDGains:
5
+ def __init__(self, pgain, dgain):
6
+ self.pgain = pgain
7
+ self.dgain = dgain
8
+
9
+
10
+ @gin.configurable
11
+ class JointPDGains(PDGains):
12
+ def __init__(self, pgain, dgain):
13
+ super(JointPDGains, self).__init__(pgain, dgain)
14
+
15
+
16
+ @gin.configurable
17
+ class DampingGains(PDGains):
18
+ def __init__(self, dgain):
19
+ super(DampingGains, self).__init__(None, dgain)
20
+
21
+
22
+ @gin.configurable
23
+ class CartPosControllerConfig:
24
+ def __init__(self, pgain_pos, J_reg, W, pgain_null, rest_posture):
25
+ self.pgain_pos = pgain_pos
26
+ self.J_reg = J_reg
27
+ self.W = W
28
+
29
+ self.rest_posture = rest_posture
30
+ self.pgain_null = pgain_null
31
+
32
+
33
+ @gin.configurable
34
+ class CartPosQuatControllerConfig:
35
+ def __init__(
36
+ self,
37
+ pgain_pos,
38
+ pgain_quat,
39
+ J_reg,
40
+ W,
41
+ pgain_null,
42
+ rest_posture,
43
+ ddgain,
44
+ joint_filter_coefficient,
45
+ min_svd_values,
46
+ max_svd_values,
47
+ num_iter,
48
+ learningRate,
49
+ ):
50
+
51
+ self.pgain_pos = pgain_pos
52
+ self.pgain_quat = pgain_quat
53
+ self.J_reg = J_reg
54
+ self.W = W
55
+
56
+ self.rest_posture = rest_posture
57
+ self.pgain_null = pgain_null
58
+
59
+ self.ddgain = ddgain
60
+ self.joint_filter_coefficient = joint_filter_coefficient
61
+ self.min_svd_values = min_svd_values
62
+ self.max_svd_values = max_svd_values
63
+
64
+ self.num_iter = num_iter
65
+ self.learningRate = learningRate
66
+
67
+
68
+ @gin.configurable
69
+ class CartPosQuatJacTransposeControllerConfig:
70
+ def __init__(
71
+ self,
72
+ pgain_pos,
73
+ dgain,
74
+ pgain_quat,
75
+ J_reg,
76
+ W,
77
+ pgain_null,
78
+ dgain_null,
79
+ rest_posture,
80
+ ):
81
+
82
+ self.pgain_pos = pgain_pos
83
+ self.dgain = dgain
84
+ self.pgain_quat = pgain_quat
85
+ self.dgain_null = dgain_null
86
+ self.J_reg = J_reg
87
+ self.W = W
88
+
89
+ self.rest_posture = rest_posture
90
+ self.pgain_null = pgain_null
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/IKControllers.py ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from abc import abstractmethod
2
+ import logging
3
+
4
+ import numpy as np
5
+
6
+ import d3il.environments.d3il.d3il_sim.controllers.GainsInterface as gains
7
+ import d3il.environments.d3il.d3il_sim.utils as utils
8
+ from d3il.environments.d3il.d3il_sim.controllers.Controller import TrackingController
9
+
10
+
11
+ class CartPosImpedenceController(TrackingController, gains.CartPosControllerConfig):
12
+
13
+ def __init__(self):
14
+
15
+ TrackingController.__init__(self, dimSetPoint=3)
16
+ gains.CartPosControllerConfig.__init__(self)
17
+
18
+ self.J_reg = 1e-6
19
+ self.W = np.diag([1, 1, 1, 1, 1, 1, 1])
20
+
21
+ self.target_th_null = np.array(
22
+ [
23
+ 3.57795216e-09,
24
+ 1.74532920e-01,
25
+ 3.30500960e-08,
26
+ -8.72664630e-01,
27
+ -1.14096181e-07,
28
+ 1.22173047e00,
29
+ 7.85398126e-01,
30
+ ]
31
+ )
32
+
33
+ self.reset()
34
+
35
+ def reset(self):
36
+ self.desired_c_pos = np.array([0.624, 0, 0.55])
37
+ self.desired_c_vel = np.zeros((3,))
38
+ self.desired_c_acc = np.zeros((3,))
39
+
40
+ def getControl(self, robot):
41
+
42
+ self.paramsLock.acquire()
43
+ xd_d = self.desired_c_pos - robot.current_c_pos
44
+ target_c_acc = self.pgain * xd_d
45
+
46
+ J = robot.getJacobian()
47
+ J = J[:3, :]
48
+ Jw = J.dot(self.W)
49
+
50
+ JwJ_reg = Jw.dot(J.T) + self.J_reg * np.eye(3)
51
+
52
+ qd_null = self.pgain_null * (self.target_th_null - robot.current_j_pos)
53
+
54
+ qd_d = np.linalg.solve(JwJ_reg, target_c_acc - J.dot(qd_null))
55
+ qd_d = self.W.dot(J.transpose()).dot(qd_d) + qd_null
56
+
57
+ robot.des_c_pos = self.desired_c_pos
58
+ robot.des_c_vel = self.desired_c_vel
59
+
60
+ robot.jointTrackingController.setSetPoint(robot.current_j_pos, qd_d)
61
+ self.paramsLock.release()
62
+
63
+ return robot.jointTrackingController.getControl(robot)
64
+
65
+ def setGains(self, pGain, dGain):
66
+
67
+ self.paramsLock.acquire()
68
+ self.pgain = pGain
69
+ self.dgain = dGain
70
+ self.paramsLock.release()
71
+
72
+ def setSetPoint(self, desired_pos, desired_vel=None, desired_acc=None):
73
+
74
+ self.paramsLock.acquire()
75
+ self.desired_c_pos = desired_pos
76
+ if desired_vel is not None:
77
+ self.desired_c_vel = desired_vel
78
+ if desired_acc is not None:
79
+ self.desired_c_acc = desired_acc
80
+ self.paramsLock.release()
81
+
82
+ def getCurrentPos(self, robot):
83
+
84
+ return robot.current_c_pos
85
+
86
+ def getDesiredPos(self, robot):
87
+ return robot.des_c_pos
88
+
89
+
90
+ class CartesianPositionController(CartPosImpedenceController):
91
+ def setAction(self, action):
92
+ self.desired_c_pos = action
93
+
94
+ @abstractmethod
95
+ def reset(self):
96
+ pass
97
+
98
+
99
+ class CartPosQuatImpedenceController(
100
+ TrackingController, gains.CartPosQuatControllerConfig
101
+ ):
102
+
103
+ def __init__(self):
104
+
105
+ TrackingController.__init__(self, dimSetPoint=7)
106
+ gains.CartPosQuatControllerConfig.__init__(self)
107
+ self.W = np.diag(self.W)
108
+ self.dgain_null = np.sqrt(self.pgain_null) * 2
109
+
110
+ self.reset()
111
+ self.neglect_dynamics = False
112
+
113
+ def reset(self):
114
+ self.desired_c_pos = np.array([0.624, 0, 0.55])
115
+ self.desired_quat = np.array([0.0, 0.984, 0, 0.177])
116
+ self.desired_quat = self.desired_quat / np.linalg.norm(self.desired_quat)
117
+ self.desired_c_vel = np.zeros((3,))
118
+ self.desired_quat_vel = np.zeros((4,))
119
+
120
+ self.old_des_joint_vel = np.zeros((7,))
121
+ self.old_q = np.zeros((7,))
122
+ self.old_q[:] = np.nan
123
+
124
+ def getControl(self, robot):
125
+
126
+ self.paramsLock.acquire()
127
+ super(CartPosQuatImpedenceController, self).getControl(robot)
128
+
129
+ if any(np.isnan(self.old_q)):
130
+ self.old_q = robot.current_j_pos.copy()
131
+
132
+ q = self.old_q.copy()
133
+
134
+ q = (
135
+ self.joint_filter_coefficient * q
136
+ + (1 - self.joint_filter_coefficient) * robot.current_j_pos
137
+ )
138
+
139
+ qd_dsum = np.zeros(q.shape)
140
+
141
+ oldErrorNorm = np.inf
142
+ qd_d = np.zeros(q.shape)
143
+
144
+ [current_c_pos, current_c_quat] = robot.getForwardKinematics(q)
145
+ target_cpos_acc = self.desired_c_pos - current_c_pos
146
+
147
+ curr_quat = current_c_quat
148
+
149
+ if np.linalg.norm(curr_quat - self.desired_quat) > np.linalg.norm(
150
+ curr_quat + self.desired_quat
151
+ ):
152
+ curr_quat = -curr_quat
153
+ oldErrorNorm = np.sum(target_cpos_acc**2) + np.sum(
154
+ (curr_quat - self.desired_quat) ** 2
155
+ )
156
+
157
+ des_quat = self.desired_quat
158
+ for i in range(self.num_iter):
159
+
160
+ [current_c_pos, current_c_quat] = robot.getForwardKinematics(q)
161
+ target_cpos_acc = self.desired_c_pos - current_c_pos
162
+
163
+ curr_quat = current_c_quat
164
+
165
+ if np.linalg.norm(curr_quat - des_quat) > np.linalg.norm(
166
+ curr_quat + des_quat
167
+ ):
168
+ des_quat = -des_quat
169
+ errNorm = np.sum(target_cpos_acc**2) + np.sum((curr_quat - des_quat) ** 2)
170
+
171
+ target_cquat = utils.get_quaternion_error(curr_quat, des_quat)
172
+
173
+ target_cpos_acc = np.clip(target_cpos_acc, -0.01, 0.01)
174
+ target_cquat = np.clip(target_cquat, -0.1, 0.1)
175
+
176
+ target_c_acc = np.hstack(
177
+ (self.pgain_pos * target_cpos_acc, self.pgain_quat * target_cquat)
178
+ )
179
+
180
+ J = robot.getJacobian(q)
181
+
182
+ Jw = J.dot(self.W)
183
+
184
+ condNumber = np.linalg.cond(Jw.dot(J.T))
185
+ JwJ_reg = Jw.dot(J.T) + self.J_reg * np.eye(J.shape[0])
186
+
187
+ u, s, v = np.linalg.svd(JwJ_reg, full_matrices=False)
188
+ s_orig = s
189
+ s = np.clip(s, self.min_svd_values, self.max_svd_values)
190
+ JwJ_reg = u @ np.diag(s) @ v
191
+ condNumber2 = np.linalg.cond(JwJ_reg)
192
+ largestSV = np.max(s_orig)
193
+
194
+ qdev_rest = np.clip(self.rest_posture - q, -0.2, 0.2)
195
+
196
+ qd_null = np.array(self.pgain_null * (qdev_rest))
197
+
198
+ margin_to_limit = 0.01
199
+ pgain_limit = 20
200
+
201
+ qd_null_limit = np.zeros(qd_null.shape)
202
+ qd_null_limit_max = pgain_limit * (
203
+ robot.joint_pos_max - margin_to_limit - q
204
+ )
205
+ qd_null_limit_min = pgain_limit * (
206
+ robot.joint_pos_min + margin_to_limit - q
207
+ )
208
+ qd_null_limit[
209
+ q > robot.joint_pos_max - margin_to_limit
210
+ ] += qd_null_limit_max[q > robot.joint_pos_max - margin_to_limit]
211
+ qd_null_limit[
212
+ q < robot.joint_pos_min + margin_to_limit
213
+ ] += qd_null_limit_min[q < robot.joint_pos_min + margin_to_limit]
214
+
215
+ qd_d = np.linalg.solve(JwJ_reg, target_c_acc - J.dot(qd_null))
216
+ qd_d = self.W.dot(J.transpose()).dot(qd_d) + qd_null
217
+
218
+ if np.linalg.norm(qd_d) > 3:
219
+ qd_d = qd_d * 3 / np.linalg.norm(qd_d)
220
+
221
+ qd_dsum = qd_dsum + qd_d
222
+
223
+ q = q + self.learningRate * qd_d
224
+ q = np.clip(q, robot.joint_pos_min, robot.joint_pos_max)
225
+
226
+ self.tracking_error = np.sum(np.abs(self.desired_c_pos - current_c_pos)) > 0.01
227
+
228
+ qd_dsum = (q - self.old_q) / robot.dt
229
+ des_acc = self.ddgain * (qd_dsum - self.old_des_joint_vel) / robot.dt
230
+
231
+ if np.sum(np.abs(self.desired_c_pos - current_c_pos)) > 0.1:
232
+ target_cquat = utils.get_quaternion_error(curr_quat, self.desired_quat)
233
+
234
+ logging.getLogger(__name__).debug(
235
+ "i: %d, Time: %f, Pos_error: %f, Quat_error: %f, qd_d: %f"
236
+ % (
237
+ i,
238
+ robot.time_stamp,
239
+ np.linalg.norm(self.desired_c_pos - current_c_pos),
240
+ np.linalg.norm(target_cquat),
241
+ np.linalg.norm(qd_d),
242
+ ),
243
+ qd_d,
244
+ self.desired_c_pos,
245
+ des_acc,
246
+ )
247
+
248
+ if np.linalg.norm(des_acc) > 10000:
249
+ des_acc = des_acc * 10000 / np.linalg.norm(des_acc)
250
+
251
+ robot.jointTrackingController.setSetPoint(q, qd_dsum, des_acc)
252
+
253
+ self.old_q = q.copy()
254
+ self.old_des_joint_vel = qd_dsum
255
+
256
+ robot.des_c_pos = self.desired_c_pos
257
+ robot.des_c_vel = self.desired_c_vel
258
+ robot.des_quat = self.desired_quat
259
+ robot.des_quat_vel = self.desired_quat_vel
260
+ robot.misc_data = np.array([errNorm, condNumber, condNumber2, largestSV])
261
+
262
+ self.paramsLock.release()
263
+
264
+ if self.neglect_dynamics:
265
+ robot.beam_to_joint_pos(q, resetDesired=False)
266
+ return np.zeros((7,))
267
+ else:
268
+ control = robot.jointTrackingController.getControl(robot)
269
+
270
+ return control
271
+
272
+ def setSetPoint(self, desired_pos, desired_vel=None, desired_acc=None):
273
+
274
+ self.paramsLock.acquire()
275
+ self.desired_c_pos = desired_pos[:3].copy()
276
+ self.desired_quat = desired_pos[3:] / np.linalg.norm(desired_pos[3:])
277
+ if desired_vel is not None:
278
+ self.desired_c_vel = desired_vel[:3]
279
+ self.desired_quat_vel = desired_vel[3:]
280
+
281
+ self.paramsLock.release()
282
+
283
+ def getCurrentPos(self, robot):
284
+
285
+ return np.hstack((robot.current_c_pos, robot.current_c_quat))
286
+
287
+ def getDesiredPos(self, robot):
288
+ return np.concatenate((robot.des_c_pos, robot.des_quat))
289
+
290
+
291
+ class CartVelocityImpedenceController(CartPosQuatImpedenceController):
292
+
293
+ def __init__(self, fixed_orientation=None, max_cart_vel=0.5):
294
+
295
+ super(CartVelocityImpedenceController, self).__init__()
296
+ self.fixed_orientation = fixed_orientation
297
+ self.max_cart_vel = max_cart_vel
298
+
299
+ self.max_cart_pos = np.array([0.7, 0.4, 0.75])
300
+ self.min_cart_pos = np.array([0.2, -0.4, 0.0])
301
+
302
+ def getControl(self, robot):
303
+
304
+ self.desired_c_pos = np.array(robot.current_c_pos) + robot.dt * np.array(
305
+ self.desired_c_vel
306
+ )
307
+ self.desired_c_pos = np.clip(
308
+ self.desired_c_pos, self.min_cart_pos, self.max_cart_pos
309
+ )
310
+
311
+ if self.fixed_orientation is None:
312
+ self.desired_quat = self.fixed_orientation
313
+ else:
314
+ self.desired_quat = self.fixed_orientation
315
+
316
+ return super(CartVelocityImpedenceController, self).getControl(robot)
317
+
318
+ def setSetPoint(self, desired_pos, desired_vel, desired_acc=None):
319
+
320
+ self.paramsLock.acquire()
321
+ self.desired_c_vel = desired_vel[:3]
322
+ if self.fixed_orientation is None:
323
+ self.desired_quat_vel = desired_vel[3:]
324
+
325
+ self.paramsLock.release()
326
+
327
+
328
+ class CartPosQuatImpedenceJacTransposeController(
329
+ CartPosQuatImpedenceController, gains.CartPosQuatJacTransposeControllerConfig
330
+ ):
331
+ def __init__(self):
332
+ super(CartPosQuatImpedenceJacTransposeController, self).__init__()
333
+ gains.CartPosQuatJacTransposeControllerConfig.__init__(self)
334
+
335
+ def getControl(self, robot):
336
+ self.paramsLock.acquire()
337
+ qd_d = self.desired_c_pos - robot.current_c_pos
338
+ target_cpos_acc = self.pgain_pos * qd_d
339
+ curr_quat = (
340
+ -robot.current_c_quat
341
+ if (robot.current_c_quat @ self.desired_quat) < 0
342
+ else robot.current_c_quat
343
+ )
344
+ target_cquat = self.pgain_quat * utils.get_quaternion_error(
345
+ robot.current_c_quat, self.desired_quat
346
+ )
347
+ J = robot.getJacobian()
348
+
349
+ qd_null = self.pgain_null * (
350
+ self.rest_posture - robot.current_j_pos
351
+ ) + self.dgain_null * (-robot.current_j_vel)
352
+ target_acc = np.concatenate((target_cpos_acc, target_cquat))
353
+ qdd = J.T @ (target_acc - self.dgain * (J @ robot.current_j_vel)) + qd_null
354
+ robot.des_c_pos = self.desired_c_pos
355
+ robot.des_c_vel = self.desired_c_vel
356
+ robot.des_quat = self.desired_quat
357
+ robot.des_quat_vel = self.desired_quat_vel
358
+ self.paramsLock.release()
359
+ return qdd
360
+
361
+
362
+ class CartPosQuatCartesianRobotController(TrackingController):
363
+ def __init__(self):
364
+ TrackingController.__init__(self, dimSetPoint=7)
365
+ self.reset()
366
+
367
+ def reset(self):
368
+ self.desired_pos = np.zeros((self.dimSetPoint,))
369
+
370
+ def setAction(self, action):
371
+ self.desired_pos = action
372
+
373
+ def setSetPoint(self, desired_pos, desired_vel=None, desired_acc=None):
374
+ self.desired_pos = desired_pos
375
+
376
+ def getControl(self, robot):
377
+ robot.des_c_pos = self.desired_pos[:3]
378
+ robot.des_c_vel = np.zeros((3,))
379
+ if self.desired_pos.shape[0] > 3:
380
+ robot.des_quat = self.desired_pos[3:]
381
+ robot.des_quat_vel = np.zeros((4,))
382
+
383
+ return self.desired_pos
384
+
385
+ def getCurrentPos(self, robot):
386
+ return np.hstack((robot.current_c_pos, robot.current_c_quat))
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/TrajectoryTracking.py ADDED
@@ -0,0 +1,416 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+
3
+ import numpy as np
4
+ from scipy.interpolate import make_interp_spline
5
+
6
+ import d3il.environments.d3il.d3il_sim.utils as utils
7
+ from d3il.environments.d3il.d3il_sim.controllers import ControllerBase
8
+
9
+
10
+ class TrajectoryGenerator:
11
+ def __init__(self):
12
+ pass
13
+
14
+ def generate_trajectory(self, trackingController, robot, duration):
15
+ pass
16
+
17
+ def setDesiredPos(self, desiredPos):
18
+ pass
19
+
20
+
21
+ class TrajectoryTracker(ControllerBase):
22
+
23
+ def __init__(self, dt, trajectory_generator=None):
24
+ ControllerBase.__init__(self)
25
+
26
+ self.trajectory_generator = trajectory_generator
27
+ self.startingTime = None
28
+ self.trajectory = None
29
+ self.trajectoryVel = None
30
+ self.trajectoryAcc = None
31
+ self.dt = dt
32
+ self.additionalDuration = 0
33
+ self.delay_trajectory = 0
34
+ self.old_time_stamp = None
35
+ self.delay_trajectory_on_error = False
36
+
37
+ def initController(self, robot, maxDuration):
38
+
39
+ self.get_tracking_controller(robot).initController(robot, maxDuration)
40
+ self.startingTime = robot.time_stamp
41
+ self.duration = maxDuration
42
+ self.delay_trajectory = 0
43
+ self.old_time_stamp = robot.time_stamp
44
+ if self.trajectory_generator is not None:
45
+ self.setTrajectory(
46
+ self.trajectory_generator.generate_trajectory(
47
+ self.get_tracking_controller(robot), robot, maxDuration
48
+ )
49
+ )
50
+
51
+ self.set_point_for_time_step(robot, 0)
52
+
53
+ def get_tracking_controller(self, robot):
54
+ pass
55
+
56
+ def setAction(self, action):
57
+ if action.ndim == 1:
58
+ self.setDesiredPos(action)
59
+ else:
60
+ self.setTrajectory(action)
61
+
62
+ def setDesiredPos(self, desiredPosition):
63
+ self.trajectory_generator.setDesiredPos(desiredPosition)
64
+
65
+ def set_point_for_time_step(self, robot, timeStep):
66
+ desired_pos = self.trajectory[timeStep, :]
67
+
68
+ if timeStep < self.trajectory.shape[0] - 1:
69
+ desired_vel = self.trajectoryVel[timeStep, :]
70
+ else:
71
+ desired_vel = np.zeros((self.trajectory.shape[1],))
72
+
73
+ if timeStep < self.trajectory.shape[0] - 2:
74
+ desired_acc = self.trajectoryAcc[timeStep, :]
75
+ else:
76
+ desired_acc = np.zeros((self.trajectory.shape[1],))
77
+
78
+ self.get_tracking_controller(robot).setSetPoint(
79
+ desired_pos, desired_vel, desired_acc
80
+ )
81
+
82
+ def getControl(self, robot):
83
+ if self.trajectory is None:
84
+ logging.getLogger(__name__).warning("Error: Trajectory is empty")
85
+
86
+ self.paramsLock.acquire()
87
+
88
+ if (
89
+ self.delay_trajectory_on_error
90
+ and self.get_tracking_controller(robot).tracking_error
91
+ ):
92
+ self.delay_trajectory += robot.time_stamp - self.old_time_stamp
93
+ self.old_time_stamp = robot.time_stamp
94
+
95
+ timeStep = np.round(
96
+ (robot.time_stamp - self.startingTime - self.delay_trajectory) / self.dt
97
+ )
98
+
99
+ timeStep = int(np.min([timeStep, self.trajectory.shape[0] - 1]))
100
+
101
+ self.set_point_for_time_step(robot, timeStep)
102
+
103
+ self.paramsLock.release()
104
+
105
+ return self.get_tracking_controller(robot).getControl(robot)
106
+
107
+ def setTrajectory(self, trajectory):
108
+
109
+ self.paramsLock.acquire()
110
+
111
+ self.trajectory = trajectory
112
+ self.trajectoryVel = np.diff(trajectory, 1, axis=0) / self.dt
113
+ self.trajectoryAcc = np.diff(trajectory, 2, axis=0) / (self.dt**2)
114
+
115
+ self.paramsLock.release()
116
+
117
+ def resetTrajectory(self):
118
+
119
+ self.trajectory = None
120
+
121
+
122
+ class JointTrajectoryTracker(TrajectoryTracker):
123
+
124
+ def __init__(self, dt, trajectory_generator=None):
125
+ TrajectoryTracker.__init__(self, dt, trajectory_generator)
126
+
127
+ def get_tracking_controller(self, robot):
128
+ return robot.jointTrackingController
129
+
130
+
131
+ class CartPosTrajectoryTracker(TrajectoryTracker):
132
+
133
+ def __init__(self, dt, trajectory_generator=None):
134
+ TrajectoryTracker.__init__(self, dt, trajectory_generator)
135
+
136
+ def get_tracking_controller(self, robot):
137
+ return robot.cartesianPosTrackingController
138
+
139
+
140
+ class CartPosQuatTrajectoryTracker(TrajectoryTracker):
141
+
142
+ def __init__(self, dt, trajectory_generator=None):
143
+ TrajectoryTracker.__init__(self, dt, trajectory_generator)
144
+
145
+ def get_tracking_controller(self, robot):
146
+ return robot.cartesianPosQuatTrackingController
147
+
148
+
149
+ class GotoTrajectoryBase(TrajectoryGenerator):
150
+ def __init__(self):
151
+
152
+ TrajectoryGenerator.__init__(self)
153
+
154
+ self.desiredPosition = np.array([0, 0, 0, -1.562, 0, 1.914, 0])
155
+
156
+ def get_init_pos(self, trackingController, robot):
157
+
158
+ cur_state = trackingController.getCurrentPos(robot)
159
+ des_state = trackingController.getDesiredPos(robot)
160
+ if (
161
+ robot.smooth_spline
162
+ and not any(np.isnan(des_state))
163
+ and not trackingController.tracking_error
164
+ and trackingController.is_used(robot)
165
+ ):
166
+ cur_state = des_state
167
+ return cur_state
168
+
169
+ def setDesiredPos(self, desiredPosition):
170
+
171
+ self.desiredPosition = desiredPosition
172
+
173
+
174
+ class GotoTrajectorySpline(GotoTrajectoryBase):
175
+
176
+ def __init__(self):
177
+
178
+ GotoTrajectoryBase.__init__(self)
179
+
180
+ def generate_trajectory(self, trackingController, robot, duration):
181
+
182
+ super().generate_trajectory(trackingController, robot, duration)
183
+
184
+ cur_state = self.get_init_pos(trackingController, robot)
185
+
186
+ time = np.linspace(0, duration, int(duration / robot.dt) + 1)
187
+ trajectory = np.zeros((time.shape[0], trackingController.dimSetPoint))
188
+
189
+ for i in range(trackingController.dimSetPoint):
190
+ try:
191
+ l, r = [(1, 0.0), (2, 0.0)], [(1, 0.0), (2, 0.0)]
192
+ bsplinef = make_interp_spline(
193
+ x=[0, duration],
194
+ y=[cur_state[i], self.desiredPosition[i]],
195
+ bc_type=(l, r),
196
+ k=5,
197
+ )
198
+ trajectory[:, i] = bsplinef(time)
199
+ except ValueError:
200
+ raise ValueError(
201
+ "Robot might be already be at this configuration.\nDesired Pos: {}\nCurrent Pos: {}".format(
202
+ self.desiredPosition[i], cur_state[i]
203
+ )
204
+ )
205
+ return trajectory
206
+
207
+
208
+ class GotoTrajectoryLinear(GotoTrajectoryBase):
209
+
210
+ def __init__(self):
211
+
212
+ GotoTrajectoryBase.__init__(self)
213
+
214
+ def generate_trajectory(self, trackingController, robot, duration):
215
+
216
+ super().generate_trajectory(trackingController, robot, duration)
217
+
218
+ cur_state = self.get_init_pos(trackingController, robot)
219
+
220
+ time = np.linspace(0, duration, int(duration / robot.dt) + 1)
221
+ trajectory = np.zeros((time.shape[0], trackingController.dimSetPoint))
222
+
223
+ for i in range(trackingController.dimSetPoint):
224
+ trajectory[:, i] = np.linspace(
225
+ cur_state[i], self.desiredPosition[i], int(duration / robot.dt) + 1
226
+ )
227
+
228
+ trajectory = trajectory[1:, :]
229
+ return trajectory
230
+
231
+
232
+ class OfflineIKTrajectoryGenerator(TrajectoryGenerator):
233
+ def __init__(self, interpolation_trajectory=None):
234
+ TrajectoryGenerator.__init__(self)
235
+
236
+ self.desiredTaskPosition = np.zeros(
237
+ 7,
238
+ )
239
+ self.J_reg = 1e-6
240
+ self.W = np.diag([1, 1, 1, 1, 1, 1, 1])
241
+ self.target_th_null = np.array(
242
+ [
243
+ 3.57795216e-09,
244
+ 1.74532920e-01,
245
+ 3.30500960e-08,
246
+ -8.72664630e-01,
247
+ -1.14096181e-07,
248
+ 1.22173047e00,
249
+ 7.85398126e-01,
250
+ ]
251
+ )
252
+ if interpolation_trajectory is None:
253
+ self.interpolation_trajectory = GotoTrajectorySpline()
254
+ else:
255
+ self.interpolation_trajectory = interpolation_trajectory
256
+
257
+ def generate_trajectory(self, trackingController, robot, duration):
258
+
259
+ eps = 1e-5
260
+ IT_MAX = 1000
261
+ DT = 1e-3
262
+
263
+ i = 0
264
+ self.pgain = [
265
+ 33.9403713446798,
266
+ 30.9403713446798,
267
+ 33.9403713446798,
268
+ 27.69370238555632,
269
+ 33.98706171459314,
270
+ 30.9185531893281,
271
+ ]
272
+ self.pgain_null = 5 * np.array(
273
+ [
274
+ 7.675519770796831,
275
+ 2.676935478437176,
276
+ 8.539040163444975,
277
+ 1.270446361314313,
278
+ 8.87752182480855,
279
+ 2.186782233762969,
280
+ 4.414432577659688,
281
+ ]
282
+ )
283
+ self.pgain_limit = 20
284
+
285
+ q = robot.current_j_pos.copy()
286
+ qd_d = np.zeros(q.shape)
287
+ oldErrNorm = np.inf
288
+ while True:
289
+ oldQ = q
290
+ q = q + DT * qd_d
291
+
292
+ q = np.clip(q, robot.joint_pos_min, robot.joint_pos_max)
293
+
294
+ cartPos, orient = robot.getForwardKinematics(q)
295
+ cpos_err = self.desiredTaskPosition[:3] - cartPos
296
+
297
+ if np.linalg.norm(orient - self.desiredTaskPosition[3:]) > np.linalg.norm(
298
+ orient + self.desiredTaskPosition[3:]
299
+ ):
300
+ orient = -orient
301
+
302
+ cpos_err = np.clip(cpos_err, -0.1, 0.1)
303
+ cquat_err = np.clip(
304
+ utils.get_quaternion_error(orient, self.desiredTaskPosition[3:]),
305
+ -0.5,
306
+ 0.5,
307
+ )
308
+ err = np.hstack((cpos_err, cquat_err))
309
+
310
+ errNorm = np.sum(cpos_err**2) + np.sum(
311
+ (orient - self.desiredTaskPosition[3:]) ** 2
312
+ )
313
+ if errNorm > oldErrNorm:
314
+ q = oldQ
315
+ DT = DT * 0.7
316
+ continue
317
+ else:
318
+ DT = DT * 1.025
319
+
320
+ if errNorm < eps:
321
+ success = True
322
+ break
323
+ if i >= IT_MAX:
324
+ success = False
325
+ break
326
+
327
+ oldErrNorm = errNorm
328
+
329
+ J = robot.getJacobian(q)
330
+
331
+ Jw = J.dot(self.W)
332
+
333
+ JwJ_reg = Jw.dot(J.T) + self.J_reg * np.eye(J.shape[0])
334
+
335
+ qd_null = self.pgain_null * (self.target_th_null - q)
336
+
337
+ margin_to_limit = 0.1
338
+ qd_null_limit = np.zeros(qd_null.shape)
339
+ qd_null_limit_max = self.pgain_limit * (
340
+ robot.joint_pos_max - margin_to_limit - q
341
+ )
342
+ qd_null_limit_min = self.pgain_limit * (
343
+ robot.joint_pos_min + margin_to_limit - q
344
+ )
345
+ qd_null_limit[
346
+ q > robot.joint_pos_max - margin_to_limit
347
+ ] += qd_null_limit_max[q > robot.joint_pos_max - margin_to_limit]
348
+ qd_null_limit[
349
+ q < robot.joint_pos_min + margin_to_limit
350
+ ] += qd_null_limit_min[q < robot.joint_pos_min + margin_to_limit]
351
+
352
+ qd_null += qd_null_limit
353
+ qd_d = np.linalg.solve(JwJ_reg, self.pgain * err - J.dot(qd_null))
354
+ qd_d = self.W.dot(J.transpose()).dot(qd_d) + qd_null
355
+
356
+ i += 1
357
+
358
+ print("Final IK error (%d iterations): %s" % (i, errNorm))
359
+
360
+ logging.getLogger(__name__).debug(
361
+ "Final IK error (%d iterations): %s" % (i, errNorm)
362
+ )
363
+ self.interpolation_trajectory.setDesiredPos(q)
364
+ return self.interpolation_trajectory.generate_trajectory(
365
+ trackingController, robot, duration
366
+ )
367
+
368
+ def setDesiredPos(self, desiredTaskPosition):
369
+
370
+ self.desiredTaskPosition = desiredTaskPosition
371
+
372
+
373
+ class GotoCartPosQuatOfflineIKController(JointTrajectoryTracker):
374
+ def __init__(self, dt):
375
+ super(JointTrajectoryTracker, self).__init__(
376
+ dt, trajectory_generator=OfflineIKTrajectoryGenerator()
377
+ )
378
+
379
+
380
+ class GotoJointController(JointTrajectoryTracker):
381
+ def __init__(self, dt):
382
+ super(JointTrajectoryTracker, self).__init__(
383
+ dt, trajectory_generator=GotoTrajectorySpline()
384
+ )
385
+
386
+
387
+ class GotoCartPosImpedanceController(CartPosTrajectoryTracker):
388
+ def __init__(self, dt):
389
+ super(CartPosTrajectoryTracker, self).__init__(
390
+ dt, trajectory_generator=GotoTrajectorySpline()
391
+ )
392
+
393
+
394
+ class GotoCartPosQuatImpedanceController(CartPosQuatTrajectoryTracker):
395
+ def __init__(self, dt):
396
+ super(CartPosQuatTrajectoryTracker, self).__init__(
397
+ dt, trajectory_generator=GotoTrajectorySpline()
398
+ )
399
+
400
+
401
+ class GotoCartPosCartesianRobotController(JointTrajectoryTracker):
402
+
403
+ def __init__(self, dt):
404
+ assert False
405
+ super(JointTrajectoryTracker, self).__init__(
406
+ dt, trajectory_generator=GotoTrajectory()
407
+ )
408
+
409
+
410
+ class GotoCartPosQuatCartesianRobotController(JointTrajectoryTracker):
411
+
412
+ def __init__(self, dt):
413
+ assert False
414
+ super(JointTrajectoryTracker, self).__init__(
415
+ dt, trajectory_generator=GotoTrajectory()
416
+ )
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from .Controller import *
2
+ from .IKControllers import *
3
+ from .TrajectoryTracking import *
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/controllers/executor.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+
4
+ def execute_controller(
5
+ robots: list,
6
+ controllers: list,
7
+ max_duration: float = 4.0,
8
+ ):
9
+ start_times = [rb.time_stamp for rb in robots]
10
+ robot_ctrl_matches = list(zip(robots, controllers, start_times))
11
+
12
+ for rb, ctrl, _ in robot_ctrl_matches:
13
+ ctrl.initController(rb, max_duration)
14
+
15
+ while (
16
+ not np.all([ctrl.isFinished(rb) for rb, ctrl, _ in robot_ctrl_matches])
17
+ ) and (
18
+ np.all([rb.time_stamp - st < max_duration for rb, _, st in robot_ctrl_matches])
19
+ ):
20
+ for rb, ctrl, _ in robot_ctrl_matches:
21
+ ctrl_action = ctrl.getControl(rb)
22
+ rb.command = ctrl_action
23
+
24
+ robots[0].nextStep()
25
+
26
+ for rb in robots:
27
+ rb.hold_joint_position()
28
+
29
+
30
+ def execute_controller_timesteps(
31
+ robots: list,
32
+ controllers: list,
33
+ time_steps: int = 10,
34
+ ):
35
+ robot_ctrl_matches = list(zip(robots, controllers))
36
+
37
+ for rb, ctrl in robot_ctrl_matches:
38
+ ctrl.initController(rb, time_steps * rb.dt)
39
+
40
+ for i in range(time_steps):
41
+ for rb, ctrl in robot_ctrl_matches:
42
+ ctrl_action = ctrl.getControl(rb)
43
+ rb.command = ctrl_action
44
+
45
+ robots[0].nextStep()
46
+
47
+ for rb in robots:
48
+ rb.hold_joint_position()
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/Camera.py ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from abc import ABC, abstractmethod
2
+ from typing import Optional, Tuple
3
+
4
+ import cv2
5
+ import numpy as np
6
+
7
+ from d3il.environments.d3il.d3il_sim.core.sim_object.sim_object import (
8
+ IntelligentSimObject,
9
+ )
10
+
11
+
12
+ class Camera(IntelligentSimObject, ABC):
13
+
14
+ def __init__(
15
+ self,
16
+ name: str,
17
+ width: int = 1000,
18
+ height: int = 1000,
19
+ init_pos=None,
20
+ init_quat=None,
21
+ near: float = 0.01,
22
+ far: float = 10,
23
+ fovy: int = 45,
24
+ *args,
25
+ **kwargs
26
+ ):
27
+
28
+ if init_pos is None:
29
+ init_pos = [0, 0, 0]
30
+ if init_quat is None:
31
+ init_quat = [0, 1, 0, 0]
32
+
33
+ super(Camera, self).__init__(name, init_pos, init_quat)
34
+ self.width = width
35
+ self.height = height
36
+
37
+ self.near = near
38
+ self.far = far
39
+ self.fovy = fovy
40
+ self.fovx = (
41
+ 2
42
+ * np.arctan(
43
+ self.width
44
+ * 0.5
45
+ / (self.height * 0.5 / np.tan(self.fovy * np.pi / 360 / 2))
46
+ )
47
+ / np.pi
48
+ * 360
49
+ )
50
+
51
+ self.fx = (self.width / 2) / (np.tan(self.fovx * np.pi / 180 / 2))
52
+ self.fy = (self.height / 2) / (np.tan(self.fovy * np.pi / 180 / 2))
53
+ self.cx = self.width / 2
54
+ self.cy = self.height / 2
55
+
56
+ self.intrinsics = np.array(
57
+ [[self.fx, 0, self.cx], [0, self.fy, self.cy], [0, 0, 1]]
58
+ )
59
+
60
+ def set_cam_params(
61
+ self,
62
+ width: Optional[int] = None,
63
+ height: Optional[int] = None,
64
+ near: Optional[float] = None,
65
+ far: Optional[float] = None,
66
+ fovy: Optional[int] = None,
67
+ ):
68
+
69
+ self.width = width or self.width
70
+ self.height = height or self.height
71
+
72
+ self.near = near or self.near
73
+ self.far = far or self.far
74
+ self.fovy = fovy or self.fovy
75
+ self.fovx = (
76
+ 2
77
+ * np.arctan(
78
+ self.width
79
+ * 0.5
80
+ / (self.height * 0.5 / np.tan(self.fovy * np.pi / 360 / 2))
81
+ )
82
+ / np.pi
83
+ * 360
84
+ )
85
+
86
+ self.fx = (self.width / 2) / (np.tan(self.fovx * np.pi / 180 / 2))
87
+ self.fy = (self.height / 2) / (np.tan(self.fovy * np.pi / 180 / 2))
88
+ self.cx = self.width / 2
89
+ self.cy = self.height / 2
90
+
91
+ self.intrinsics = np.array(
92
+ [[self.fx, 0, self.cx], [0, self.fy, self.cy], [0, 0, 1]]
93
+ )
94
+
95
+ def get_segmentation(
96
+ self, width: int = None, height: int = None, depth: bool = True
97
+ ) -> np.ndarray:
98
+
99
+ return self._get_img_data(
100
+ width=width, height=height, depth=depth, segmentation=True
101
+ )
102
+
103
+ def get_image(
104
+ self,
105
+ width: int = None,
106
+ height: int = None,
107
+ depth: bool = True,
108
+ denormalize_depth: bool = True,
109
+ ) -> np.ndarray:
110
+
111
+ return self._get_img_data(width, height, depth, denormalize_depth, False)
112
+
113
+ def calc_point_cloud(
114
+ self, width: int = None, height: int = None, denormalize: bool = True
115
+ ) -> Tuple[np.ndarray, np.ndarray]:
116
+
117
+ rgb_img, depth_img = self.get_image(
118
+ width, height, denormalize_depth=denormalize
119
+ )
120
+
121
+ return self.calc_point_cloud_from_images(rgb_img=rgb_img, depth_img=depth_img)
122
+
123
+ def calc_point_cloud_from_images(
124
+ self, rgb_img: np.ndarray, depth_img: np.ndarray
125
+ ) -> Tuple[np.ndarray, np.ndarray]:
126
+
127
+ true_width = rgb_img.shape[1]
128
+ true_height = rgb_img.shape[0]
129
+ if self.height == true_height and self.width == true_width:
130
+ fx = self.fx
131
+ fy = self.fy
132
+ cx = self.cx
133
+ cy = self.cy
134
+ else:
135
+ fx = (true_width / 2) / (np.tan(self.fovx * np.pi / 180 / 2))
136
+ fy = (true_height / 2) / (np.tan(self.fovy * np.pi / 180 / 2))
137
+ cx = true_width / 2
138
+ cy = true_height / 2
139
+
140
+ z = depth_img
141
+ u = np.arange(true_width) - cx
142
+ v = np.arange(true_height) - cy
143
+
144
+ x = (z * u) / fx
145
+ y = (z.T * v).T / fy
146
+
147
+ points = np.stack((x, y, z), axis=-1).reshape((true_width * true_height, 3))
148
+ colors = rgb_img.reshape((true_width * true_height, 3)) / 255.0
149
+
150
+ valid_points = ~np.isnan(points).any(axis=1)
151
+ points = points[valid_points]
152
+ colors = colors[valid_points]
153
+
154
+ return points, colors
155
+
156
+ def denormalize_depth(self, depth_img: np.ndarray) -> np.ndarray:
157
+
158
+ z = self.near / (1 - depth_img * (1 - self.near / self.far))
159
+ return z
160
+
161
+ def apply_noise(self, depth_img: np.ndarray) -> np.ndarray:
162
+
163
+ z = self.denormalize_depth(depth_img)
164
+
165
+ depth_img = depth_img + (
166
+ 0.0001 * np.power(z - 0.5, 2) + 0.0004
167
+ ) * np.random.rand(self.height, self.width)
168
+
169
+ depth_img = ((40000 * depth_img).astype(int) / 40000.0).astype(np.float32)
170
+
171
+ z = (
172
+ 2
173
+ * self.far
174
+ * self.near
175
+ / (self.far + self.near - (self.far - self.near) * (2 * depth_img - 1))
176
+ )
177
+
178
+ z = cv2.bilateralFilter(z, 5, 0.1, 5)
179
+
180
+ return z
181
+
182
+ def get_poi(self) -> list:
183
+
184
+ return [self.name]
185
+
186
+ @abstractmethod
187
+ def _get_img_data(
188
+ self,
189
+ width: int = None,
190
+ height: int = None,
191
+ depth: bool = True,
192
+ denormalize_depth: bool = True,
193
+ segmentation: bool = False,
194
+ ) -> np.ndarray:
195
+
196
+ pass
197
+
198
+ @abstractmethod
199
+ def get_cart_pos_quat(self) -> Tuple[np.ndarray, np.ndarray]:
200
+
201
+ pass
202
+
203
+ @property
204
+ def fov(self):
205
+ return self.fovy
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/Model.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import pinocchio
3
+
4
+ from d3il.environments.d3il.d3il_sim.utils.sim_path import d3il_path
5
+
6
+
7
+ class RobotKinematicsInterface:
8
+ def getForwardKinematics(self, q=None):
9
+ pass
10
+
11
+ def getJacobian(self, q=None):
12
+ pass
13
+
14
+
15
+ class RobotDynamicsInterface:
16
+ def get_gravity(self, q=None):
17
+ pass
18
+
19
+ def get_coriolis(self, q=None, qd=None):
20
+ pass
21
+
22
+ def get_mass_matrix(self, q=None):
23
+ pass
24
+
25
+
26
+ class RobotModelFromPinochio(RobotKinematicsInterface, RobotDynamicsInterface):
27
+ def __init__(self, obj_urdf="./models/common/robots/panda_arm_hand_pinocchio.urdf"):
28
+ obj_urdf = d3il_path(obj_urdf)
29
+ self.pin_model = pinocchio.buildModelFromUrdf(obj_urdf)
30
+ self.pin_data = self.pin_model.createData()
31
+
32
+ self.pin_end_effector_frame_id = self.pin_model.getFrameId("panda_grasptarget")
33
+
34
+ self.pin_q = np.zeros(self.pin_model.nv)
35
+ self.pin_qd = np.zeros(self.pin_model.nv)
36
+
37
+ def getForwardKinematics(self, q):
38
+
39
+ self.pin_q[:7] = q
40
+ pinocchio.framesForwardKinematics(self.pin_model, self.pin_data, self.pin_q)
41
+
42
+ current_c_pos = np.array(
43
+ self.pin_data.oMf[self.pin_end_effector_frame_id].translation
44
+ )
45
+
46
+ quat_pin = pinocchio.Quaternion(
47
+ self.pin_data.oMf[self.pin_end_effector_frame_id].rotation
48
+ ).coeffs()
49
+ current_c_quat = np.zeros(4)
50
+ current_c_quat[1:] = quat_pin[:3]
51
+ current_c_quat[0] = quat_pin[-1]
52
+
53
+ return current_c_pos, current_c_quat
54
+
55
+ def getJacobian(self, q):
56
+ self.pin_q[:7] = q
57
+
58
+ pinocchio.computeJointJacobians(self.pin_model, self.pin_data, self.pin_q)
59
+ pinocchio.framesForwardKinematics(self.pin_model, self.pin_data, self.pin_q)
60
+ return pinocchio.getFrameJacobian(
61
+ self.pin_model,
62
+ self.pin_data,
63
+ self.pin_end_effector_frame_id,
64
+ pinocchio.LOCAL_WORLD_ALIGNED,
65
+ )[:, :7]
66
+
67
+ def get_gravity(self, q=None):
68
+ self.pin_q[:7] = q
69
+
70
+ vq = np.zeros(self.pin_q.shape)
71
+ aq0 = np.zeros(self.pin_q.shape)
72
+
73
+ b = pinocchio.rnea(self.pin_model, self.pin_data, self.pin_q, vq, aq0)
74
+ return b[:7]
75
+
76
+ def get_coriolis(self, q, qd):
77
+ self.pin_q[:7] = q
78
+ self.pin_qd[:7] = qd
79
+
80
+ aq0 = np.zeros(self.pin_q.shape)
81
+
82
+ b = pinocchio.rnea(self.pin_model, self.pin_data, self.pin_q, self.pin_qd, aq0)
83
+ return b[:7] - self.get_gravity(q)
84
+
85
+ def get_mass_matrix(self, q):
86
+ if q.shape[0] == 7:
87
+ q_tmp = q.copy()
88
+ q = np.zeros(9)
89
+ q[:7] = q_tmp
90
+ M = pinocchio.crba(self.pin_model, self.pin_data, q)
91
+ return M[:7, :7]
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/Robots.py ADDED
@@ -0,0 +1,491 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from enum import Enum, auto
2
+
3
+ import numpy as np
4
+
5
+ import d3il.environments.d3il.d3il_sim.controllers as ctrl
6
+ import d3il.environments.d3il.d3il_sim.core.logger as logger
7
+ import d3il.environments.d3il.d3il_sim.core.Model as model
8
+ import d3il.environments.d3il.d3il_sim.core.time_keeper as time_keeper
9
+ import d3il.environments.d3il.d3il_sim.utils.geometric_transformation as geom_trans
10
+
11
+
12
+ class RobotControlInterface(Enum):
13
+ TorqueInterface = (auto(),)
14
+ CartesianInterface = auto()
15
+
16
+
17
+ class RobotBase:
18
+
19
+ def __init__(self, scene, dt, num_DoF=7, base_position=None, base_orientation=None):
20
+
21
+ self.scene = scene
22
+ self.dt = dt
23
+ self.num_DoF = num_DoF
24
+
25
+ self.inhand_cam = None
26
+
27
+ if base_position is None:
28
+ base_position = [0.0, 0.0, 0.0]
29
+ self.base_position = np.array(base_position)
30
+
31
+ if base_orientation is None:
32
+ base_orientation = [1.0, 0.0, 0.0, 0.0]
33
+ self.base_orientation = np.array(base_orientation)
34
+
35
+ self.misc_data = None
36
+
37
+ self.use_inv_dyn = False
38
+ self.gravity_comp = True
39
+ self.clip_rate = False
40
+
41
+ self.kinModel = model.RobotModelFromPinochio()
42
+ self.dynModel = self.kinModel
43
+
44
+ self.smooth_spline = True
45
+
46
+ self.torque_limit = np.array([80, 80, 80, 80, 10, 10, 10], dtype=np.float64)
47
+
48
+ self.joint_vel_limit = np.array([2.00, 2.00, 2.00, 2.00, 2.50, 2.50, 2.50])
49
+ self.joint_pos_min = np.array(
50
+ [-2.8973, -1.7628, -2.8973, -3.0718, -2.8973, -0.0175, -2.8973]
51
+ )
52
+ self.joint_pos_max = np.array(
53
+ [2.8973, 1.7628, 2.0, -0.0698, 2.8973, 3.7525, 2.8973]
54
+ )
55
+
56
+ self.clip_actions = True
57
+ self.rate_limit = 0.8
58
+ self.end_effector = None
59
+
60
+ self.jointTrackingController = ctrl.JointPDController()
61
+ self.cartesianPosTrackingController = ctrl.CartPosImpedenceController()
62
+ self.cartesianPosQuatTrackingController = ctrl.CartPosQuatImpedenceController()
63
+ self.activeController = self.jointTrackingController
64
+
65
+ self.jointPosController = ctrl.JointPositionController()
66
+ self.jointVelController = ctrl.JointVelocityController()
67
+ self.torqueController = ctrl.TorqueController()
68
+
69
+ self.gotoJointController = ctrl.GotoJointController(self.dt)
70
+
71
+ self.gotoCartPosController = ctrl.GotoCartPosQuatOfflineIKController(self.dt)
72
+ self.gotoCartPosQuatController = ctrl.GotoCartPosQuatOfflineIKController(
73
+ self.dt
74
+ )
75
+
76
+ self.gotoCartPosImpedanceController = ctrl.GotoCartPosImpedanceController(
77
+ self.dt
78
+ )
79
+ self.gotoCartPosQuatImpedanceController = (
80
+ ctrl.GotoCartPosQuatImpedanceController(self.dt)
81
+ )
82
+
83
+ self.jointTrajectoryTracker = ctrl.JointTrajectoryTracker(self.dt)
84
+ self.cartPosQuatTrajectoryTracker = ctrl.CartPosQuatTrajectoryTracker(self.dt)
85
+
86
+ self.controlInterface = RobotControlInterface.TorqueInterface
87
+
88
+ self.robot_logger = logger.RobotLogger(self)
89
+ self.time_keeper = time_keeper.TimeKeeper(self.dt)
90
+ self.additional_loggers = []
91
+
92
+ self.scene.add_robot(self)
93
+ self.reset()
94
+
95
+ def reset(self):
96
+
97
+ self.current_j_pos = np.zeros((self.num_DoF,)) * np.nan
98
+ self.current_j_vel = np.zeros((self.num_DoF,)) * np.nan
99
+ self.des_joint_pos = np.zeros((self.num_DoF,)) * np.nan
100
+ self.des_joint_vel = np.zeros((self.num_DoF,)) * np.nan
101
+ self.des_joint_acc = np.zeros((self.num_DoF,)) * np.nan
102
+
103
+ self.current_fing_pos = np.zeros((2,)) * np.nan
104
+ self.current_fing_vel = np.zeros((2,)) * np.nan
105
+ self.des_fing_pos = np.zeros(2) * np.nan
106
+ self.gripper_width = 0
107
+ self.set_gripper_width = 0.001
108
+ self.finger_commands = np.zeros((2,))
109
+ self.grasp_flag = False
110
+
111
+ self.current_c_pos = np.zeros((3,)) * np.nan
112
+ self.current_c_vel = np.zeros((3,)) * np.nan
113
+ self.current_c_quat = np.zeros((4,)) * np.nan
114
+ self.current_c_quat_vel = np.zeros((4,)) * np.nan
115
+ self.des_c_pos = np.zeros((3,)) * np.nan
116
+ self.des_c_vel = np.zeros((3,)) * np.nan
117
+ self.des_quat = np.zeros((4,)) * np.nan
118
+ self.des_quat_vel = np.zeros((4,)) * np.nan
119
+
120
+ self.current_c_pos_global = np.zeros((3,)) * np.nan
121
+ self.current_c_vel_global = np.zeros((3,)) * np.nan
122
+ self.current_c_quat_global = np.zeros((4,)) * np.nan
123
+ self.current_c_quat_vel_global = np.zeros((4,)) * np.nan
124
+ self.des_c_pos_global = np.zeros((3,)) * np.nan
125
+ self.des_c_vel_global = np.zeros((3,)) * np.nan
126
+ self.des_quat_global = np.zeros((4,)) * np.nan
127
+ self.des_quat_vel_global = np.zeros((4,)) * np.nan
128
+
129
+ self.uff = np.zeros((self.num_DoF + 2,))
130
+ self.uff_last = np.zeros((self.num_DoF + 2,))
131
+ self.last_cmd = np.zeros((self.num_DoF,))
132
+ self.command = np.zeros((self.num_DoF,))
133
+ self.grav_terms = np.zeros(9) * np.nan
134
+ self.current_load = np.zeros((self.num_DoF,))
135
+
136
+ self.robot_logger = logger.RobotLogger(self)
137
+ self.time_keeper = time_keeper.TimeKeeper(self.dt)
138
+
139
+ if self.gotoJointController is not None:
140
+ self.gotoJointController.resetTrajectory()
141
+
142
+ if self.gotoCartPosController is not None:
143
+ self.gotoCartPosController.resetTrajectory()
144
+ if self.gotoCartPosQuatController is not None:
145
+ self.gotoCartPosQuatController.resetTrajectory()
146
+ if self.gotoCartPosImpedanceController is not None:
147
+ self.gotoCartPosImpedanceController.resetTrajectory()
148
+ if self.gotoCartPosQuatImpedanceController is not None:
149
+ self.gotoCartPosQuatImpedanceController.resetTrajectory()
150
+
151
+ self.jointTrackingController = ctrl.JointPDController()
152
+
153
+ self.cartesianPosTrackingController.reset()
154
+ self.cartesianPosQuatTrackingController.reset()
155
+ self.activeController.reset()
156
+
157
+ def getForwardKinematics(self, q=None):
158
+ if q is None:
159
+ q = self.current_j_pos
160
+
161
+ return self.kinModel.getForwardKinematics(q)
162
+
163
+ def getJacobian(self, q=None):
164
+ if q is None:
165
+ q = self.current_j_pos
166
+
167
+ return self.kinModel.getJacobian(q)
168
+
169
+ def get_gravity(self, q=None):
170
+ if q is None:
171
+ q = self.current_j_pos
172
+
173
+ return self.dynModel.get_gravity(q)
174
+
175
+ def get_coriolis(self, q=None, qd=None):
176
+ if q is None:
177
+ q = self.current_j_pos
178
+
179
+ if qd is None:
180
+ qd = self.current_j_vel
181
+
182
+ return self.dynModel.get_coriolis(q, qd)
183
+
184
+ def get_mass_matrix(self, q=None):
185
+ if q is None:
186
+ q = self.current_j_pos
187
+ return self.dynModel.get_mass_matrix(q)
188
+
189
+ def start_logging(self, duration: float = 300.0, **kwargs):
190
+ self.robot_logger.start_logging(duration, **kwargs)
191
+
192
+ def stop_logging(self):
193
+ self.robot_logger.stop_logging()
194
+
195
+ def log_data(self):
196
+ self.robot_logger.log_data()
197
+
198
+ def hold_joint_position(self):
199
+ self.des_joint_pos = self.current_j_pos
200
+ self.command = None
201
+ self.activeController = self.jointTrackingController
202
+ self.jointTrackingController.setSetPoint(self.current_j_pos)
203
+
204
+ def gotoJointPosition(self, desiredPos, duration=4.0, block=True):
205
+
206
+ self.gotoJointController.setDesiredPos(desiredPos)
207
+ self.gotoJointController.executeController(self, duration, block=block)
208
+
209
+ def executeJointPosCtrlTimeStep(self, action, timeSteps=1, block=True):
210
+ self.jointPosController.setAction(action)
211
+ self.jointPosController.executeControllerTimeSteps(self, timeSteps, block=block)
212
+
213
+ def executeJointVelCtrlTimeStep(self, action, timeSteps=1, block=True):
214
+ self.jointVelController.setAction(action)
215
+ self.jointVelController.executeControllerTimeSteps(self, timeSteps, block=block)
216
+
217
+ def executeTorqueCtrlTimeStep(self, action, timeSteps=1, block=True):
218
+ self.torqueController.setAction(action)
219
+ self.torqueController.executeControllerTimeSteps(self, timeSteps, block=block)
220
+
221
+ def follow_JointTraj(self, desiredTraj, goto_start=True, block=True):
222
+
223
+ if goto_start:
224
+ if np.linalg.norm(self.current_j_pos - desiredTraj[0, :]) > 0.05:
225
+ self.gotoJointPosition(desiredTraj[0, :], 4.0)
226
+
227
+ self.jointTrajectoryTracker.setTrajectory(trajectory=desiredTraj)
228
+ self.jointTrajectoryTracker.executeController(
229
+ self, maxDuration=desiredTraj.shape[0] * self.dt, block=block
230
+ )
231
+
232
+ def gotoCartPosition_ImpedanceCtrl(
233
+ self, desiredPos, duration=4.0, global_coord=True, block=True
234
+ ):
235
+ if global_coord:
236
+ desiredPos = self._localize_cart_pos(desiredPos)
237
+
238
+ self.gotoCartPosImpedanceController.setDesiredPos(desiredPos)
239
+ self.gotoCartPosImpedanceController.executeController(
240
+ self, duration, block=block
241
+ )
242
+
243
+ def gotoCartPositionAndQuat_ImpedanceCtrl(
244
+ self, desiredPos, desiredQuat, duration=4.0, global_coord=True, block=True
245
+ ):
246
+ if global_coord:
247
+ desiredPos = self._localize_cart_pos(desiredPos)
248
+ desiredQuat = self._localize_cart_quat(desiredQuat)
249
+
250
+ self.gotoCartPosQuatImpedanceController.setDesiredPos(
251
+ np.hstack((desiredPos, desiredQuat))
252
+ )
253
+ self.gotoCartPosQuatImpedanceController.executeController(
254
+ self, duration, block=block
255
+ )
256
+
257
+ def gotoCartPosition(self, desiredPos, duration=4.0, global_coord=True, block=True):
258
+
259
+ if global_coord:
260
+ desiredPos = self._localize_cart_pos(desiredPos)
261
+ self.gotoCartPosController.setDesiredPos(desiredPos)
262
+ self.gotoCartPosController.executeController(self, duration, block=block)
263
+
264
+ def gotoCartPositionAndQuat(
265
+ self,
266
+ desiredPos,
267
+ desiredQuat,
268
+ duration=4.0,
269
+ global_coord=True,
270
+ block=True,
271
+ log=True,
272
+ ):
273
+
274
+ if global_coord:
275
+ desiredPos = self._localize_cart_pos(desiredPos)
276
+ desiredQuat = self._localize_cart_quat(desiredQuat)
277
+
278
+ self.gotoCartPosQuatController.setDesiredPos(
279
+ np.hstack((desiredPos, desiredQuat))
280
+ )
281
+ self.gotoCartPosQuatController.executeController(
282
+ self, duration, block=block, log=log
283
+ )
284
+
285
+ def follow_CartPositionAndQuatTraj(
286
+ self, desiredPos, desiredQuat, goto_start=True, global_coord=True, block=True
287
+ ):
288
+
289
+ if global_coord:
290
+ desiredPos = np.array([self._localize_cart_pos(p) for p in desiredPos])
291
+ desiredQuat = np.array([self._localize_cart_quat(q) for q in desiredQuat])
292
+
293
+ desiredTraj = np.hstack((desiredPos, desiredQuat))
294
+ duration = desiredTraj.shape[0] * self.dt
295
+
296
+ if goto_start:
297
+ is_position_far = (
298
+ np.linalg.norm(self.current_c_pos - desiredPos[0, :]) > 0.005
299
+ )
300
+ is_rotation_far = (
301
+ np.linalg.norm(self.current_c_quat - desiredQuat[0, :]) > 0.005
302
+ ) and (np.linalg.norm(self.current_c_quat + desiredQuat[0, :]) > 0.005)
303
+
304
+ if is_position_far or is_rotation_far:
305
+ self.gotoCartPositionAndQuat(
306
+ desiredPos=desiredPos[0, :],
307
+ desiredQuat=desiredQuat[0, :],
308
+ duration=4.0,
309
+ )
310
+
311
+ self.cartPosQuatTrajectoryTracker.setTrajectory(trajectory=desiredTraj)
312
+ self.cartPosQuatTrajectoryTracker.executeController(
313
+ self, maxDuration=duration, block=block
314
+ )
315
+
316
+ def _localize_cart_pos(self, pos):
317
+ if not np.any(self.base_position) and np.array_equal(
318
+ self.base_orientation, [1, 0, 0, 0]
319
+ ):
320
+ return pos
321
+
322
+ pos_vec = np.array(pos)
323
+
324
+ local_pos = pos_vec - self.base_position
325
+ local_pos = geom_trans.quat_rot_vec(
326
+ geom_trans.quat_conjugate(self.base_orientation), local_pos
327
+ )
328
+ return local_pos
329
+
330
+ def _localize_cart_quat(self, quat):
331
+ if np.array_equal(self.base_orientation, [1, 0, 0, 0]):
332
+ return quat
333
+
334
+ local_quat = quat
335
+ if local_quat is not None:
336
+ quat_vec = np.array(local_quat)
337
+ local_quat = geom_trans.quat_mul(
338
+ geom_trans.quat_conjugate(self.base_orientation), quat_vec
339
+ )
340
+ return local_quat
341
+
342
+ def _localize_cart_coords(self, pos, quat=None):
343
+ if quat is not None:
344
+ quat = self._localize_cart_quat(quat)
345
+ return self._localize_cart_pos(pos), quat
346
+
347
+ def wait(self, duration=1.0, block=True):
348
+ self.activeController.executeController(self, duration, block=block)
349
+
350
+ def open_fingers(self):
351
+ self.set_desired_gripper_width(0.04)
352
+
353
+ def close_fingers(self, duration=0.5):
354
+ self.set_gripper_width = 0.0
355
+ self.grasp_flag = False
356
+ if duration > 0:
357
+ self.wait(duration)
358
+ self.grasp_flag = True
359
+
360
+ def set_desired_gripper_width(self, desired_width):
361
+ self.set_gripper_width = desired_width
362
+ self.grasp_flag = False
363
+
364
+ def fing_ctrl_step(self):
365
+
366
+ pgain = 1 * np.array([500, 500], dtype=np.float64)
367
+ dgain = 1 * np.array([10, 10], dtype=np.float64)
368
+
369
+ gripper_width = self.current_fing_pos
370
+ gripper_width_vel = self.current_fing_vel
371
+
372
+ des_fing_pos = np.array(
373
+ [self.set_gripper_width, self.set_gripper_width], dtype=np.float64
374
+ )
375
+
376
+ mean_finger_pos = np.mean(gripper_width)
377
+ force = pgain * (mean_finger_pos - gripper_width)
378
+
379
+ if (np.mean(gripper_width) - self.set_gripper_width) > 0.005:
380
+ if self.grasp_flag:
381
+ force2 = np.array([-20, -20])
382
+ else:
383
+ force2 = dgain * (np.array([-0.2, -0.2]) - gripper_width_vel)
384
+ else:
385
+ force2 = pgain * (des_fing_pos - gripper_width) - dgain * gripper_width_vel
386
+ force2 = np.clip(force2, -5, 5)
387
+
388
+ force = force + force2
389
+
390
+ return force
391
+
392
+ def receiveState(self):
393
+
394
+ raise NotImplementedError
395
+
396
+ def tick(self):
397
+ self.time_keeper.tick()
398
+
399
+ def nextStep(self, log=True):
400
+
401
+ self.scene.next_step(log)
402
+
403
+ def prepare_step(self):
404
+
405
+ self.des_joint_pos[:] = np.nan
406
+ self.des_joint_vel[:] = np.nan
407
+ self.des_joint_acc[:] = np.nan
408
+
409
+ self.des_c_pos[:] = np.nan
410
+ self.des_c_vel[:] = np.nan
411
+ self.des_quat[:] = np.nan
412
+ self.des_quat_vel[:] = np.nan
413
+
414
+ def get_command_from_inverse_dynamics(
415
+ self, target_j_acc, mj_calc_inv=False, robot_id=None, client_id=None
416
+ ):
417
+ raise NotImplementedError
418
+
419
+ def preprocessCommand(self, target_j_acc):
420
+ if len(target_j_acc.shape) == 2:
421
+ target_j_acc = target_j_acc.reshape((-1))
422
+ if target_j_acc.shape[0] != self.num_DoF:
423
+ raise ValueError(
424
+ "Specified motor command vector needs to be of size {} is {}\n".format(
425
+ self.num_DoF, target_j_acc.shape[0]
426
+ )
427
+ )
428
+
429
+ self.finger_commands = self.fing_ctrl_step()
430
+ if self.use_inv_dyn:
431
+ target_j_acc = np.append(target_j_acc, self.finger_commands[0])
432
+ target_j_acc = np.append(target_j_acc, self.finger_commands[1])
433
+ self.des_joint_acc = target_j_acc.copy()
434
+ self.uff = self.get_command_from_inverse_dynamics(
435
+ target_j_acc, mj_calc_inv=True
436
+ )
437
+ self.uff[7:9] = self.finger_commands
438
+
439
+ else:
440
+ target_j_acc = np.append(target_j_acc, self.finger_commands[0])
441
+ target_j_acc = np.append(target_j_acc, self.finger_commands[1])
442
+ self.uff = target_j_acc
443
+ if self.gravity_comp:
444
+ comp_forces = self.get_command_from_inverse_dynamics(
445
+ target_j_acc=np.zeros(9), mj_calc_inv=False
446
+ )
447
+ self.grav_terms = comp_forces.copy()
448
+ self.uff += comp_forces
449
+
450
+ if self.step_count == 0:
451
+ self.uff_last = 0
452
+
453
+ if self.clip_rate:
454
+ uff_diff = self.uff - self.uff_last
455
+ uff_diff = np.clip(uff_diff, -self.rate_limit, self.rate_limit)
456
+ self.uff = self.uff_last + uff_diff
457
+
458
+ if self.clip_actions:
459
+ self.uff[:7] = np.clip(self.uff[:7], -self.torque_limit, self.torque_limit)
460
+
461
+ def beam_to_cart_pos_and_quat(self, desiredPos, desiredQuat):
462
+ q = self.gotoCartPosQuatController.trajectory_generator.findJointPosition(
463
+ self, desiredPos=desiredPos, desiredQuat=desiredQuat
464
+ )
465
+ self.beam_to_joint_pos(q)
466
+
467
+ def beam_to_joint_pos(self, desiredJoints, run=True, log=False):
468
+ self.set_q(desiredJoints)
469
+ self.receiveState()
470
+ self.gotoJointController.resetTrajectory()
471
+ self.gotoCartPosQuatController.resetTrajectory()
472
+ self.gotoCartPosImpedanceController.resetTrajectory()
473
+ self.jointTrackingController.setSetPoint(desiredJoints)
474
+ if run:
475
+ self.jointTrackingController.executeControllerTimeSteps(self, 1, log)
476
+
477
+ def set_q(self, joints, robot_id=None, physicsClientId=None):
478
+
479
+ raise NotImplementedError
480
+
481
+ @property
482
+ def step_count(self):
483
+ return self.time_keeper.step_count
484
+
485
+ @property
486
+ def time_stamp(self):
487
+ return self.time_keeper.time_stamp
488
+
489
+ @property
490
+ def step_count(self):
491
+ return self.time_keeper.step_count
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/Scene.py ADDED
@@ -0,0 +1,319 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import enum
2
+ from abc import ABC, abstractmethod
3
+ from typing import List
4
+
5
+ import numpy as np
6
+
7
+ import d3il.environments.d3il.d3il_sim.core.sim_object as sim_object
8
+ import d3il.environments.d3il.d3il_sim.core.time_keeper as time_keeper
9
+ import d3il.environments.d3il.d3il_sim.utils.geometric_transformation as geom_trans
10
+ from d3il.environments.d3il.d3il_sim.core import Camera, Robots
11
+
12
+
13
+ class Scene(ABC):
14
+
15
+ class RenderMode(enum.Enum):
16
+ BLIND = "blind"
17
+ OFFSCREEN = "offscreen"
18
+ HUMAN = "human"
19
+
20
+ def __init__(
21
+ self,
22
+ object_list=None,
23
+ dt=0.001,
24
+ render: RenderMode = RenderMode.HUMAN,
25
+ *args,
26
+ **kwargs
27
+ ):
28
+ if object_list is None:
29
+ object_list = []
30
+
31
+ self.obj_repo = sim_object.SimObjectRepository(object_list)
32
+
33
+ self.dt = dt
34
+ self.render_mode = render
35
+
36
+ self.setup_done = False
37
+
38
+ self._robots: List[Robots.RobotBase] = []
39
+ self.inhand_cam = None
40
+ self.cage_cam = None
41
+
42
+ self.step_callbacks = []
43
+ self.additional_loggers = []
44
+ self.time_keeper = time_keeper.TimeKeeper(self.dt)
45
+
46
+ def add_robot(self, robot):
47
+ self._robots.append(robot)
48
+
49
+ @property
50
+ def robots(self):
51
+ return self._robots
52
+
53
+ def register_callback(self, fn, **kwargs):
54
+
55
+ self.step_callbacks.append((fn, kwargs))
56
+
57
+ @property
58
+ @abstractmethod
59
+ def sim_name(self) -> str:
60
+
61
+ return "NONE"
62
+
63
+ @abstractmethod
64
+ def _setup_scene(self):
65
+
66
+ self._setup_objects(self.object_list)
67
+
68
+ @abstractmethod
69
+ def reset(self, obj_pos=None):
70
+
71
+ raise NotImplementedError
72
+
73
+ def start(self, robot_init_qpos: np.ndarray = None):
74
+
75
+ self._setup_scene()
76
+ self.load_robot_to_scene(robot_init_qpos=robot_init_qpos)
77
+ self.setup_done = True
78
+ self.reset()
79
+
80
+ @abstractmethod
81
+ def render(self):
82
+
83
+ raise NotImplementedError
84
+
85
+ def next_step(self, log=True):
86
+ for rb in self.robots:
87
+ rb.prepare_step()
88
+
89
+ self._sim_step()
90
+
91
+ self.time_keeper.tick()
92
+
93
+ for rb in self.robots:
94
+ rb.tick()
95
+ rb.receiveState()
96
+
97
+ for call_back, kwargs in self.step_callbacks:
98
+ call_back(**kwargs)
99
+ if log:
100
+ self.log_data()
101
+
102
+ self.render()
103
+
104
+ @abstractmethod
105
+ def _sim_step(self):
106
+ raise NotImplementedError
107
+
108
+ @abstractmethod
109
+ def load_robot_to_scene(self, robot_init_qpos: np.ndarray = None):
110
+
111
+ raise NotImplementedError
112
+
113
+ @abstractmethod
114
+ def _setup_objects(self, sim_objs: List[sim_object.SimObject]):
115
+
116
+ raise NotImplementedError
117
+
118
+ @abstractmethod
119
+ def _rt_add_object(self, sim_obj: sim_object.SimObject):
120
+
121
+ raise NotImplementedError
122
+
123
+ def add_object(self, sim_obj: sim_object.SimObject):
124
+
125
+ if not self.setup_done:
126
+ self.obj_repo.add_object(sim_obj)
127
+ else:
128
+ self._rt_add_object(sim_obj)
129
+
130
+ def list_objects(self):
131
+ return list(self._objects.keys())
132
+
133
+ def get_object(self, name: str = None, obj_id: int = None) -> sim_object.SimObject:
134
+
135
+ return self.obj_repo.get_object(name, obj_id)
136
+
137
+ def _query_pois(self, sim_obj: sim_object.SimObject, fn) -> np.ndarray:
138
+
139
+ if len(sim_obj.get_poi()) > 1:
140
+ return np.array([fn(poi, sim_obj) for poi in sim_obj.get_poi()])
141
+ else:
142
+ return fn(sim_obj.get_poi()[0], sim_obj)
143
+
144
+ @abstractmethod
145
+ def _get_obj_seg_id(self, obj_name: str) -> int:
146
+
147
+ raise NotImplementedError
148
+
149
+ def get_obj_seg_id(
150
+ self,
151
+ sim_obj: sim_object.SimObject = None,
152
+ obj_name: str = None,
153
+ obj_id: int = None,
154
+ ) -> int:
155
+
156
+ if obj_name is None:
157
+ if sim_obj is None:
158
+ sim_obj = self.get_object(obj_id=obj_id)
159
+ obj_name = sim_obj.name
160
+
161
+ return self._get_obj_seg_id(obj_name=obj_name)
162
+
163
+ @abstractmethod
164
+ def _get_obj_pos(self, poi, sim_obj: sim_object.SimObject) -> np.ndarray:
165
+
166
+ raise NotImplementedError
167
+
168
+ def get_obj_pos(
169
+ self,
170
+ sim_obj: sim_object.SimObject = None,
171
+ obj_name: str = None,
172
+ obj_id: int = None,
173
+ ) -> np.ndarray:
174
+
175
+ if sim_obj is None:
176
+ sim_obj = self.get_object(obj_name, obj_id)
177
+ return self._query_pois(sim_obj, self._get_obj_pos)
178
+
179
+ @abstractmethod
180
+ def _get_obj_quat(self, poi, sim_obj: sim_object.SimObject) -> np.ndarray:
181
+
182
+ raise NotImplementedError
183
+
184
+ def get_obj_quat(
185
+ self,
186
+ sim_obj: sim_object.SimObject = None,
187
+ obj_name: str = None,
188
+ obj_id: int = None,
189
+ ) -> np.ndarray:
190
+
191
+ if sim_obj is None:
192
+ sim_obj = self.get_object(obj_name, obj_id)
193
+ return self._query_pois(sim_obj, self._get_obj_quat)
194
+
195
+ def _get_obj_rot_mat(self, poi, sim_obj: sim_object.SimObject) -> np.ndarray:
196
+
197
+ quat = self._get_obj_quat(poi, sim_obj)
198
+ return geom_trans.mat2quat(quat)
199
+
200
+ def get_obj_rot_mat(
201
+ self,
202
+ sim_obj: sim_object.SimObject = None,
203
+ obj_name: str = None,
204
+ obj_id: int = None,
205
+ ) -> np.ndarray:
206
+
207
+ if sim_obj is None:
208
+ sim_obj = self.get_object(obj_name, obj_id)
209
+ return self._query_pois(sim_obj, self._get_obj_rot_mat)
210
+
211
+ @abstractmethod
212
+ def _set_obj_pos(self, new_pos, sim_obj: sim_object.SimObject):
213
+
214
+ raise NotImplementedError
215
+
216
+ def set_obj_pos(
217
+ self,
218
+ new_pos,
219
+ sim_obj: sim_object.SimObject = None,
220
+ obj_name: str = None,
221
+ obj_id: int = None,
222
+ ):
223
+
224
+ if sim_obj is None:
225
+ sim_obj = self.get_object(obj_name, obj_id)
226
+
227
+ self._set_obj_pos(new_pos, sim_obj)
228
+
229
+ @abstractmethod
230
+ def _set_obj_quat(self, new_quat, sim_obj: sim_object.SimObject) -> np.ndarray:
231
+
232
+ raise NotImplementedError
233
+
234
+ def set_obj_quat(
235
+ self,
236
+ new_quat,
237
+ sim_obj: sim_object.SimObject = None,
238
+ obj_name: str = None,
239
+ obj_id: int = None,
240
+ ):
241
+
242
+ if sim_obj is None:
243
+ sim_obj = self.get_object(obj_name, obj_id)
244
+
245
+ self._set_obj_quat(new_quat, sim_obj)
246
+
247
+ @abstractmethod
248
+ def _set_obj_pos_and_quat(
249
+ self, new_pos, new_quat, sim_obj: sim_object.SimObject
250
+ ) -> np.ndarray:
251
+
252
+ raise NotImplementedError
253
+
254
+ def set_obj_pos_and_quat(
255
+ self,
256
+ new_pos,
257
+ new_quat,
258
+ sim_obj: sim_object.SimObject = None,
259
+ obj_name: str = None,
260
+ obj_id: int = None,
261
+ ):
262
+
263
+ if sim_obj is None:
264
+ sim_obj = self.get_object(obj_name, obj_id)
265
+
266
+ self._set_obj_pos_and_quat(new_pos, new_quat, sim_obj)
267
+
268
+ @abstractmethod
269
+ def _remove_object(self, sim_obj: sim_object.SimObject):
270
+ raise NotImplementedError
271
+
272
+ def remove_object(
273
+ self,
274
+ sim_obj: sim_object.SimObject = None,
275
+ obj_name: str = None,
276
+ obj_id: int = None,
277
+ ):
278
+ if sim_obj is None:
279
+ sim_obj = self.get_object(obj_name, obj_id)
280
+
281
+ self._remove_object(sim_obj)
282
+ self.obj_repo.remove_object(sim_obj)
283
+
284
+ def get_cage_cam(self) -> Camera.Camera:
285
+ return self.cage_cam
286
+
287
+ def start_logging(self, duration: float = 300.0, **kwargs):
288
+
289
+ for rb in self.robots:
290
+ rb.start_logging(duration, **kwargs)
291
+
292
+ for logger in self.additional_loggers:
293
+ logger.start_logging(duration, **kwargs)
294
+
295
+ def stop_logging(self):
296
+
297
+ for rb in self.robots:
298
+ rb.stop_logging()
299
+
300
+ for logger in self.additional_loggers:
301
+ logger.stop_logging()
302
+
303
+ def add_logger(self, logger):
304
+
305
+ self.additional_loggers.append(logger)
306
+
307
+ def log_data(self):
308
+ for rb in self.robots:
309
+ rb.log_data()
310
+ for logger in self.additional_loggers:
311
+ logger.log_data()
312
+
313
+ @property
314
+ def step_count(self):
315
+ return self.time_keeper.step_count
316
+
317
+ @property
318
+ def time_stamp(self):
319
+ return self.time_keeper.time_stamp
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from .logger import *
2
+ from .Model import *
3
+ from .Robots import *
4
+ from .Scene import *
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/logger.py ADDED
@@ -0,0 +1,867 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import abc
2
+ import datetime
3
+ import os
4
+ from enum import Flag, auto
5
+
6
+ import numpy as np
7
+
8
+ try:
9
+ import wandb
10
+ except ImportError:
11
+ pass
12
+
13
+
14
+ def reset_wandb_env():
15
+ exclude = {
16
+ "WANDB_PROJECT",
17
+ "WANDB_ENTITY",
18
+ "WANDB_API_KEY",
19
+ "WANDB_START_METHOD",
20
+ }
21
+ for k, v in os.environ.items():
22
+ if k.startswith("WANDB_") and k not in exclude:
23
+ del os.environ[k]
24
+
25
+
26
+ class RobotPlotFlags(Flag):
27
+ JOINT_POS = auto()
28
+ JOINT_VEL = auto()
29
+ JOINT_ACC = auto()
30
+
31
+ CART_POS = auto()
32
+ CART_VEL = auto()
33
+ ORIENTATION = auto()
34
+ ORIENTATION_VEL = auto()
35
+
36
+ CART_POS_GLOBAL = auto()
37
+ CART_VEL_GLOBAL = auto()
38
+ ORIENTATION_GLOBAL = auto()
39
+ ORIENTATION_VEL_GLOBAL = auto()
40
+
41
+ COMMAND = auto()
42
+ TORQUES = auto()
43
+ GRAVITY = auto()
44
+ LOADS = auto()
45
+ TIME_STAMPS = auto()
46
+
47
+ GRIPPER_POS = auto()
48
+ GRIPPER_WIDTH = auto()
49
+ GRIPPER_FORCE = auto()
50
+ GRIPPER_VEL = auto()
51
+
52
+ MISC = auto()
53
+
54
+ GRIPPER = GRIPPER_WIDTH | GRIPPER_POS | GRIPPER_FORCE | GRIPPER_VEL
55
+ JOINTS = JOINT_POS | JOINT_ACC | JOINT_VEL
56
+ END_EFFECTOR = CART_POS | CART_VEL | ORIENTATION | ORIENTATION_VEL
57
+ END_EFFECTOR_GLOBAL = (
58
+ CART_POS_GLOBAL | CART_VEL_GLOBAL | ORIENTATION_GLOBAL | ORIENTATION_VEL_GLOBAL
59
+ )
60
+
61
+ FULL = GRIPPER | JOINTS | END_EFFECTOR | END_EFFECTOR_GLOBAL
62
+
63
+
64
+ class ObjectPlotFlags(Flag):
65
+ POSITION = auto()
66
+ ORIENTATION = auto()
67
+ FULL = POSITION | ORIENTATION
68
+
69
+
70
+ class CamPlotFlags(Flag):
71
+ IMAGE = auto()
72
+ FULL = IMAGE
73
+
74
+
75
+ class LoggerBase(abc.ABC):
76
+ def __init__(self):
77
+
78
+ self.logged_time = 0
79
+ self.log_interval = None
80
+ self.log_duration = None
81
+ self.logged_time_steps = 0
82
+ self.max_time_steps = None
83
+ self.last_log_time = None
84
+ self.is_logging = False
85
+
86
+ def start_logging(self, duration: float = 300.0, **kwargs):
87
+
88
+ self.logged_time = 0
89
+ self.logged_time_steps = 0
90
+ self.log_duration = duration
91
+ self._start(duration, **kwargs)
92
+ self.is_logging = True
93
+
94
+ def log_data(self):
95
+
96
+ if self.is_logging and self._check_log_interval():
97
+ self._log()
98
+ self.logged_time_steps += 1
99
+ if (
100
+ self.max_time_steps is not None
101
+ and self.logged_time_steps >= self.max_time_steps
102
+ ) or self.logged_time >= self.log_duration:
103
+ self.stop_logging()
104
+
105
+ def stop_logging(self):
106
+
107
+ if self.is_logging:
108
+ self.is_logging = False
109
+ if self.logged_time_steps > 0:
110
+ self._stop()
111
+
112
+ @abc.abstractmethod
113
+ def _start(self, duration=600, **kwargs):
114
+ pass
115
+
116
+ @abc.abstractmethod
117
+ def _log(self):
118
+ pass
119
+
120
+ @abc.abstractmethod
121
+ def _stop(self):
122
+ pass
123
+
124
+ @abc.abstractmethod
125
+ def _check_log_interval(self) -> bool:
126
+ return True
127
+
128
+ @abc.abstractmethod
129
+ def reset(self):
130
+ pass
131
+
132
+
133
+ class RobotLogger(LoggerBase):
134
+ def __init__(self, robot):
135
+ super().__init__()
136
+
137
+ self.robot = robot
138
+ self.plot_selection = RobotPlotFlags.FULL
139
+ self.use_wandb = False
140
+
141
+ self.reset()
142
+
143
+ def reset(self):
144
+ self.log_dict_full = None
145
+
146
+ @property
147
+ def log_dict(self):
148
+ log_dict = dict()
149
+
150
+ if RobotPlotFlags.JOINTS & self.plot_selection:
151
+ log_dict.update(
152
+ {
153
+ "joint_pos": self.robot.current_j_pos,
154
+ "joint_vel": self.robot.current_j_vel,
155
+ "des_joint_pos": self.robot.des_joint_pos,
156
+ "des_joint_vel": self.robot.des_joint_vel,
157
+ "des_joint_acc": self.robot.des_joint_acc,
158
+ }
159
+ )
160
+
161
+ if RobotPlotFlags.GRIPPER & self.plot_selection:
162
+ log_dict.update(
163
+ {
164
+ "finger_pos": self.robot.current_fing_pos,
165
+ "finger_vel": self.robot.current_fing_vel,
166
+ "des_finger_pos": self.robot.set_gripper_width,
167
+ "gripper_width": self.robot.gripper_width,
168
+ "uff": self.robot.uff,
169
+ }
170
+ )
171
+
172
+ if RobotPlotFlags.END_EFFECTOR & self.plot_selection:
173
+ log_dict.update(
174
+ {
175
+ "cart_pos": self.robot.current_c_pos,
176
+ "cart_vel": self.robot.current_c_vel,
177
+ "cart_quat": self.robot.current_c_quat,
178
+ "cart_quat_vel": self.robot.current_c_quat_vel,
179
+ "des_c_pos": self.robot.des_c_pos,
180
+ "des_c_vel": self.robot.des_c_vel,
181
+ "des_quat": self.robot.des_quat,
182
+ "des_quat_vel": self.robot.des_quat_vel,
183
+ }
184
+ )
185
+
186
+ if RobotPlotFlags.END_EFFECTOR_GLOBAL & self.plot_selection:
187
+ log_dict.update(
188
+ {
189
+ "cart_pos_global": self.robot.current_c_pos_global,
190
+ "cart_vel_global": self.robot.current_c_vel_global,
191
+ "cart_quat_global": self.robot.current_c_quat_global,
192
+ "cart_quat_vel_global": self.robot.current_c_quat_vel_global,
193
+ }
194
+ )
195
+
196
+ if RobotPlotFlags.COMMAND & self.plot_selection:
197
+ log_dict.update(
198
+ {
199
+ "uff": self.robot.uff,
200
+ "last_cmd": self.robot.last_cmd,
201
+ "command": self.robot.command,
202
+ "grav_terms": self.robot.grav_terms,
203
+ "load": self.robot.current_load,
204
+ }
205
+ )
206
+
207
+ if RobotPlotFlags.MISC & self.plot_selection:
208
+ log_dict.update({"misc": self.robot.misc_data})
209
+
210
+ log_dict.update(
211
+ {
212
+ "time_stamp": self.robot.time_stamp,
213
+ "step": self.robot.step_count,
214
+ "wall_clock": self.robot.time_keeper.wall_clock,
215
+ }
216
+ )
217
+
218
+ return log_dict
219
+
220
+ def _start(
221
+ self,
222
+ duration=600,
223
+ log_interval=None,
224
+ plot_selection: RobotPlotFlags = RobotPlotFlags.FULL,
225
+ use_wandb=False,
226
+ **kwargs
227
+ ):
228
+
229
+ self.plot_selection = plot_selection
230
+ self.use_wandb = use_wandb
231
+
232
+ if log_interval is None:
233
+ self.log_interval = 1
234
+ else:
235
+ self.log_interval = log_interval
236
+
237
+ assert self.log_interval >= 1
238
+
239
+ self.max_time_steps = int(duration / self.log_interval)
240
+
241
+ if self.max_time_steps > 1800000:
242
+ self.max_time_steps = 1800000
243
+
244
+ self.log_dict_full = {
245
+ k: [None] * self.max_time_steps for k, v in self.log_dict.items()
246
+ }
247
+
248
+ self.initial_time_stamp = self.robot.step_count
249
+
250
+ if self.use_wandb:
251
+ reset_wandb_env()
252
+ now = datetime.datetime.now().strftime("%d_%m_%Y_%H_%M_%S")
253
+ job_name = "robot_log_" + now
254
+ self.run = wandb.init(
255
+ project="sf",
256
+ group="test_log",
257
+ name=job_name,
258
+ settings=wandb.Settings(_disable_stats=True),
259
+ )
260
+
261
+ def _log(self):
262
+ log_properties = self.log_dict
263
+
264
+ for k, v in log_properties.items():
265
+ self.log_dict_full[k][self.logged_time_steps] = v
266
+
267
+ self.last_log_time = log_properties["step"]
268
+
269
+ self.logged_time = self.last_log_time - self.initial_time_stamp
270
+
271
+ if self.use_wandb:
272
+ flat_log_dict = {
273
+ k + "_" + str(i): vv
274
+ for k, v in log_properties.items()
275
+ for i, vv in enumerate(np.atleast_1d(v))
276
+ }
277
+ self.run.log(flat_log_dict, step=self.logged_time_steps)
278
+
279
+ def _stop(self):
280
+
281
+ if self.logged_time_steps < self.max_time_steps:
282
+ for v in self.log_dict_full.values():
283
+ del v[self.logged_time_steps :]
284
+
285
+ if self.use_wandb:
286
+ if self.run is not None:
287
+ self.run.finish()
288
+
289
+ self.__dict__.update({k: np.array(v) for k, v in self.log_dict_full.items()})
290
+
291
+ def _check_log_interval(self) -> bool:
292
+
293
+ if (
294
+ self.last_log_time is None
295
+ or self.robot.step_count >= self.last_log_time + self.log_interval
296
+ ):
297
+ return True
298
+ return False
299
+
300
+ def plot(self, plot_selection=RobotPlotFlags.FULL, block=True):
301
+
302
+ import matplotlib.pyplot as plt
303
+
304
+ valid_plot_selections = plot_selection & self.plot_selection
305
+
306
+ if self.is_logging:
307
+ self.stop_logging()
308
+
309
+ self.time_stamp = self.time_stamp - self.time_stamp[0]
310
+
311
+ j1_limit_lower = -2.9671
312
+ j1_limit_upper = 2.9671
313
+ j2_limit_lower = -1.8326
314
+ j2_limit_upper = 1.8326
315
+ j3_limit_lower = -2.9671
316
+ j3_limit_upper = 2.9671
317
+ j4_limit_lower = -3.1416
318
+ j4_limit_upper = 0.0873
319
+ j5_limit_lower = -2.9671
320
+ j5_limit_upper = 2.9671
321
+ j6_limit_lower = -0.0873
322
+ j6_limit_upper = 3.8223
323
+ j7_limit_lower = -2.9671
324
+ j7_limit_upper = 2.9671
325
+
326
+ j1_limit_lower_safety = -2.8973
327
+ j1_limit_upper_safety = 2.8973
328
+ j2_limit_lower_safety = -1.7628
329
+ j2_limit_upper_safety = 1.7628
330
+ j3_limit_lower_safety = -2.8973
331
+ j3_limit_upper_safety = 2.8973
332
+ j4_limit_lower_safety = -3.0718
333
+ j4_limit_upper_safety = 0.0175
334
+ j5_limit_lower_safety = -2.8973
335
+ j5_limit_upper_safety = 2.8973
336
+ j6_limit_lower_safety = -0.0175
337
+ j6_limit_upper_safety = 3.7525
338
+ j7_limit_lower_safety = -2.8973
339
+ j7_limit_upper_safety = 2.8973
340
+
341
+ j1_vel_limit_lower = -2.3925
342
+ j1_vel_limit_upper = 2.3925
343
+ j2_vel_limit_lower = -2.3925
344
+ j2_vel_limit_upper = 2.3925
345
+ j3_vel_limit_lower = -2.3925
346
+ j3_vel_limit_upper = 2.3925
347
+ j4_vel_limit_lower = -2.3925
348
+ j4_vel_limit_upper = 2.3925
349
+ j5_vel_limit_lower = -2.8710
350
+ j5_vel_limit_upper = 2.8710
351
+ j6_vel_limit_lower = -2.8710
352
+ j6_vel_limit_upper = 2.8710
353
+ j7_vel_limit_lower = -2.8710
354
+ j7_vel_limit_upper = 2.8710
355
+
356
+ upper_limits = [
357
+ j1_limit_upper,
358
+ j2_limit_upper,
359
+ j3_limit_upper,
360
+ j4_limit_upper,
361
+ j5_limit_upper,
362
+ j6_limit_upper,
363
+ j7_limit_upper,
364
+ ]
365
+ lower_limits = [
366
+ j1_limit_lower,
367
+ j2_limit_lower,
368
+ j3_limit_lower,
369
+ j4_limit_lower,
370
+ j5_limit_lower,
371
+ j6_limit_lower,
372
+ j7_limit_lower,
373
+ ]
374
+
375
+ soft_upper_limits = [
376
+ j1_limit_upper_safety,
377
+ j2_limit_upper_safety,
378
+ j3_limit_upper_safety,
379
+ j4_limit_upper_safety,
380
+ j5_limit_upper_safety,
381
+ j6_limit_upper_safety,
382
+ j7_limit_upper_safety,
383
+ ]
384
+
385
+ soft_lower_limits = [
386
+ j1_limit_lower_safety,
387
+ j2_limit_lower_safety,
388
+ j3_limit_lower_safety,
389
+ j4_limit_lower_safety,
390
+ j5_limit_lower_safety,
391
+ j6_limit_lower_safety,
392
+ j7_limit_lower_safety,
393
+ ]
394
+
395
+ upper_limits_vel = [
396
+ j1_vel_limit_upper,
397
+ j2_vel_limit_upper,
398
+ j3_vel_limit_upper,
399
+ j4_vel_limit_upper,
400
+ j5_vel_limit_upper,
401
+ j6_vel_limit_upper,
402
+ j7_vel_limit_upper,
403
+ ]
404
+
405
+ lower_limits_vel = [
406
+ j1_vel_limit_lower,
407
+ j2_vel_limit_lower,
408
+ j3_vel_limit_lower,
409
+ j4_vel_limit_lower,
410
+ j5_vel_limit_lower,
411
+ j6_vel_limit_lower,
412
+ j7_vel_limit_lower,
413
+ ]
414
+
415
+ if RobotPlotFlags.JOINT_POS in valid_plot_selections:
416
+ joint_pos_fig = plt.figure()
417
+ for k in range(7):
418
+ plt.figure(joint_pos_fig.number)
419
+ plt.subplot(7, 1, k + 1)
420
+ plt.plot(self.time_stamp, self.joint_pos[:, k])
421
+ plt.plot(self.time_stamp, self.des_joint_pos[:, k], "r")
422
+ plt.subplot(7, 1, 1)
423
+ plt.title("joint positions ")
424
+
425
+ if RobotPlotFlags.JOINT_VEL in valid_plot_selections:
426
+ joint_vel_fig = plt.figure()
427
+ for k in range(7):
428
+ plt.figure(joint_vel_fig.number)
429
+ plt.subplot(7, 1, k + 1)
430
+ plt.plot(self.time_stamp, self.joint_vel[:, k])
431
+ plt.plot(self.time_stamp, self.des_joint_vel[:, k], "r")
432
+ plt.subplot(7, 1, 1)
433
+ plt.title("joint velocities ")
434
+
435
+ if RobotPlotFlags.JOINT_ACC in valid_plot_selections:
436
+ robot_acceleration = np.diff(self.joint_vel, 1, axis=0) / self.robot.dt
437
+ acceleration_fig = plt.figure()
438
+ for k in range(7):
439
+ plt.figure(acceleration_fig.number)
440
+ plt.subplot(7, 1, k + 1)
441
+ plt.plot(self.time_stamp[1:], robot_acceleration[:, k])
442
+ plt.plot(self.time_stamp, self.des_joint_acc[:, k], "r")
443
+ plt.subplot(7, 1, 1)
444
+ plt.title("joint accelerations ")
445
+
446
+ if RobotPlotFlags.COMMAND in valid_plot_selections:
447
+ ctrl_torques_fig = plt.figure()
448
+ for k in range(7):
449
+ plt.figure(ctrl_torques_fig.number)
450
+ plt.subplot(7, 1, k + 1)
451
+ plt.plot(self.time_stamp, self.command[:, k])
452
+ plt.subplot(7, 1, 1)
453
+ plt.title(" control torques (without gravity comp.)")
454
+
455
+ if RobotPlotFlags.TORQUES in valid_plot_selections:
456
+ clipped_torques_fig = plt.figure()
457
+ for k in range(7):
458
+ plt.figure(clipped_torques_fig.number)
459
+ plt.subplot(7, 1, k + 1)
460
+ plt.plot(self.time_stamp, self.uff[:, k])
461
+ plt.subplot(7, 1, 1)
462
+ plt.title(" clipped torques (with gravity comp.)")
463
+
464
+ if RobotPlotFlags.GRAVITY in valid_plot_selections:
465
+ grav_terms_fig = plt.figure()
466
+ for k in range(7):
467
+ plt.figure(grav_terms_fig.number)
468
+ plt.subplot(9, 1, k + 1)
469
+ plt.plot(self.time_stamp, self.grav_terms[:, k])
470
+ plt.subplot(7, 1, 1)
471
+ plt.title(" gravity (+coriolis) ")
472
+
473
+ if RobotPlotFlags.LOADS in valid_plot_selections:
474
+ loads_fig = plt.figure()
475
+ for k in range(7):
476
+ plt.figure(loads_fig.number)
477
+ plt.subplot(7, 1, k + 1)
478
+ plt.plot(self.time_stamp, self.load[:, k])
479
+ plt.subplot(7, 1, 1)
480
+ plt.title(" loads - forces in joints")
481
+
482
+ if RobotPlotFlags.GRIPPER_WIDTH in valid_plot_selections:
483
+ gripper_fig = plt.figure()
484
+ plt.figure(gripper_fig.number)
485
+ plt.plot(self.time_stamp, self.gripper_width)
486
+ plt.title(" gripper width ")
487
+
488
+ if RobotPlotFlags.GRIPPER_FORCE in valid_plot_selections:
489
+ gripper_force_fig = plt.figure()
490
+ plt.figure(gripper_force_fig.number)
491
+ plt.plot(self.time_stamp, self.uff[:, -2:])
492
+
493
+ plt.title(" gripper force (without contact forces)")
494
+
495
+ if RobotPlotFlags.GRIPPER_POS in valid_plot_selections:
496
+ gripper_pos_fig = plt.figure()
497
+ plt.figure(gripper_pos_fig.number)
498
+ plt.plot(self.time_stamp, self.finger_pos[:, -2:], label="actual")
499
+ plt.plot(self.time_stamp, self.des_finger_pos, label="desired")
500
+ plt.legend()
501
+ plt.title(" gripper pos ")
502
+
503
+ if RobotPlotFlags.GRIPPER_VEL in valid_plot_selections:
504
+ gripper_vel_fig = plt.figure()
505
+ plt.figure(gripper_vel_fig.number)
506
+ plt.plot(self.time_stamp, self.finger_vel[:, -2:])
507
+ plt.title(" gripper vel ")
508
+
509
+ if RobotPlotFlags.CART_POS in valid_plot_selections:
510
+ cart_pos_fig = plt.figure()
511
+ for j in range(3):
512
+ plt.figure(cart_pos_fig.number)
513
+ plt.subplot(3, 1, j + 1)
514
+ plt.plot(self.time_stamp, self.cart_pos[:, j])
515
+ plt.plot(self.time_stamp, self.des_c_pos[:, j], "r")
516
+ plt.subplot(3, 1, 1)
517
+ plt.title(" endeffector pos ")
518
+
519
+ if RobotPlotFlags.CART_VEL in valid_plot_selections:
520
+ cart_vel_fig = plt.figure()
521
+ for j in range(3):
522
+ plt.figure(cart_vel_fig.number)
523
+ plt.subplot(3, 1, j + 1)
524
+ plt.plot(self.time_stamp, self.cart_vel[:, j])
525
+ plt.plot(self.time_stamp, self.des_c_vel[:, j], "r")
526
+ plt.subplot(3, 1, 1)
527
+ plt.title(" endeffector vel ")
528
+
529
+ if RobotPlotFlags.ORIENTATION in valid_plot_selections:
530
+ orientation_fig = plt.figure()
531
+ for j in range(4):
532
+ plt.figure(orientation_fig.number)
533
+ plt.subplot(4, 1, j + 1)
534
+ plt.plot(self.time_stamp, self.cart_quat[:, j])
535
+ plt.plot(self.time_stamp, self.des_quat[:, j], "r")
536
+ plt.subplot(4, 1, 1)
537
+ plt.title(" endeffector orientation ")
538
+
539
+ if RobotPlotFlags.ORIENTATION_VEL in valid_plot_selections:
540
+ orientation_vel_fig = plt.figure()
541
+ for j in range(4):
542
+ plt.figure(orientation_vel_fig.number)
543
+ plt.subplot(4, 1, j + 1)
544
+ plt.plot(self.time_stamp, self.cart_quat_vel[:, j])
545
+ plt.plot(self.time_stamp, self.des_quat_vel[:, j], "r")
546
+ plt.subplot(4, 1, 1)
547
+ plt.title(" endeffector angular velocity ")
548
+
549
+ if RobotPlotFlags.CART_POS_GLOBAL in valid_plot_selections:
550
+ cart_pos_fig = plt.figure()
551
+ for j in range(3):
552
+ plt.figure(cart_pos_fig.number)
553
+ plt.subplot(3, 1, j + 1)
554
+ plt.plot(self.time_stamp, self.cart_pos_global[:, j])
555
+ plt.subplot(3, 1, 1)
556
+ plt.title(" endeffector pos global")
557
+
558
+ if RobotPlotFlags.CART_VEL_GLOBAL in valid_plot_selections:
559
+ cart_vel_fig = plt.figure()
560
+ for j in range(3):
561
+ plt.figure(cart_vel_fig.number)
562
+ plt.subplot(3, 1, j + 1)
563
+ plt.plot(self.time_stamp, self.cart_vel_global[:, j])
564
+ plt.subplot(3, 1, 1)
565
+ plt.title(" endeffector vel global")
566
+
567
+ if RobotPlotFlags.ORIENTATION_GLOBAL in valid_plot_selections:
568
+ orientation_fig = plt.figure()
569
+ for j in range(4):
570
+ plt.figure(orientation_fig.number)
571
+ plt.subplot(4, 1, j + 1)
572
+ plt.plot(self.time_stamp, self.cart_quat_global[:, j])
573
+ plt.subplot(4, 1, 1)
574
+ plt.title(" endeffector orientation global")
575
+
576
+ if RobotPlotFlags.ORIENTATION_VEL_GLOBAL in valid_plot_selections:
577
+ orientation_vel_fig = plt.figure()
578
+ for j in range(4):
579
+ plt.figure(orientation_vel_fig.number)
580
+ plt.subplot(4, 1, j + 1)
581
+ plt.plot(self.time_stamp, self.cart_quat_vel_global[:, j])
582
+ plt.subplot(4, 1, 1)
583
+ plt.title(" endeffector angular velocity global")
584
+
585
+ if RobotPlotFlags.TIME_STAMPS in valid_plot_selections:
586
+ timeStamp_fig = plt.figure()
587
+ plt.figure(timeStamp_fig.number)
588
+ plt.plot(np.diff(self.time_stamp))
589
+ plt.title("time stamp difference ")
590
+
591
+ if RobotPlotFlags.MISC in valid_plot_selections:
592
+ misc_fig = plt.figure()
593
+ numplots = self.misc.shape[1]
594
+ for j in range(numplots):
595
+ plt.figure(misc_fig.number)
596
+ plt.subplot(numplots, 1, j + 1)
597
+ plt.plot(self.misc[:, j])
598
+
599
+ plt.subplot(numplots, 1, 1)
600
+ plt.title("misc debug data ")
601
+ plt.show(block=block)
602
+
603
+
604
+ class ObjectLogger(LoggerBase):
605
+
606
+ def __init__(self, scene, sim_object=None, obj_name=None):
607
+ super().__init__()
608
+ self.scene = scene
609
+
610
+ if obj_name is not None:
611
+ sim_object = scene.get_object(name=obj_name)
612
+
613
+ if sim_object is None:
614
+ raise ValueError("No Simobject defined.")
615
+ self.object = sim_object
616
+ self.plot_selection = ObjectPlotFlags.FULL
617
+
618
+ def reset(self):
619
+ self.log_dict_full = None
620
+ self.last_log_time = None
621
+
622
+ @property
623
+ def log_dict(self):
624
+ log_dict = dict()
625
+
626
+ if ObjectPlotFlags.POSITION in self.plot_selection:
627
+ log_dict.update({"pos": self.scene.get_obj_pos(self.object).flatten()})
628
+
629
+ if ObjectPlotFlags.ORIENTATION in self.plot_selection:
630
+ log_dict.update({"orientation": self.scene.get_obj_quat(self.object)})
631
+
632
+ log_dict.update({"time_stamp": self.scene.robots[0].time_stamp})
633
+ log_dict.update({"step": self.scene.robots[0].step_count})
634
+
635
+ return log_dict
636
+
637
+ def _start(
638
+ self,
639
+ duration=600,
640
+ log_interval=None,
641
+ obj_plot_selection: ObjectPlotFlags = ObjectPlotFlags.FULL,
642
+ use_wandb=False,
643
+ **kwargs
644
+ ):
645
+
646
+ self.plot_selection = obj_plot_selection
647
+ self.use_wandb = use_wandb
648
+
649
+ if log_interval is None:
650
+ self.log_interval = 1
651
+ else:
652
+ self.log_interval = log_interval
653
+
654
+ assert self.log_interval >= 1
655
+
656
+ self.max_time_steps = int(duration / self.log_interval)
657
+
658
+ if self.max_time_steps > 1800000:
659
+ self.max_time_steps = 1800000
660
+
661
+ self.log_dict_full = {
662
+ k: [None] * self.max_time_steps for k, v in self.log_dict.items()
663
+ }
664
+
665
+ self.initial_time_stamp = self.scene.robots[0].step_count
666
+
667
+ if self.use_wandb:
668
+ reset_wandb_env()
669
+ now = datetime.datetime.now().strftime("%d_%m_%Y_%H_%M_%S")
670
+ job_name = "robot_log_" + now
671
+ self.run = wandb.init(
672
+ project="sf",
673
+ group="test_log",
674
+ name=job_name,
675
+ settings=wandb.Settings(_disable_stats=True),
676
+ )
677
+
678
+ def _log(self):
679
+ log_properties = self.log_dict
680
+
681
+ for k, v in log_properties.items():
682
+ self.log_dict_full[k][self.logged_time_steps] = v
683
+
684
+ self.last_log_time = log_properties["step"]
685
+
686
+ self.logged_time = self.last_log_time - self.initial_time_stamp
687
+
688
+ if self.use_wandb:
689
+ flat_log_dict = {
690
+ k + "_" + str(i): vv
691
+ for k, v in log_properties.items()
692
+ for i, vv in enumerate(np.atleast_1d(v))
693
+ }
694
+ self.run.log(flat_log_dict, step=self.logged_time_steps)
695
+
696
+ def _stop(self):
697
+
698
+ if self.logged_time_steps < self.max_time_steps:
699
+ for v in self.log_dict_full.values():
700
+ del v[self.logged_time_steps :]
701
+
702
+ if self.use_wandb:
703
+ if self.run is not None:
704
+ self.run.finish()
705
+
706
+ self.__dict__.update({k: np.array(v) for k, v in self.log_dict_full.items()})
707
+
708
+ def _check_log_interval(self) -> bool:
709
+ if (
710
+ self.last_log_time is None
711
+ or self.scene.robots[0].step_count >= self.last_log_time + self.log_interval
712
+ ):
713
+ return True
714
+ return False
715
+
716
+ def plot(self, plot_selection=ObjectPlotFlags.FULL, block=True):
717
+ valid_plot_selections = plot_selection & self.plot_selection
718
+
719
+ import matplotlib.pyplot as plt
720
+
721
+ self.time_stamp = self.time_stamp - self.time_stamp[0]
722
+
723
+ if ObjectPlotFlags.POSITION in valid_plot_selections:
724
+ pos_fig = plt.figure()
725
+ for k in range(3):
726
+ plt.figure(pos_fig.number)
727
+ plt.subplot(3, 1, k + 1)
728
+ plt.plot(self.time_stamp, self.pos[:, k])
729
+ plt.subplot(3, 1, 1)
730
+ plt.title("object positions ")
731
+
732
+ if ObjectPlotFlags.ORIENTATION in valid_plot_selections:
733
+ orientation_fig = plt.figure()
734
+ for k in range(4):
735
+ plt.figure(orientation_fig.number)
736
+ plt.subplot(4, 1, k + 1)
737
+ plt.plot(self.time_stamp, self.orientation[:, k])
738
+ plt.title(" object orientation ")
739
+ plt.show(block=block)
740
+
741
+
742
+ class CamLogger(LoggerBase):
743
+
744
+ def __init__(self, scene, camera):
745
+ super().__init__()
746
+
747
+ self.scene = scene
748
+ self.cam = camera
749
+
750
+ self.plot_selection = CamPlotFlags.FULL
751
+
752
+ def reset(self):
753
+ self.log_dict_full = None
754
+ self.last_log_time = None
755
+ self.cam.get_image(depth=False)
756
+
757
+ @property
758
+ def log_dict(self):
759
+ log_dict = dict()
760
+
761
+ if CamPlotFlags.IMAGE in self.plot_selection:
762
+
763
+ log_dict.update({"color_image": self.cam.get_image(depth=False)})
764
+
765
+ log_dict.update({"time_stamp": self.scene.robots[0].step_count})
766
+ log_dict.update({"step": self.scene.robots[0].step_count})
767
+
768
+ return log_dict
769
+
770
+ def _start(
771
+ self,
772
+ duration=600,
773
+ log_interval=None,
774
+ obj_plot_selection: CamPlotFlags = CamPlotFlags.FULL,
775
+ use_wandb=False,
776
+ **kwargs
777
+ ):
778
+
779
+ self.plot_selection = obj_plot_selection
780
+ self.use_wandb = use_wandb
781
+
782
+ if log_interval is None:
783
+ self.log_interval = 1
784
+ else:
785
+ self.log_interval = log_interval
786
+
787
+ assert self.log_interval >= 1
788
+
789
+ self.max_time_steps = int(duration / self.log_interval)
790
+
791
+ if self.max_time_steps > 1800000:
792
+ self.max_time_steps = 1800000
793
+
794
+ self.log_dict_full = {
795
+ k: [None] * self.max_time_steps for k, v in self.log_dict.items()
796
+ }
797
+
798
+ self.initial_time_stamp = self.scene.robots[0].step_count
799
+
800
+ if self.use_wandb:
801
+ reset_wandb_env()
802
+ now = datetime.datetime.now().strftime("%d_%m_%Y_%H_%M_%S")
803
+ job_name = "robot_log_" + now
804
+ self.run = wandb.init(
805
+ project="sf",
806
+ group="test_log",
807
+ name=job_name,
808
+ settings=wandb.Settings(_disable_stats=True),
809
+ )
810
+
811
+ def _log(self):
812
+
813
+ log_properties = self.log_dict
814
+
815
+ for k, v in log_properties.items():
816
+ self.log_dict_full[k][self.logged_time_steps] = v
817
+
818
+ self.last_log_time = log_properties["step"]
819
+
820
+ self.logged_time = self.last_log_time - self.initial_time_stamp
821
+
822
+ if self.use_wandb:
823
+ flat_log_dict = {
824
+ k + "_" + str(i): vv
825
+ for k, v in log_properties.items()
826
+ for i, vv in enumerate(np.atleast_1d(v))
827
+ }
828
+ self.run.log(flat_log_dict, step=self.logged_time_steps)
829
+
830
+ def _stop(self):
831
+
832
+ if self.logged_time_steps < self.max_time_steps:
833
+ for v in self.log_dict_full.values():
834
+ del v[self.logged_time_steps :]
835
+
836
+ if self.use_wandb:
837
+ if self.run is not None:
838
+ self.run.finish()
839
+
840
+ self.__dict__.update({k: np.array(v) for k, v in self.log_dict_full.items()})
841
+
842
+ def _check_log_interval(self) -> bool:
843
+
844
+ if (
845
+ self.last_log_time is None
846
+ or self.scene.robots[0].step_count >= self.last_log_time + self.log_interval
847
+ ):
848
+ return True
849
+ return False
850
+
851
+ def plot(self, plot_selection=CamPlotFlags.FULL, block=True):
852
+ valid_plot_selections = plot_selection & self.plot_selection
853
+
854
+ import matplotlib.pyplot as plt
855
+
856
+ self.time_stamp = self.time_stamp - self.time_stamp[0]
857
+
858
+ if CamPlotFlags.IMAGE in valid_plot_selections:
859
+ pos_fig = plt.figure()
860
+ for k in range(3):
861
+ plt.figure(pos_fig.number)
862
+ plt.subplot(3, 1, k + 1)
863
+ plt.plot(self.time_stamp, self.pos[:, k])
864
+ plt.subplot(3, 1, 1)
865
+ plt.title("camera images ")
866
+
867
+ plt.show(block=block)
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/sim_object/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from .sim_obj_repo import SimObjectRepository
2
+ from .sim_object import IntelligentSimObject, SimObject
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/sim_object/sim_obj_repo.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List
2
+
3
+ from d3il.environments.d3il.d3il_sim.utils.unique_dict import UniqueDict
4
+
5
+ from .sim_object import SimObject
6
+
7
+
8
+ class SimObjectRepository:
9
+
10
+ def __init__(self, obj_list=None) -> None:
11
+ self._name2id_map = UniqueDict(err_msg="Duplicate object name:")
12
+ self._id2name_map = UniqueDict(err_msg="Duplicate object id:")
13
+ self._objects = UniqueDict(err_msg="Duplicate object name:")
14
+
15
+ if obj_list is not None:
16
+ for obj in obj_list:
17
+ self.add_object(obj)
18
+
19
+ def add_object(self, sim_obj: SimObject) -> None:
20
+ self._objects[sim_obj.name] = sim_obj
21
+
22
+ def remove_object(self, sim_obj: SimObject) -> None:
23
+ del self._name2id_map[sim_obj.name]
24
+
25
+ del self._objects[sim_obj.name]
26
+
27
+ def register_obj_id(self, sim_obj: SimObject, obj_id: int):
28
+ sim_obj.obj_id = obj_id
29
+ self._name2id_map[sim_obj.name] = obj_id
30
+
31
+ def get_obj_list(self) -> List[SimObject]:
32
+ return list(self._objects.values())
33
+
34
+ def get_object(self, name: str = None, obj_id: int = None) -> SimObject:
35
+
36
+ if obj_id is not None:
37
+ name = self.get_name_from_id(obj_id)
38
+ return self._objects[name]
39
+
40
+ def get_id_from_name(self, name: str) -> int:
41
+
42
+ return self._name2id_map[name]
43
+
44
+ def get_name_from_id(self, obj_id: int) -> str:
45
+
46
+ return self._id2name_map[obj_id]
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/sim_object/sim_object.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import abc
2
+ from typing import List
3
+
4
+
5
+ class SimObject(abc.ABC):
6
+
7
+ GLOBAL_NAME_COUNTER = 0
8
+
9
+ def __init__(self, name: str = None, init_pos=None, init_quat=None):
10
+
11
+ if name is None:
12
+ name = "SIM_OBJ_{}".format(SimObject.GLOBAL_NAME_COUNTER)
13
+
14
+ self.name = name
15
+
16
+ self.init_pos = init_pos
17
+ self.init_quat = init_quat
18
+
19
+ self.obj_id = None
20
+
21
+ SimObject.GLOBAL_NAME_COUNTER += 1
22
+
23
+ @abc.abstractmethod
24
+ def get_poi(self) -> list:
25
+
26
+ return [self.name]
27
+
28
+
29
+ class IntelligentSimObject(SimObject, abc.ABC):
30
+
31
+ def __init__(self, name: str = None, init_pos=None, init_quat=None):
32
+
33
+ super(IntelligentSimObject, self).__init__(name, init_pos, init_quat)
34
+
35
+ self.sim = None
36
+ self.sim_name = None
37
+
38
+ def register_sim(self, sim, sim_name):
39
+
40
+ self.sim = sim
41
+ self.sim_name = sim_name
42
+
43
+
44
+ class DummyObject(SimObject):
45
+ def __init__(self, pois: List[str]):
46
+ self.pois = pois
47
+
48
+ def get_poi(self) -> list:
49
+ return self.pois
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/core/time_keeper.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+
3
+
4
+ class TimeKeeper:
5
+ def __init__(self, dt) -> None:
6
+ self.dt = dt
7
+ self.step_count = 0
8
+ self.time_stamp = 0
9
+
10
+ def tick(self):
11
+ self.step_count += 1
12
+ self.time_stamp += self.dt
13
+ self.wall_clock = time.time_ns()
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/gyms/__init__.py ADDED
File without changes
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/gyms/gym_controllers.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import abc
2
+
3
+ import gym
4
+ import numpy as np
5
+
6
+ import d3il.environments.d3il.d3il_sim.controllers.Controller as ctrl
7
+ from d3il.environments.d3il.d3il_sim.controllers import CartPosQuatImpedenceController
8
+
9
+
10
+ class GymController(abc.ABC):
11
+ def __init__(self, robot, controller):
12
+ self.controller = controller
13
+ self.robot = robot
14
+
15
+ @abc.abstractmethod
16
+ def action_space(self):
17
+ raise NotImplementedError
18
+
19
+ def set_action(self, action):
20
+ pass
21
+
22
+ def reset(self):
23
+ self.controller.reset()
24
+
25
+ def execute_action(self, n_time_steps):
26
+ self.controller.executeControllerTimeSteps(self.robot, timeSteps=n_time_steps)
27
+
28
+
29
+ class GymJointPosController(GymController):
30
+ def __init__(self, robot):
31
+
32
+ super().__init__(robot, ctrl.JointPositionController())
33
+
34
+ def action_space(self):
35
+ low = [-2.8973, -1.7628, -2.8973, -3.0718, -2.8973, -0.0175, -2.8973]
36
+ high = [2.8973, 1.7628, 2.8973, -0.0698, 2.8973, 3.7525, 2.8973]
37
+
38
+ action_space = gym.spaces.Box(low=np.array(low), high=np.array(high))
39
+
40
+ return action_space
41
+
42
+ def set_action(self, action):
43
+ self.controller.setSetPoint(desired_pos=action)
44
+
45
+
46
+ class GymJointVelController(GymController):
47
+ def __init__(self, robot):
48
+
49
+ super().__init__(robot, ctrl.JointVelocityController())
50
+
51
+ def action_space(self):
52
+ low = [-2.175, -2.1750, -2.1750, -2.1750, -2.6100, -2.6100, -2.6100]
53
+ high = [2.175, 2.1750, 2.1750, 2.1750, 2.6100, 2.6100, 2.6100]
54
+
55
+ action_space = gym.spaces.Box(low=np.array(low), high=np.array(high))
56
+
57
+ return action_space
58
+
59
+ def set_action(self, action):
60
+ self.controller.setSetPoint(desired_vel=action)
61
+
62
+
63
+ class GymTorqueController(GymController):
64
+ def __init__(self, robot):
65
+ super().__init__(robot, ctrl.TorqueController())
66
+
67
+ def action_space(self):
68
+ low = [-2.175, -2.1750, -2.1750, -2.1750, -2.6100, -2.6100, -2.6100]
69
+ high = [2.175, 2.1750, 2.1750, 2.1750, 2.6100, 2.6100, 2.6100]
70
+
71
+ action_space = gym.spaces.Box(low=np.array(low), high=np.array(high))
72
+
73
+ return action_space
74
+
75
+ def set_action(self, action):
76
+ self.controller.setAction(action)
77
+
78
+
79
+ class GymCartesianVelController(GymController):
80
+ def __init__(self, robot, fixed_orientation=None, max_cart_vel=0.05):
81
+ controller = CartPosQuatImpedenceController()
82
+ super(GymCartesianVelController, self).__init__(robot, controller)
83
+ self.fixed_orientation = fixed_orientation
84
+ self.max_cart_vel = max_cart_vel
85
+ self.max_cart_pos = np.array([0.7, 0.4, 0.6])
86
+ self.min_cart_pos = np.array([0.2, -0.4, 0.0])
87
+ self.desired_c_pos = robot.des_c_pos
88
+
89
+ def action_space(self):
90
+ low_xyz_gripper = np.array([-1.0, -1.0, -1.0]) * self.max_cart_vel
91
+ high_xyz_gripper = np.array([1.0, 1.0, 1.0]) * self.max_cart_vel
92
+
93
+ quat_low_wxyz = np.array([-1, -1, -1, -1])
94
+ quat_high_wxyz = np.array([1, 1, 1, 1])
95
+
96
+ low_limits = low_xyz_gripper
97
+ high_limits = high_xyz_gripper
98
+
99
+ if self.fixed_orientation is None:
100
+ low_limits.append(quat_low_wxyz)
101
+ high_limits.append(quat_high_wxyz)
102
+
103
+ action_space = gym.spaces.Box(low=low_limits, high=high_limits)
104
+ return action_space
105
+
106
+ def set_action(self, action):
107
+ self.desired_c_pos = np.array(action[:3])
108
+
109
+ if self.fixed_orientation is None:
110
+ desired_quat = np.array(action[3:])
111
+ else:
112
+ desired_quat = self.fixed_orientation
113
+
114
+ self.controller.setDesiredPos(
115
+ np.concatenate([self.desired_c_pos, desired_quat])
116
+ )
117
+
118
+
119
+ class GymXYVelController(GymController):
120
+ def __init__(
121
+ self, robot, fixed_orientation=None, fixed_z_pos=0.4, max_cart_vel=0.05
122
+ ):
123
+ controller = CartPosQuatImpedenceController()
124
+ super(GymCartesianVelController, self).__init__(robot, controller)
125
+ self.fixed_orientation = fixed_orientation
126
+ self.fixed_z_pos = fixed_z_pos
127
+ self.max_cart_vel = max_cart_vel
128
+ self.max_cart_pos = np.array([0.7, 0.4])
129
+ self.min_cart_pos = np.array([0.2, -0.4])
130
+ self.desired_c_pos = robot.des_c_pos
131
+
132
+ def action_space(self):
133
+ low_xyz_gripper = np.array([-1.0, -1.0]) * self.max_cart_vel
134
+ high_xyz_gripper = np.array([1.0, 1.0]) * self.max_cart_vel
135
+
136
+ quat_low_wxyz = np.array([-1, -1, -1, -1])
137
+ quat_high_wxyz = np.array([1, 1, 1, 1])
138
+
139
+ low_limits = low_xyz_gripper
140
+ high_limits = high_xyz_gripper
141
+
142
+ if self.fixed_orientation is None:
143
+ low_limits.append(quat_low_wxyz)
144
+ high_limits.append(quat_high_wxyz)
145
+
146
+ action_space = gym.spaces.Box(low=low_limits, high=high_limits)
147
+ return action_space
148
+
149
+ def set_action(self, action):
150
+ self.desired_c_pos = np.array(self.robot.des_c_pos) + np.array(action[:2])
151
+ self.desired_c_pos = np.clip(
152
+ self.desired_c_pos, self.min_cart_pos, self.max_cart_pos
153
+ )
154
+
155
+ if self.fixed_orientation is None:
156
+ desired_quat = np.array(action[2:])
157
+ else:
158
+ desired_quat = self.fixed_orientation
159
+
160
+ self.controller.setDesiredPos(
161
+ np.concatenate([self.desired_c_pos, desired_quat])
162
+ )
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/gyms/gym_env_wrapper.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from abc import ABC, abstractmethod
2
+
3
+ import gym
4
+ from gym.utils import seeding
5
+ import numpy as np
6
+
7
+ from d3il.environments.d3il.d3il_sim.controllers.Controller import ControllerBase
8
+ from d3il.environments.d3il.d3il_sim.core import Scene
9
+
10
+
11
+ class GymEnvWrapper(gym.Env, ABC):
12
+
13
+ metadata = {"render.modes": ["human", "rgb_array"], "video.frames_per_second": 50}
14
+
15
+ def __init__(
16
+ self,
17
+ scene: Scene,
18
+ controller: ControllerBase,
19
+ max_steps_per_episode,
20
+ n_substeps,
21
+ debug: bool = False,
22
+ ):
23
+ self.scene = scene
24
+ self.robot = scene.robots[0]
25
+
26
+ self.controller = controller
27
+
28
+ self.max_steps_per_episode = max_steps_per_episode
29
+ self.n_substeps = n_substeps
30
+ self.env_step_counter = 0
31
+
32
+ self.episode = 0
33
+ self.terminated = False
34
+ self.debug = debug
35
+
36
+ def start(self):
37
+ self.scene.start()
38
+ self.controller.reset()
39
+
40
+ def seed(self, seed=None):
41
+ self.np_random, seed = seeding.np_random(seed)
42
+ return [seed]
43
+
44
+ def step(self, action, gripper_width=None, desired_vel=None, desired_acc=None):
45
+
46
+ if gripper_width is not None:
47
+ self.robot.set_gripper_width = gripper_width
48
+
49
+ self.robot.open_fingers()
50
+
51
+ self.controller.setSetPoint(action)
52
+ self.controller.executeControllerTimeSteps(
53
+ self.robot, self.n_substeps, block=False
54
+ )
55
+
56
+ for i in range(self.n_substeps):
57
+ self.scene.next_step()
58
+
59
+ observation = self.get_observation()
60
+ reward = self.get_reward()
61
+ done = self.is_finished()
62
+
63
+ debug_info = {}
64
+ if self.debug:
65
+ debug_info = self.debug_msg()
66
+
67
+ self.env_step_counter += 1
68
+ return observation, reward, done, debug_info
69
+
70
+ @abstractmethod
71
+ def get_observation(self) -> np.ndarray:
72
+ raise NotImplementedError
73
+
74
+ @abstractmethod
75
+ def get_reward(self):
76
+ raise NotImplementedError
77
+
78
+ @abstractmethod
79
+ def _check_early_termination(self) -> bool:
80
+ return self.terminated
81
+
82
+ def is_finished(self):
83
+ if (
84
+ self.terminated
85
+ or self._check_early_termination()
86
+ or self.env_step_counter >= self.max_steps_per_episode - 1
87
+ ):
88
+ return True
89
+ return False
90
+
91
+ def debug_msg(self) -> dict:
92
+ return {}
93
+
94
+ @abstractmethod
95
+ def _reset_env(self):
96
+ raise NotImplementedError
97
+
98
+ def reset(self):
99
+ self.terminated = False
100
+ self.env_step_counter = 0
101
+ self.episode += 1
102
+ obs = self._reset_env()
103
+
104
+ return obs
105
+
106
+ def robot_state(self):
107
+ self.robot.receiveState()
108
+
109
+ joint_pos = self.robot.current_j_pos
110
+ joint_vel = self.robot.current_j_vel
111
+
112
+ gripper_vel = self.robot.current_fing_vel
113
+ gripper_width = [self.robot.gripper_width]
114
+
115
+ tcp_pos = self.robot.current_c_pos
116
+ tcp_vel = self.robot.current_c_vel
117
+ tcp_quad = self.robot.current_c_quat
118
+
119
+ return tcp_pos
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/gyms/gym_utils/__init__.py ADDED
File without changes
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/gyms/gym_utils/helpers.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+
4
+ def obj_distance(obj1_pos, obj2_pos):
5
+ dist = np.linalg.norm(obj1_pos - obj2_pos)
6
+ rel_dist = (obj1_pos - obj2_pos) / dist + 1e-8
7
+ return dist, rel_dist
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/gyms/gym_utils/rewards.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+
4
+ class Distance:
5
+ @staticmethod
6
+ def linear(start, goal):
7
+ return np.linalg.norm(start - goal, axis=-1)
8
+
9
+ @staticmethod
10
+ def quadratic(start, goal): ...
11
+
12
+ @staticmethod
13
+ def tanh(start, goal): ...
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/SimFactory.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import abc
2
+ from functools import wraps
3
+
4
+ from d3il.environments.d3il.d3il_sim.core import Camera, RobotBase, Scene
5
+ from d3il.environments.d3il.d3il_sim.sims.universal_sim.PrimitiveObjects import (
6
+ PrimitiveObject,
7
+ )
8
+
9
+
10
+ def _register_function_on_class(cls, fn):
11
+
12
+ @wraps(fn)
13
+ def self_wrapper(self, *args, **kwargs):
14
+ return fn(self, *args, **kwargs)
15
+
16
+ setattr(cls, fn.__name__, self_wrapper)
17
+
18
+
19
+ class SimFactory(abc.ABC):
20
+
21
+ def __init__(self) -> None:
22
+ super().__init__()
23
+ fn = self.prim_loading()
24
+ if fn is not None:
25
+ _register_function_on_class(PrimitiveObject, fn)
26
+
27
+ @abc.abstractmethod
28
+ def create_scene(
29
+ self,
30
+ gin_config=None,
31
+ object_list: list = None,
32
+ dt: float = 0.001,
33
+ render: Scene.RenderMode = Scene.RenderMode.HUMAN,
34
+ *args,
35
+ **kwargs
36
+ ) -> Scene:
37
+ pass
38
+
39
+ @abc.abstractmethod
40
+ def create_robot(self, scene, *args, **kwargs) -> RobotBase:
41
+ pass
42
+
43
+ @abc.abstractmethod
44
+ def create_camera(
45
+ self,
46
+ name: str,
47
+ width: int = 1000,
48
+ height: int = 1000,
49
+ init_pos=None,
50
+ init_quat=None,
51
+ *args,
52
+ **kwargs
53
+ ) -> Camera.Camera:
54
+ pass
55
+
56
+ @abc.abstractmethod
57
+ def prim_loading(self):
58
+ return None
59
+
60
+ @property
61
+ def RenderMode(self):
62
+ return Scene.RenderMode
63
+
64
+
65
+ class SimRepository:
66
+
67
+ _repository = {}
68
+
69
+ @classmethod
70
+ def register(cls, factory: SimFactory, sim_name: str):
71
+ if sim_name in cls._repository:
72
+ return
73
+ cls._repository[sim_name] = factory
74
+
75
+ @classmethod
76
+ def get_factory(cls, sim_name: str) -> SimFactory:
77
+ return cls._repository[sim_name]
78
+
79
+ @classmethod
80
+ def list_all_sims(cls):
81
+ return cls._repository.keys()
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ from .mj_beta import *
2
+
3
+ try:
4
+ from .mj_beta import MjCamera
5
+ except ImportError:
6
+ pass
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/MjCamera.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Tuple
2
+ from xml.etree import ElementTree as Et
3
+
4
+ import numpy as np
5
+ from mujoco import MjData, MjModel, mj_name2id, mjtObj
6
+
7
+ from d3il.environments.d3il.d3il_sim.core.Camera import Camera
8
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.mj_utils.mj_helper import IncludeType
9
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.mj_utils.mj_render_singleton import (
10
+ render,
11
+ )
12
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.MjLoadable import MjLoadable
13
+ from d3il.environments.d3il.d3il_sim.utils.geometric_transformation import (
14
+ mat2posQuat,
15
+ posRotMat2TFMat,
16
+ quat2mat,
17
+ )
18
+
19
+
20
+ class MjCamera(Camera, MjLoadable):
21
+ def __init__(
22
+ self,
23
+ name: str,
24
+ width: int = 1000,
25
+ height: int = 1000,
26
+ init_pos=None,
27
+ init_quat=None,
28
+ near=0.01,
29
+ far=10,
30
+ *args,
31
+ **kwargs,
32
+ ):
33
+ super(MjCamera, self).__init__(
34
+ name, width, height, init_pos, init_quat, near=near, far=far
35
+ )
36
+ self.viewer = None
37
+ self.data = None
38
+ self.model = None
39
+
40
+ def register_sim(self, sim: Tuple[MjModel, MjData], sim_name: str):
41
+ self.model = sim[0]
42
+ self.data = sim[1]
43
+ super().register_sim(sim, sim_name)
44
+
45
+ extent = self.model.stat.extent
46
+ self.near = self.model.vis.map.znear * extent
47
+ self.far = self.model.vis.map.zfar * extent
48
+
49
+ cam_id = mj_name2id(m=self.model, name=self.name, type=mjtObj.mjOBJ_CAMERA)
50
+ self.fovy = self.model.cam_fovy[cam_id]
51
+ self.fovx = (
52
+ 2
53
+ * np.arctan(
54
+ self.width
55
+ * 0.5
56
+ / (self.height * 0.5 / np.tan(self.fovy * np.pi / 360 / 2))
57
+ )
58
+ / np.pi
59
+ * 360
60
+ )
61
+
62
+ self.fx = (self.width / 2) / (np.tan(self.fovx * np.pi / 180 / 2))
63
+ self.fy = (self.height / 2) / (np.tan(self.fovy * np.pi / 180 / 2))
64
+ self.cx = self.width / 2
65
+ self.cy = self.height / 2
66
+
67
+ self.intrinsics = np.array(
68
+ [[self.fx, 0, self.cx], [0, self.fy, self.cy], [0, 0, 1]]
69
+ )
70
+
71
+ return
72
+
73
+ def _get_img_data(
74
+ self,
75
+ width: int = None,
76
+ height: int = None,
77
+ depth: bool = True,
78
+ denormalize_depth: bool = True,
79
+ segmentation: bool = False,
80
+ ):
81
+ if width is None:
82
+ width = self.width
83
+ if height is None:
84
+ height = self.height
85
+
86
+ rendered_images = render(
87
+ cam_name=self.name,
88
+ width=width,
89
+ height=height,
90
+ depth=depth,
91
+ segmentation=segmentation,
92
+ model=self.model,
93
+ data=self.data,
94
+ )
95
+
96
+ if depth:
97
+ color_img, depth_img = rendered_images
98
+ color_img = self.vertical_flip(color_img)
99
+ depth_img = self.vertical_flip(depth_img)
100
+ if denormalize_depth:
101
+ depth_img = self.denormalize_depth(depth_img)
102
+ return color_img, depth_img
103
+ elif segmentation:
104
+ seg_img = rendered_images
105
+ seg_img = self.vertical_flip(seg_img)
106
+ return seg_img
107
+ else:
108
+ color_img = rendered_images
109
+ color_img = self.vertical_flip(color_img)
110
+ return color_img
111
+
112
+ def get_cart_pos_quat(self):
113
+ cam_id = mj_name2id(m=self.model, name=self.name, type=mjtObj.mjOBJ_CAMERA)
114
+
115
+ cam_pos = self.data.cam_xpos[cam_id]
116
+ cam_mat = self.data.cam_xmat[cam_id]
117
+ c2b_r = cam_mat.reshape((3, 3))
118
+ b2w_r = quat2mat([0, 1, 0, 0])
119
+ c2w_r = np.matmul(c2b_r, b2w_r)
120
+ c2w = posRotMat2TFMat(cam_pos, c2w_r)
121
+ pos, quat = mat2posQuat(c2w)
122
+
123
+ return pos, quat
124
+
125
+ def mj_load(self):
126
+ pos_str = " ".join(map(str, self.init_pos))
127
+ quat_str = " ".join(map(str, self.init_quat))
128
+
129
+ object_body = Et.Element("body")
130
+ object_body.set("pos", pos_str)
131
+ object_body.set("quat", quat_str)
132
+ object_body.set("name", self.name)
133
+
134
+ cam = Et.SubElement(object_body, "camera")
135
+ cam.set("name", self.name)
136
+ cam.set("fovy", str(self.fovy))
137
+
138
+ return object_body, {}, IncludeType.WORLD_BODY
139
+
140
+ def get_segmentation(self, width=None, height=None, depth=True):
141
+ data = super(MjCamera, self).get_segmentation(width, height, depth)
142
+
143
+ if depth:
144
+ data, d = data
145
+
146
+ obj_types = data[..., 0]
147
+ obj_ids = self.model.geom_bodyid[data[..., 1]]
148
+
149
+ if depth:
150
+ return obj_ids, d
151
+ return obj_ids
152
+
153
+ def vertical_flip(self, img):
154
+ return np.flipud(img)
155
+
156
+
157
+ class MjInhandCamera(MjCamera):
158
+
159
+ def __init__(
160
+ self,
161
+ robot_cam_id: str,
162
+ width: int = 96,
163
+ height: int = 96,
164
+ *args,
165
+ **kwargs,
166
+ ):
167
+ super().__init__(
168
+ robot_cam_id,
169
+ width,
170
+ height,
171
+ *args,
172
+ **kwargs,
173
+ )
174
+
175
+ def mj_load(self):
176
+
177
+ return None, None, IncludeType.VIRTUAL_INCLUDE
178
+
179
+
180
+ class MjCageCam(MjCamera):
181
+
182
+ def __init__(self, width: int = 1000, height: int = 1000, *args, **kwargs):
183
+ super().__init__(
184
+ "rgbd_cage",
185
+ width,
186
+ height,
187
+ init_pos=[0.7, 0.1, 0.9],
188
+ init_quat=[
189
+ 0.6830127,
190
+ 0.1830127,
191
+ 0.1830127,
192
+ 0.683012,
193
+ ],
194
+ *args,
195
+ **kwargs,
196
+ )
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/MjFactory.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gin
2
+
3
+ import d3il.environments.d3il.d3il_sim.sims.SimFactory as Sims
4
+ from d3il.environments.d3il.d3il_sim.core import Camera, RobotBase, Scene
5
+ from d3il.environments.d3il.d3il_sim.utils.sim_path import d3il_path
6
+
7
+ from .MjCamera import MjCamera
8
+ from .MjPrimLoader import mj_load
9
+ from .MjRobot import MjRobot
10
+ from .MjScene import MjScene
11
+
12
+
13
+ class MjFactory(Sims.SimFactory):
14
+ def create_scene(
15
+ self,
16
+ gin_path=None,
17
+ object_list: list = None,
18
+ dt: float = 0.001,
19
+ render: Scene.RenderMode = Scene.RenderMode.HUMAN,
20
+ *args,
21
+ **kwargs
22
+ ) -> Scene:
23
+
24
+ if gin_path is None:
25
+ gin_path = d3il_path(
26
+ "d3il_sim/controllers/Config/mujoco_controller_config.gin"
27
+ )
28
+ gin.parse_config_file(gin_path)
29
+ return MjScene(object_list, dt, render, *args, **kwargs)
30
+
31
+ def create_robot(self, scene, *args, **kwargs) -> RobotBase:
32
+ return MjRobot(scene, *args, **kwargs)
33
+
34
+ def create_camera(
35
+ self,
36
+ name: str,
37
+ width: int = 1000,
38
+ height: int = 1000,
39
+ init_pos=None,
40
+ init_quat=None,
41
+ *args,
42
+ **kwargs
43
+ ) -> Camera:
44
+ return MjCamera(name, width, height, init_pos, init_quat)
45
+
46
+ def prim_loading(self):
47
+ return mj_load
48
+
49
+
50
+ Sims.SimRepository.register(MjFactory(), "mj_beta")
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/MjLoadable.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import abc
2
+ import os
3
+ import xml.etree.ElementTree as Et
4
+ from typing import Tuple
5
+
6
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.mj_utils.mj_helper import IncludeType
7
+
8
+
9
+ class MjLoadable(abc.ABC):
10
+
11
+ @abc.abstractmethod
12
+ def mj_load(self) -> Tuple[Et.Element, list, IncludeType]:
13
+ raise NotImplementedError
14
+
15
+
16
+ class MjXmlLoadable(MjLoadable):
17
+
18
+ def __init__(self, full_xml_path, asset_path=None) -> None:
19
+ super().__init__()
20
+ self._full_xml_path = full_xml_path
21
+ self._asset_path = asset_path
22
+
23
+ @property
24
+ def loadable_dir(self):
25
+ return os.path.split(self._full_xml_path)[0]
26
+
27
+ @property
28
+ def asset_path(self):
29
+ if self._asset_path is not None:
30
+ return self._asset_path
31
+ return os.path.join(self.loadable_dir, "assets")
32
+
33
+ @property
34
+ def file_name(self):
35
+ return os.path.split(self._full_xml_path)[1]
36
+
37
+ def mj_load(self) -> Tuple[Et.Element, list, IncludeType]:
38
+ et_include = Et.Element("include")
39
+ et_include.set("file", self.file_name)
40
+ assets = {}
41
+
42
+ if os.path.isdir(self.asset_path):
43
+ for dirpath, dirnames, files in os.walk(self.asset_path):
44
+ for f in files:
45
+ with open(os.path.join(dirpath, f), "rb") as file:
46
+ assets[f] = file.read()
47
+
48
+ with open(os.path.join(self._full_xml_path), "rb") as file:
49
+ assets[self.file_name] = file.read()
50
+ return et_include, assets, IncludeType.FILE_INCLUDE
51
+
52
+
53
+ class MjIncludeTemplate(MjXmlLoadable):
54
+ def __init__(self, full_xml_path, asset_path=None) -> None:
55
+ super().__init__(full_xml_path, asset_path)
56
+ self._tmp_filled_xml = None
57
+
58
+ @abc.abstractmethod
59
+ def modify_template(self, et: Et.ElementTree) -> Et.ElementTree:
60
+ pass
61
+
62
+ def mj_load(self) -> Tuple[Et.Element, list, IncludeType]:
63
+ inc, assets, include_type = super().mj_load()
64
+
65
+ obj = Et.parse(self._full_xml_path)
66
+ new_xml = self.modify_template(obj)
67
+
68
+ self._tmp_filled_xml = new_xml
69
+
70
+ et_include = Et.Element("include")
71
+ et_include.set("file", new_xml)
72
+ return et_include, assets, include_type
73
+
74
+ def cleanup(self):
75
+ if self._tmp_filled_xml is not None:
76
+ os.remove(self._tmp_filled_xml)
77
+
78
+
79
+ class MjFreezable:
80
+ @abc.abstractmethod
81
+ def freeze(self, data, model):
82
+ pass
83
+
84
+ @abc.abstractmethod
85
+ def unfreeze(self, data, model):
86
+ pass
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/MjPrimLoader.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import xml.etree.ElementTree as Et
2
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.mj_utils.mj_helper import IncludeType
3
+
4
+
5
+ def mj_load(prim_obj, *args, **kwargs):
6
+ pos_str = " ".join(map(str, prim_obj.init_pos))
7
+ orientation_str = " ".join(map(str, prim_obj.init_quat))
8
+ mass_str = str(prim_obj.mass)
9
+ size_str = " ".join(map(str, prim_obj.size))
10
+ rgba_str = " ".join(map(str, prim_obj.rgba))
11
+
12
+ object_body = Et.Element("body")
13
+ object_body.set("name", prim_obj.name)
14
+ object_body.set("pos", pos_str)
15
+ object_body.set("quat", orientation_str)
16
+
17
+ geom = Et.SubElement(object_body, "geom")
18
+ geom.set("type", prim_obj.type.value)
19
+ geom.set("name", "{}:geom".format(prim_obj.name))
20
+ if prim_obj.mass:
21
+ geom.set("mass", mass_str)
22
+ geom.set("size", size_str)
23
+ geom.set("rgba", rgba_str)
24
+
25
+ if prim_obj.visual_only:
26
+ geom.set("contype", "0")
27
+ geom.set("conaffinity", "0")
28
+
29
+ if not prim_obj.static:
30
+ Et.SubElement(object_body, "freejoint")
31
+
32
+ if prim_obj.solimp is not None:
33
+ geom.set("solimp", " ".join(prim_obj.solimp))
34
+ if prim_obj.solref is not None:
35
+ geom.set("solref", " ".join(prim_obj.solref))
36
+
37
+ inc_type = IncludeType.WORLD_BODY
38
+ return object_body, {}, inc_type
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/MjRobot.py ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import xml.etree.ElementTree as Et
2
+
3
+ import mujoco
4
+ import numpy as np
5
+
6
+ from d3il.environments.d3il.d3il_sim.controllers.Controller import (
7
+ ModelBasedFeedforwardController,
8
+ )
9
+ from d3il.environments.d3il.d3il_sim.core import RobotBase
10
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.mj_utils.mj_helper import (
11
+ IncludeType,
12
+ get_body_xvelp,
13
+ get_body_xvelr,
14
+ )
15
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.MjCamera import MjInhandCamera
16
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.MjLoadable import (
17
+ MjIncludeTemplate,
18
+ MjXmlLoadable,
19
+ )
20
+ from d3il.environments.d3il.d3il_sim.utils import sim_path
21
+
22
+
23
+ class MjRobot(RobotBase, MjIncludeTemplate):
24
+ GLOBAL_MJ_ROBOT_COUNTER = 0
25
+
26
+ def __init__(
27
+ self,
28
+ scene,
29
+ dt=1e-3,
30
+ num_DoF=7,
31
+ base_position=None,
32
+ base_orientation=None,
33
+ gravity_comp=True,
34
+ clip_actions=False,
35
+ root=sim_path.D3IL_DIR,
36
+ xml_path=None,
37
+ ):
38
+ RobotBase.__init__(self, scene, dt, num_DoF, base_position, base_orientation)
39
+
40
+ if xml_path is None:
41
+ xml_path = sim_path.d3il_path("models/mj/robot/panda.xml")
42
+ MjXmlLoadable.__init__(self, xml_path)
43
+
44
+ self.clip_actions = clip_actions
45
+ self.gravity_comp = gravity_comp
46
+
47
+ self.joint_names = None
48
+ self.joint_indices = None
49
+ self.joint_act_indices = None
50
+
51
+ self.gripper_names = None
52
+ self.gripper_indices = None
53
+ self.gripper_act_indices = None
54
+
55
+ self.jointTrackingController = ModelBasedFeedforwardController()
56
+
57
+ self._mj_robot_id = MjRobot.GLOBAL_MJ_ROBOT_COUNTER
58
+ MjRobot.GLOBAL_MJ_ROBOT_COUNTER += 1
59
+ self.root = root
60
+
61
+ self.inhand_cam = MjInhandCamera(self.add_id2model_key("rgbd"))
62
+
63
+ self.qpos_freeze = None
64
+ self.qvel_freeze = None
65
+ self.ctrl_freeze = None
66
+
67
+ def _getJacobian_internal(self, q=None):
68
+ jac = np.zeros((6, 7))
69
+ if q is not None:
70
+
71
+ cur_sim_state = self.scene.sim.get_state()
72
+ qpos_idx = self.joint_indices
73
+ self.scene.sim.data.qpos[qpos_idx] = q
74
+ mujoco.mj_kinematics(self.scene.model, self.scene.sim.data)
75
+ mujoco.mj_comPos(self.scene.model, self.scene.sim.data)
76
+
77
+ tcp_id = self.add_id2model_key("tcp")
78
+ jac[:3, :] = self.scene.sim.data.get_body_jacp(tcp_id).reshape((3, -1))[
79
+ :, -9:-2
80
+ ]
81
+ jac[3:, :] = self.scene.sim.data.get_body_jacr(tcp_id).reshape((3, -1))[
82
+ :, -9:-2
83
+ ]
84
+
85
+ if q is not None:
86
+ self.scene.sim.set_state(cur_sim_state)
87
+ return jac
88
+
89
+ def _getForwardKinematics_internal(self, q=None):
90
+ if q is not None:
91
+ cur_sim_state = self.scene.sim.get_state()
92
+ qpos_idx = self.joint_indices
93
+ self.scene.data.qpos[qpos_idx] = q
94
+ mujoco.mj_kinematics(self.scene.model, self.scene.data)
95
+
96
+ tcp_id = self.add_id2model_key("tcp")
97
+ cart_pos = self.scene.data.get_body_xpos(tcp_id)
98
+ cart_or = self.scene.data.get_body_xquat(tcp_id)
99
+ if q is not None:
100
+ self.scene.sim.set_state(cur_sim_state)
101
+ return cart_pos, cart_or
102
+
103
+ def prepare_step(self):
104
+ self.command = self.activeController.getControl(self)
105
+
106
+ self.preprocessCommand(self.command)
107
+ self.scene.data.ctrl[self.joint_act_indices] = self.uff.copy()[: self.num_DoF]
108
+ self.scene.data.ctrl[self.gripper_act_indices] = self.finger_commands
109
+ self.receiveState()
110
+
111
+ def receiveState(self):
112
+ if self.joint_indices is None:
113
+ self._init_jnt_indices()
114
+
115
+ tcp_name = self.add_id2model_key("tcp")
116
+
117
+ self.current_j_pos = np.array(
118
+ [self.scene.data.joint(name).qpos.copy() for name in self.joint_names]
119
+ ).squeeze()
120
+ self.current_j_vel = np.array(
121
+ [self.scene.data.joint(name).qvel.copy() for name in self.joint_names]
122
+ ).squeeze()
123
+
124
+ test = self.scene.data.body(tcp_name)
125
+ self.current_c_pos_global = self.scene.data.body(tcp_name).xpos.copy()
126
+ self.current_c_vel_global = get_body_xvelp(
127
+ self.scene.model,
128
+ self.scene.data,
129
+ tcp_name,
130
+ )
131
+ self.current_c_quat_global = self.scene.data.body(tcp_name).xquat.copy()
132
+ self.current_c_quat_vel_global = np.zeros(4)
133
+
134
+ self.current_c_quat_vel_global[1:] = get_body_xvelr(
135
+ self.scene.model, self.scene.data, tcp_name
136
+ )
137
+ self.current_c_quat_vel_global *= 0.5 * self.current_c_quat_global
138
+
139
+ self.current_c_pos, self.current_c_quat = self._localize_cart_coords(
140
+ self.current_c_pos_global, self.current_c_quat_global
141
+ )
142
+ self.current_c_vel, _ = self._localize_cart_coords(
143
+ self.current_c_vel_global + self.base_position
144
+ )
145
+ _, self.current_c_quat_vel = self._localize_cart_coords(
146
+ self.base_position, self.current_c_quat_vel_global
147
+ )
148
+
149
+ self.current_fing_pos = np.array(
150
+ [self.scene.data.joint(name).qpos.copy() for name in self.gripper_names]
151
+ ).squeeze()
152
+ self.current_fing_vel = np.array(
153
+ [self.scene.data.joint(name).qvel.copy() for name in self.gripper_names]
154
+ ).squeeze()
155
+ self.gripper_width = self.current_fing_pos[-2] + self.current_fing_pos[-1]
156
+
157
+ def get_command_from_inverse_dynamics(self, target_j_acc, mj_calc_inv=False):
158
+ if mj_calc_inv:
159
+ self.scene.data.qacc[self.joint_vel_indices + self.gripper_vel_indices] = (
160
+ target_j_acc
161
+ )
162
+ mujoco.mj_inverse(self.scene.model, self.scene.sim.data)
163
+ return self.scene.data.qfrc_inverse[
164
+ self.joint_vel_indices + self.gripper_vel_indices
165
+ ]
166
+ else:
167
+ return self.scene.data.qfrc_bias[
168
+ self.joint_vel_indices + self.gripper_vel_indices
169
+ ]
170
+
171
+ def get_init_qpos(self):
172
+ return np.array(
173
+ [
174
+ 3.57795216e-09,
175
+ 1.74532920e-01,
176
+ 3.30500960e-08,
177
+ -8.72664630e-01,
178
+ -1.14096181e-07,
179
+ 1.22173047e00,
180
+ 7.85398126e-01,
181
+ ]
182
+ )
183
+
184
+ def _init_jnt_indices(self):
185
+ n_joints = len(self.joint_names)
186
+ assert (
187
+ n_joints == self.num_DoF
188
+ ), "Error, found {} joints, but expected {}".format(n_joints, self.num_DoF)
189
+ assert (
190
+ len(self.gripper_names) == 2
191
+ ), "Error, found more gripper joints than expected."
192
+
193
+ self.joint_indices = []
194
+ self.joint_vel_indices = []
195
+ self.gripper_indices = []
196
+ self.gripper_vel_indices = []
197
+ for jnt_name in self.joint_names:
198
+ jnt_id = mujoco.mj_name2id(
199
+ self.scene.model, type=mujoco.mjtObj.mjOBJ_JOINT, name=jnt_name
200
+ )
201
+ self.joint_indices.append(self.scene.model.jnt_qposadr[jnt_id])
202
+ self.joint_vel_indices.append(self.scene.model.jnt_dofadr[jnt_id])
203
+ for grp_name in self.gripper_names:
204
+ grp_id = mujoco.mj_name2id(
205
+ self.scene.model, type=mujoco.mjtObj.mjOBJ_JOINT, name=grp_name
206
+ )
207
+ self.gripper_indices.append(self.scene.model.jnt_qposadr[grp_id])
208
+ self.gripper_vel_indices.append(self.scene.model.jnt_dofadr[grp_id])
209
+ self.joint_act_indices = [
210
+ mujoco.mj_name2id(
211
+ self.scene.model, type=mujoco.mjtObj.mjOBJ_ACTUATOR, name=name + "_act"
212
+ )
213
+ for name in self.joint_names
214
+ ]
215
+ self.gripper_act_indices = [
216
+ mujoco.mj_name2id(
217
+ self.scene.model, type=mujoco.mjtObj.mjOBJ_ACTUATOR, name=name + "_act"
218
+ )
219
+ for name in self.gripper_names
220
+ ]
221
+
222
+ def set_q(self, joint_pos):
223
+ if self.joint_indices is None:
224
+ self._init_jnt_indices()
225
+
226
+ qpos = self.scene.data.qpos.copy()
227
+ qpos[self.joint_indices] = joint_pos
228
+
229
+ qvel = self.scene.data.qvel.copy()
230
+ qvel[self.joint_vel_indices] = np.zeros(len(self.joint_vel_indices))
231
+ self.scene.set_state(qpos, qvel)
232
+
233
+ def add_id2model_key(self, model_key_id: str) -> str:
234
+ attrib_split = model_key_id.split("_")
235
+ attrib_split.insert(1, "rb{}".format(self._mj_robot_id))
236
+ attrib_id = "_".join(attrib_split)
237
+ return attrib_id
238
+
239
+ def modify_template(self, et: Et.ElementTree) -> str:
240
+ self.joint_names = None
241
+ self.joint_indices = None
242
+ self.joint_act_indices = None
243
+
244
+ self.gripper_names = None
245
+ self.gripper_indices = None
246
+ self.gripper_act_indices = None
247
+
248
+ for node in et.iter():
249
+ for attrib in [
250
+ "body1",
251
+ "body2",
252
+ "name",
253
+ "class",
254
+ "childclass",
255
+ "mesh",
256
+ "site",
257
+ "joint",
258
+ ]:
259
+ if attrib in node.attrib:
260
+ model_key_id = node.get(attrib)
261
+ attrib_id = self.add_id2model_key(model_key_id)
262
+ node.set(attrib, attrib_id)
263
+
264
+ wb = et.find("worldbody")
265
+ body_root = wb.find("body")
266
+ body_root.set("pos", " ".join(map(str, self.base_position)))
267
+ body_root.set("quat", " ".join(map(str, self.base_orientation)))
268
+
269
+ self.joint_names = []
270
+ self.gripper_names = []
271
+ for jnt in wb.iter("joint"):
272
+ if jnt.get("name") is not None and jnt.get("name").startswith(
273
+ self.add_id2model_key("panda_joint")
274
+ ):
275
+ self.joint_names.append(jnt.get("name"))
276
+ if jnt.get("name") is not None and jnt.get("name").startswith(
277
+ self.add_id2model_key("panda_finger_joint")
278
+ ):
279
+ self.gripper_names.append(jnt.get("name"))
280
+
281
+ import uuid
282
+
283
+ new_path = sim_path.d3il_path(
284
+ f"models/mj/robot/panda_tmp_rb{self._mj_robot_id}_{uuid.uuid1()}.xml"
285
+ )
286
+ et.write(new_path)
287
+ return new_path
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/MjScene.py ADDED
@@ -0,0 +1,282 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import itertools
2
+ import logging
3
+ import os
4
+ from typing import List, Tuple
5
+
6
+ import mujoco
7
+ import numpy as np
8
+ from mujoco import MjData, MjModel, mj_name2id, mjtObj
9
+
10
+ from d3il.environments.d3il.d3il_sim.core.Scene import Scene
11
+ from d3il.environments.d3il.d3il_sim.core.sim_object.sim_object import (
12
+ IntelligentSimObject,
13
+ SimObject,
14
+ )
15
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.mj_utils.mj_render_singleton import (
16
+ reset_singleton as reset_render_singleton,
17
+ )
18
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.mj_utils.mj_renderer import Viewer
19
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.mj_utils.mj_scene_object import (
20
+ MjSurrounding,
21
+ )
22
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.mj_utils.mj_scene_parser import (
23
+ MjSceneParser,
24
+ )
25
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.MjCamera import MjCageCam, MjCamera
26
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.MjLoadable import (
27
+ MjFreezable,
28
+ MjXmlLoadable,
29
+ )
30
+ from d3il.environments.d3il.d3il_sim.utils import sim_path
31
+
32
+
33
+ class MjScene(Scene):
34
+ def __init__(
35
+ self,
36
+ object_list=None,
37
+ dt=0.001,
38
+ render=Scene.RenderMode.HUMAN,
39
+ surrounding=None,
40
+ random_env=False,
41
+ main_xml_path=None,
42
+ ):
43
+
44
+ super(MjScene, self).__init__(object_list=object_list, dt=dt, render=render)
45
+
46
+ self.data: MjData = None
47
+ self.model: MjModel = None
48
+ self.viewer: Viewer = None
49
+ self.rt_obj = []
50
+
51
+ self.init_qpos, self.init_qvel = None, None
52
+ self.random_env = random_env
53
+
54
+ if surrounding is None:
55
+ surrounding = sim_path.d3il_path(
56
+ "models/mujoco/surroundings/lab_surrounding.xml"
57
+ )
58
+
59
+ self.surrounding = MjSurrounding(
60
+ surrounding_name=os.path.split(os.path.splitext(surrounding)[0])[-1],
61
+ root=os.path.dirname(surrounding),
62
+ )
63
+
64
+ self.mj_scene_parser = MjSceneParser(main_xml_path=main_xml_path)
65
+
66
+ self.cage_cam = MjCageCam()
67
+ self.add_object(self.cage_cam)
68
+
69
+ @property
70
+ def sim_name(self) -> str:
71
+ return "mj"
72
+
73
+ def _setup_scene(self):
74
+ for rb in self.robots:
75
+ self.add_object(rb.inhand_cam)
76
+
77
+ self.model, self.data = self.mj_scene_parser.create_scene(
78
+ self.robots, self.surrounding, self.obj_repo.get_obj_list(), self.dt
79
+ )
80
+
81
+ self.viewer = None
82
+ if self.render_mode == self.RenderMode.HUMAN:
83
+ self.viewer = Viewer(self.model, self.data)
84
+ self.init_qpos = self.data.qpos.copy()
85
+ self.init_qvel = np.zeros(self.data.qvel.shape)
86
+
87
+ self._setup_objects(self.obj_repo.get_obj_list())
88
+
89
+ def set_views(self, views):
90
+ if self.render_mode == self.RenderMode.HUMAN:
91
+ cam_ids = []
92
+ for v in views:
93
+ cam_ids.append(
94
+ mujoco.mj_name2id(self.model, mujoco.mjtObj.mjOBJ_CAMERA, v.name)
95
+ )
96
+ self.viewer.set_cameras(cam_ids)
97
+
98
+ def load_robot_to_scene(self, robot_init_qpos: np.ndarray = None):
99
+ if robot_init_qpos is None:
100
+ robot_init_qpos = np.stack([robot.get_init_qpos() for robot in self.robots])
101
+ else:
102
+ robot_init_qpos = np.asarray(robot_init_qpos)
103
+ if robot_init_qpos.ndim == 1:
104
+ robot_init_qpos = np.expand_dims(robot_init_qpos, 0)
105
+
106
+ for i in range(len(self.robots)):
107
+ self.robots[i].beam_to_joint_pos(robot_init_qpos[i], run=False)
108
+ self.init_qpos = self.data.qpos.copy()
109
+
110
+ def _sim_step(self):
111
+ mujoco.mj_step(self.model, self.data)
112
+
113
+ def sim_steps(self, n_steps):
114
+ mujoco.mj_step(self.model, self.data, n_steps)
115
+
116
+ def render(self):
117
+ if self.render_mode == self.RenderMode.HUMAN:
118
+ self.viewer.render()
119
+
120
+ def reset(self, obj_pos=None):
121
+ if obj_pos is None:
122
+ obj_pos = []
123
+
124
+ for rb in self.robots:
125
+ rb.reset()
126
+
127
+ mujoco.mj_resetData(self.model, self.data)
128
+
129
+ qpos = self.data.qpos.copy()
130
+ qpos[:] = self.init_qpos
131
+
132
+ qvel = np.zeros(self.data.qvel.shape)
133
+ self.set_state(qpos, qvel)
134
+
135
+ for obj, new_pos in obj_pos:
136
+ self.set_obj_pos(new_pos, obj)
137
+
138
+ mujoco.mj_forward(self.model, self.data)
139
+
140
+ for rb in self.robots:
141
+ rb.receiveState()
142
+
143
+ def add_object_rt(self, new_obj: MjXmlLoadable):
144
+ for obj in itertools.chain(self.obj_repo.get_obj_list(), self.robots):
145
+ if isinstance(obj, MjFreezable):
146
+ obj.freeze(self.model, self.data)
147
+
148
+ self.obj_repo.add_object(new_obj)
149
+ self.obj_repo.register_obj_id(new_obj, len(self.obj_repo.get_obj_list()))
150
+ if isinstance(new_obj, IntelligentSimObject):
151
+ new_obj.register_sim((self.model, self.data), self.sim_name)
152
+
153
+ self.mj_scene_parser = MjSceneParser()
154
+ self.model, self.data = self.mj_scene_parser.create_scene(
155
+ self.robots, self.surrounding, self.obj_repo.get_obj_list(), self.dt
156
+ )
157
+
158
+ reset_render_singleton()
159
+ if self.render_mode == self.RenderMode.HUMAN:
160
+ self.viewer.reinit(self.model, self.data)
161
+
162
+ self.init_qpos = self.data.qpos.copy()
163
+ self.init_qvel = np.zeros(self.data.qvel.shape)
164
+ self.load_robot_to_scene()
165
+
166
+ for obj in itertools.chain(self.obj_repo.get_obj_list(), self.robots):
167
+ if isinstance(obj, MjFreezable):
168
+ obj.unfreeze(self.model, self.data)
169
+ self.rt_obj.append(new_obj)
170
+
171
+ def obj_reset(self):
172
+ for obj in self.rt_obj:
173
+ self.obj_repo.remove_object(obj)
174
+
175
+ for obj in itertools.chain(self.obj_repo.get_obj_list(), self.robots):
176
+ if isinstance(obj, MjFreezable):
177
+ obj.freeze(self.model, self.data)
178
+
179
+ self.mj_scene_parser = MjSceneParser()
180
+ self.model, self.data = self.mj_scene_parser.create_scene(
181
+ self.robots, self.surrounding, self.obj_repo.get_obj_list(), self.dt
182
+ )
183
+ if self.render_mode == self.RenderMode.HUMAN:
184
+ self.viewer.reinit(self.model, self.data)
185
+
186
+ self.init_qpos = self.data.qpos.copy()
187
+ self.init_qvel = np.zeros(self.data.qvel.shape)
188
+ self.load_robot_to_scene()
189
+
190
+ for obj in itertools.chain(self.obj_repo.get_obj_list(), self.robots):
191
+ if isinstance(obj, MjFreezable):
192
+ obj.unfreeze(self.model, self.data)
193
+ self.rt_objects = []
194
+
195
+ def start_recording(self, nframes):
196
+ if self.render_mode == self.RenderMode.HUMAN:
197
+ self.viewer.start_recording(nframes=nframes)
198
+
199
+ def _setup_objects(self, sim_objs: List[SimObject]):
200
+ for i, obj in enumerate(sim_objs):
201
+ self.obj_repo.register_obj_id(obj, i)
202
+
203
+ if isinstance(obj, IntelligentSimObject):
204
+ obj.register_sim((self.model, self.data), self.sim_name)
205
+
206
+ def _rt_add_object(self, sim_obj: SimObject):
207
+ raise RuntimeError(
208
+ "Adding objects in MuJoCo only possible prior to scene setup."
209
+ )
210
+
211
+ def _get_obj_seg_id(self, obj_name: str):
212
+ return mj_name2id(self.model, 1, obj_name)
213
+
214
+ def _get_obj_pos(self, poi, sim_obj: SimObject):
215
+ pos, quat = self._get_obj_pos_and_quat(poi=poi, sim_obj=sim_obj)
216
+ return pos
217
+
218
+ def _get_obj_quat(self, poi, sim_obj: SimObject):
219
+ pos, quat = self._get_obj_pos_and_quat(poi=poi, sim_obj=sim_obj)
220
+ return quat
221
+
222
+ def _get_obj_pos_and_quat(self, poi, sim_obj: SimObject):
223
+ body_id = mj_name2id(self.model, mjtObj.mjOBJ_BODY, sim_obj.name)
224
+ body_jnt_addr = self.model.body_jntadr[body_id]
225
+ qposadr = self.model.jnt_qposadr[body_jnt_addr]
226
+
227
+ if body_jnt_addr == -1:
228
+ pos = self.model.body_pos[body_id]
229
+ quat = self.model.body_quat[body_id]
230
+ else:
231
+ pos = self.data.qpos[qposadr : qposadr + 3]
232
+ quat = self.data.qpos[qposadr + 3 : qposadr + 7]
233
+
234
+ return pos.copy(), quat.copy()
235
+
236
+ def _set_obj_pos(self, new_pos, sim_obj: SimObject):
237
+ self._set_obj_pos_and_quat(new_pos, None, sim_obj=sim_obj)
238
+
239
+ def _set_obj_quat(self, new_quat, sim_obj: SimObject):
240
+ self._set_obj_pos_and_quat(None, new_quat, sim_obj=sim_obj)
241
+
242
+ def _set_obj_pos_and_quat(self, new_pos, new_quat, sim_obj: SimObject):
243
+ if new_pos is None and new_quat is None:
244
+ logging.getLogger(__name__).warning(
245
+ "Expected at least either a new position or quaternion for set_obj_pos_and_quat"
246
+ )
247
+ return
248
+
249
+ body_id = mj_name2id(self.model, mjtObj.mjOBJ_BODY, sim_obj.name)
250
+ body_jnt_addr = self.model.body_jntadr[body_id]
251
+ qposadr = self.model.jnt_qposadr[body_jnt_addr]
252
+
253
+ if new_pos is not None:
254
+ assert len(new_pos) == 3, print(
255
+ f"Expected a positions list of 3 values, got {len(new_pos)}"
256
+ )
257
+
258
+ if body_jnt_addr == -1:
259
+ self.model.body_pos[body_id] = new_pos
260
+ else:
261
+ self.data.qpos[qposadr : qposadr + 3] = new_pos
262
+
263
+ if new_quat is not None:
264
+ assert len(new_quat) == 4, print(
265
+ f"Expected a quaternions list of 4 values, got {len(new_quat)}"
266
+ )
267
+ if body_jnt_addr == -1:
268
+ self.model.body_quat[body_id] = new_quat
269
+ else:
270
+ self.data.qpos[qposadr + 3 : qposadr + 7] = new_quat
271
+
272
+ def _remove_object(self, sim_obj: SimObject):
273
+ raise RuntimeError(
274
+ "Removing objects in MuJoCo only possible prior to scene setup."
275
+ )
276
+
277
+ def set_state(self, qpos, qvel):
278
+ self.data.qpos[:] = np.copy(qpos)
279
+ self.data.qvel[:] = np.copy(qvel)
280
+ if self.model.na == 0:
281
+ self.data.act[:] = None
282
+ mujoco.mj_forward(self.model, self.data)
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/__init__.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+
3
+ try:
4
+ import mujoco
5
+
6
+ from .MjFactory import *
7
+ from .MjCamera import MjCamera
8
+ except ImportError as e:
9
+ logging.getLogger(__name__).info(e)
10
+ logging.getLogger(__name__).info(
11
+ "No MuJoCo bindings are(new bindings from DeepMind) installed.",
12
+ "Install MuJoCo >= 2.1.5 and load bindings via pip, conda or mamba",
13
+ )
14
+ pass
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/mj_utils/__init__.py ADDED
File without changes
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/mj_utils/mj_helper.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from enum import Enum
2
+
3
+ import mujoco
4
+ import numpy as np
5
+
6
+
7
+ class IncludeType(Enum):
8
+ FILE_INCLUDE = 0
9
+ MJ_INCLUDE = 1
10
+ WORLD_BODY = 2
11
+ VIRTUAL_INCLUDE = 3
12
+
13
+
14
+ def change_domain(value, in_low, in_high, out_low, out_high):
15
+ return (out_high - out_low) * ((value - in_low) / (in_high - in_low)) + out_low
16
+
17
+
18
+ def obj_position(data, obj_id: str):
19
+ return data.get_body_xpos(obj_id)
20
+
21
+
22
+ def obj_distance(data, obj1: str, obj2: str):
23
+ obj1_pos = obj_position(data, obj1)
24
+ obj2_pos = obj_position(data, obj2)
25
+ dist = np.linalg.norm(obj1_pos - obj2_pos)
26
+ rel_dist = (obj1_pos - obj2_pos) / dist + 1e-8
27
+ return dist, rel_dist
28
+
29
+
30
+ def reset_mocap2body_xpos(model, data):
31
+
32
+ if model.eq_type is None or model.eq_obj1id is None or model.eq_obj2id is None:
33
+ return
34
+ for eq_type, obj1_id, obj2_id in zip(
35
+ model.eq_type, model.eq_obj1id, model.eq_obj2id
36
+ ):
37
+ if eq_type != mujoco.const.EQ_WELD:
38
+ continue
39
+
40
+ mocap_id = model.body_mocapid[obj1_id]
41
+ if mocap_id != -1:
42
+ body_idx = obj2_id
43
+ else:
44
+ mocap_id = model.body_mocapid[obj2_id]
45
+ body_idx = obj1_id
46
+
47
+ assert mocap_id != -1
48
+ data.mocap_pos[mocap_id][:] = data.body_xpos[body_idx]
49
+ data.mocap_quat[mocap_id][:] = data.body_xquat[body_idx]
50
+
51
+
52
+ def get_body_jacr(model, data, name):
53
+ id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_BODY, name)
54
+ jacr = np.zeros((3, model.nv))
55
+ mujoco.mj_jacBody(model, data, None, jacr, body=id)
56
+ return jacr
57
+
58
+
59
+ def get_body_jacp(model, data, name):
60
+ id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_BODY, name)
61
+ jacp = np.zeros((3, model.nv))
62
+ mujoco.mj_jacBody(model, data, jacp, None, body=id)
63
+ return jacp
64
+
65
+
66
+ def get_body_xvelp(model, data, name):
67
+ jacp = get_body_jacp(model, data, name).reshape((3, model.nv))
68
+ xvelp = np.dot(jacp, data.qvel.copy())
69
+ return xvelp
70
+
71
+
72
+ def get_body_xvelr(model, data, name):
73
+ jacr = get_body_jacr(model, data, name).reshape((3, model.nv))
74
+ xvelr = np.dot(jacr, data.qvel.copy())
75
+ return xvelr
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/mj_utils/mj_render_singleton.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from mujoco import MjData, MjModel, mj_name2id, mjtObj
2
+
3
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.mj_utils.mj_renderer import (
4
+ RenderContext,
5
+ RenderContextOffscreen,
6
+ )
7
+
8
+ __RENDER_CTX_MAP = {}
9
+
10
+
11
+ def reset_singleton():
12
+ global __RENDER_CTX_MAP
13
+ keys = list(__RENDER_CTX_MAP.keys())
14
+ for key in keys:
15
+ del __RENDER_CTX_MAP[key]
16
+ __RENDER_CTX_MAP = {}
17
+
18
+
19
+ def get_renderer(
20
+ name: str, width: int, height: int, model: MjModel, data: MjData
21
+ ) -> RenderContextOffscreen:
22
+ global __RENDER_CTX_MAP
23
+ if name not in __RENDER_CTX_MAP:
24
+ ctx = RenderContextOffscreen(width, height, model, data)
25
+ __RENDER_CTX_MAP[name] = ctx
26
+ ctx = __RENDER_CTX_MAP[name]
27
+ return ctx
28
+
29
+
30
+ def render(
31
+ cam_name: str,
32
+ width: int,
33
+ height: int,
34
+ model: MjModel,
35
+ data: MjData,
36
+ depth: bool,
37
+ segmentation: bool,
38
+ ):
39
+
40
+ ctx = get_renderer(cam_name, width, height, model, data)
41
+ ctx.opengl_context.make_current()
42
+ cam_id = mj_name2id(m=model, name=cam_name, type=mjtObj.mjOBJ_CAMERA)
43
+ ctx.render(width, height, cam_id, segmentation=segmentation)
44
+ return ctx.read_pixels(width, height, depth=depth, segmentation=segmentation)
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/mj_utils/mj_renderer.py ADDED
@@ -0,0 +1,593 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import collections
2
+ import os
3
+ import time
4
+ from threading import Lock
5
+ from typing import List
6
+
7
+ import glfw
8
+ import imageio
9
+ import mujoco
10
+ import numpy as np
11
+
12
+
13
+ def _import_egl(width, height):
14
+ from mujoco.egl import GLContext
15
+
16
+ return GLContext(width, height)
17
+
18
+
19
+ def _import_glfw(width, height):
20
+ from mujoco.glfw import GLContext
21
+
22
+ return GLContext(width, height)
23
+
24
+
25
+ def _import_osmesa(width, height):
26
+ from mujoco.osmesa import GLContext
27
+
28
+ return GLContext(width, height)
29
+
30
+
31
+ _ALL_RENDERERS = collections.OrderedDict(
32
+ [
33
+ ("glfw", _import_glfw),
34
+ ("egl", _import_egl),
35
+ ("osmesa", _import_osmesa),
36
+ ]
37
+ )
38
+
39
+
40
+ class RenderContext:
41
+
42
+ def __init__(self, model, data, offscreen=True):
43
+
44
+ self.model = model
45
+ self.data = data
46
+ self.offscreen = offscreen
47
+ max_geom = 1000
48
+
49
+ mujoco.mj_forward(self.model, self.data)
50
+
51
+ self.scn = mujoco.MjvScene(self.model, max_geom)
52
+ self.cam = mujoco.MjvCamera()
53
+ self.vopt = mujoco.MjvOption()
54
+ self.pert = mujoco.MjvPerturb()
55
+ self.con = mujoco.MjrContext(self.model, mujoco.mjtFontScale.mjFONTSCALE_150)
56
+
57
+ self._markers = []
58
+ self._overlays = {}
59
+
60
+ self._init_camera()
61
+ self._set_mujoco_buffers()
62
+
63
+ def _set_mujoco_buffers(self):
64
+ if self.offscreen:
65
+ mujoco.mjr_setBuffer(mujoco.mjtFramebuffer.mjFB_OFFSCREEN, self.con)
66
+ if self.con.currentBuffer != mujoco.mjtFramebuffer.mjFB_OFFSCREEN:
67
+ raise RuntimeError("Offscreen rendering not supported")
68
+ else:
69
+ mujoco.mjr_setBuffer(mujoco.mjtFramebuffer.mjFB_WINDOW, self.con)
70
+ if self.con.currentBuffer != mujoco.mjtFramebuffer.mjFB_WINDOW:
71
+ raise RuntimeError("Window rendering not supported")
72
+
73
+ def update_offscreen_size(self, width, height):
74
+ if width != self.con.offWidth or height != self.con.offHeight:
75
+ self.model.vis.global_.offwidth = width
76
+ self.model.vis.global_.offheight = height
77
+ self.con.free()
78
+ self.con = mujoco.MjrContext(
79
+ self.model, mujoco.mjtFontScale.mjFONTSCALE_150
80
+ )
81
+ self._set_mujoco_buffers()
82
+
83
+ def render(self, width, height, camera_id=None, segmentation=False):
84
+ rect = mujoco.MjrRect(left=0, bottom=0, width=width, height=height)
85
+
86
+ if width != self.con.offWidth or height != self.con.offHeight:
87
+ new_width = max(width, self.model.vis.global_.offwidth)
88
+ new_height = max(height, self.model.vis.global_.offheight)
89
+ self.update_offscreen_size(new_width, new_height)
90
+
91
+ if camera_id is not None:
92
+ if camera_id == -1:
93
+ self.cam.type = mujoco.mjtCamera.mjCAMERA_FREE
94
+ else:
95
+ self.cam.type = mujoco.mjtCamera.mjCAMERA_FIXED
96
+ self.cam.fixedcamid = camera_id
97
+
98
+ mujoco.mjv_updateScene(
99
+ self.model,
100
+ self.data,
101
+ self.vopt,
102
+ self.pert,
103
+ self.cam,
104
+ mujoco.mjtCatBit.mjCAT_ALL,
105
+ self.scn,
106
+ )
107
+
108
+ if segmentation:
109
+ self.scn.flags[mujoco.mjtRndFlag.mjRND_SEGMENT] = 1
110
+ self.scn.flags[mujoco.mjtRndFlag.mjRND_IDCOLOR] = 1
111
+
112
+ for marker_params in self._markers:
113
+ self._add_marker_to_scene(marker_params)
114
+
115
+ mujoco.mjr_render(rect, self.scn, self.con)
116
+
117
+ for gridpos, (text1, text2) in self._overlays.items():
118
+ mujoco.mjr_overlay(
119
+ mujoco.mjtFontScale.mjFONTSCALE_150,
120
+ gridpos,
121
+ rect,
122
+ text1.encode(),
123
+ text2.encode(),
124
+ self.con,
125
+ )
126
+
127
+ if segmentation:
128
+ self.scn.flags[mujoco.mjtRndFlag.mjRND_SEGMENT] = 0
129
+ self.scn.flags[mujoco.mjtRndFlag.mjRND_IDCOLOR] = 0
130
+
131
+ def read_pixels(self, width, height, depth=True, segmentation=False):
132
+ rect = mujoco.MjrRect(left=0, bottom=0, width=width, height=height)
133
+
134
+ rgb_arr = np.zeros(3 * rect.width * rect.height, dtype=np.uint8)
135
+ depth_arr = np.zeros(rect.width * rect.height, dtype=np.float32)
136
+
137
+ mujoco.mjr_readPixels(rgb_arr, depth_arr, rect, self.con)
138
+ rgb_img = rgb_arr.reshape(rect.height, rect.width, 3)
139
+
140
+ ret_img = rgb_img
141
+ if segmentation:
142
+ seg_img = (
143
+ rgb_img[:, :, 0]
144
+ + rgb_img[:, :, 1] * (2**8)
145
+ + rgb_img[:, :, 2] * (2**16)
146
+ )
147
+ seg_img[seg_img >= (self.scn.ngeom + 1)] = 0
148
+ seg_ids = np.full((self.scn.ngeom + 1, 2), fill_value=-1, dtype=np.int32)
149
+
150
+ for i in range(self.scn.ngeom):
151
+ geom = self.scn.geoms[i]
152
+ if geom.segid != -1:
153
+ seg_ids[geom.segid + 1, 0] = geom.objtype
154
+ seg_ids[geom.segid + 1, 1] = geom.objid
155
+ ret_img = seg_ids[seg_img]
156
+
157
+ if depth:
158
+ depth_img = depth_arr.reshape(rect.height, rect.width)
159
+ return (ret_img, depth_img)
160
+ else:
161
+ return ret_img
162
+
163
+ def _init_camera(self):
164
+ self.cam.type = mujoco.mjtCamera.mjCAMERA_FREE
165
+ self.cam.fixedcamid = -1
166
+ for i in range(3):
167
+ self.cam.lookat[i] = np.median(self.data.geom_xpos[:, i])
168
+
169
+ self.cam.azimuth = 180
170
+ self.cam.elevation = -30
171
+ self.cam.distance = self.model.stat.extent * 0.75
172
+
173
+ def add_overlay(self, gridpos: int, text1: str, text2: str):
174
+ if gridpos not in self._overlays:
175
+ self._overlays[gridpos] = ["", ""]
176
+ self._overlays[gridpos][0] += text1 + "\n"
177
+ self._overlays[gridpos][1] += text2 + "\n"
178
+
179
+ def add_marker(self, **marker_params):
180
+ self._markers.append(marker_params)
181
+
182
+ def _add_marker_to_scene(self, marker):
183
+ if self.scn.ngeom >= self.scn.maxgeom:
184
+ raise RuntimeError("Ran out of geoms. maxgeom: %d" % self.scn.maxgeom)
185
+
186
+ g = self.scn.geoms[self.scn.ngeom]
187
+ g.dataid = -1
188
+ g.objtype = mujoco.mjtObj.mjOBJ_UNKNOWN
189
+ g.objid = -1
190
+ g.category = mujoco.mjtCatBit.mjCAT_DECOR
191
+ g.texid = -1
192
+ g.texuniform = 0
193
+ g.texrepeat[0] = 1
194
+ g.texrepeat[1] = 1
195
+ g.emission = 0
196
+ g.specular = 0.5
197
+ g.shininess = 0.5
198
+ g.reflectance = 0
199
+ g.type = mujoco.mjtGeom.mjGEOM_BOX
200
+ g.size[:] = np.ones(3) * 0.1
201
+ g.mat[:] = np.eye(3)
202
+ g.rgba[:] = np.ones(4)
203
+
204
+ for key, value in marker.items():
205
+ if isinstance(value, (int, float, mujoco._enums.mjtGeom)):
206
+ setattr(g, key, value)
207
+ elif isinstance(value, (tuple, list, np.ndarray)):
208
+ attr = getattr(g, key)
209
+ attr[:] = np.asarray(value).reshape(attr.shape)
210
+ elif isinstance(value, str):
211
+ assert key == "label", "Only label is a string in mjtGeom."
212
+ if value is None:
213
+ g.label[0] = 0
214
+ else:
215
+ g.label = value
216
+ elif hasattr(g, key):
217
+ raise ValueError(
218
+ "mjtGeom has attr {} but type {} is invalid".format(
219
+ key, type(value)
220
+ )
221
+ )
222
+ else:
223
+ raise ValueError("mjtGeom doesn't have field %s" % key)
224
+
225
+ self.scn.ngeom += 1
226
+
227
+ def close(self):
228
+ pass
229
+
230
+
231
+ class RenderContextOffscreen(RenderContext):
232
+
233
+ def __init__(self, width, height, model, data):
234
+
235
+ self._get_opengl_backend(width, height)
236
+ self.opengl_context.make_current()
237
+
238
+ super().__init__(model, data, offscreen=True)
239
+
240
+ def _get_opengl_backend(self, width, height):
241
+
242
+ backend = os.environ.get("MUJOCO_GL")
243
+ if backend is not None:
244
+ try:
245
+ self.opengl_context = _ALL_RENDERERS[backend](width, height)
246
+ except KeyError:
247
+ raise RuntimeError(
248
+ "Environment variable {} must be one of {!r}: got {!r}.".format(
249
+ "MUJOCO_GL", _ALL_RENDERERS.keys(), backend
250
+ )
251
+ )
252
+
253
+ else:
254
+ for name, _ in _ALL_RENDERERS.items():
255
+ try:
256
+ self.opengl_context = _ALL_RENDERERS[name](width, height)
257
+ backend = name
258
+ break
259
+ except:
260
+ pass
261
+ if backend is None:
262
+ raise RuntimeError(
263
+ "No OpenGL backend could be imported. Attempting to create a "
264
+ "rendering context will result in a RuntimeError."
265
+ )
266
+
267
+
268
+ class Viewer(RenderContext):
269
+
270
+ def __init__(self, model, data):
271
+ self._gui_lock = Lock()
272
+ self._button_left_pressed = False
273
+ self._button_right_pressed = False
274
+ self._last_mouse_x = 0
275
+ self._last_mouse_y = 0
276
+ self._paused = False
277
+ self._transparent = False
278
+ self._contacts = False
279
+ self._render_every_frame = False
280
+ self._image_idx = 0
281
+ self._image_path = "/tmp/frame_%07d.png"
282
+ self._run_speed = 1.0
283
+ self.last_time_rendered = 0.0
284
+ self._advance_by_one_step = False
285
+ self._hide_menu = False
286
+ self.windows = []
287
+ self.cams = [-1]
288
+
289
+ glfw.init()
290
+ self.width, self.height = glfw.get_video_mode(glfw.get_primary_monitor()).size
291
+ self.windows.append(
292
+ glfw.create_window(self.width // 2, self.height // 2, "mujoco", None, None)
293
+ )
294
+ glfw.make_context_current(self.windows[0])
295
+ glfw.swap_interval(1)
296
+
297
+ framebuffer_width, framebuffer_height = glfw.get_framebuffer_size(
298
+ self.windows[0]
299
+ )
300
+ window_width, _ = glfw.get_window_size(self.windows[0])
301
+ self._scale = framebuffer_width * 1.0 / window_width
302
+
303
+ glfw.set_cursor_pos_callback(self.windows[0], self._cursor_pos_callback)
304
+ glfw.set_mouse_button_callback(self.windows[0], self._mouse_button_callback)
305
+ glfw.set_scroll_callback(self.windows[0], self._scroll_callback)
306
+ glfw.set_key_callback(self.windows[0], self._key_callback)
307
+
308
+ self.viewport = mujoco.MjrRect(0, 0, framebuffer_width, framebuffer_height)
309
+ super().__init__(model, data, offscreen=False)
310
+
311
+ def set_cameras(self, cameras: List[int]):
312
+ for cam in cameras:
313
+ self.windows.append(
314
+ glfw.create_window(
315
+ self.width // 2,
316
+ self.height // 2,
317
+ "Camera: {}".format(str(cam)),
318
+ None,
319
+ self.windows[0],
320
+ )
321
+ )
322
+ glfw.make_context_current(self.windows[-1])
323
+ self.cams.append(cam)
324
+
325
+ def _key_callback(self, window, key, scancode, action, mods):
326
+ if action != glfw.RELEASE:
327
+ return
328
+ elif key == glfw.KEY_TAB:
329
+ self.cams[0] += 1
330
+ if self.cams[0] >= self.model.ncam:
331
+ self.cams[0] = -1
332
+ elif key == glfw.KEY_A:
333
+ self.windows.append(
334
+ glfw.create_window(
335
+ self.width // 2,
336
+ self.height // 2,
337
+ "Camera: {}".format(str(self.cams[0])),
338
+ None,
339
+ self.windows[0],
340
+ )
341
+ )
342
+ glfw.make_context_current(self.windows[-1])
343
+ self.cams.append(self.cams[0])
344
+ elif key == glfw.KEY_P:
345
+ print("lookat: ", self.cam.lookat)
346
+ print("elevation: ", self.cam.elevation)
347
+ print("distance: ", self.cam.distance)
348
+ print("azimuth: ", self.cam.azimuth)
349
+ elif key == glfw.KEY_SPACE and self._paused is not None:
350
+ self._paused = not self._paused
351
+ elif key == glfw.KEY_RIGHT and self._paused is not None:
352
+ self._advance_by_one_step = True
353
+ self._paused = True
354
+ elif key == glfw.KEY_S:
355
+ self._run_speed -= 0.25
356
+ if self._run_speed <= 0.0:
357
+ self._run_speed = 0.25
358
+ elif key == glfw.KEY_F:
359
+ self._run_speed += 0.25
360
+ elif key == glfw.KEY_D:
361
+ self._render_every_frame = not self._render_every_frame
362
+ elif key == glfw.KEY_T:
363
+ img = np.zeros(
364
+ (
365
+ glfw.get_framebuffer_size(window)[1],
366
+ glfw.get_framebuffer_size(window)[0],
367
+ 3,
368
+ ),
369
+ dtype=np.uint8,
370
+ )
371
+ mujoco.mjr_readPixels(img, None, self.viewport, self.con)
372
+ imageio.imwrite(self._image_path % self._image_idx, np.flipud(img))
373
+ self._image_idx += 1
374
+ elif key == glfw.KEY_C:
375
+ self._contacts = not self._contacts
376
+ self.vopt.flags[mujoco.mjtVisFlag.mjVIS_CONTACTPOINT] = self._contacts
377
+ self.vopt.flags[mujoco.mjtVisFlag.mjVIS_CONTACTFORCE] = self._contacts
378
+ elif key == glfw.KEY_E:
379
+ self.vopt.frame = 1 - self.vopt.frame
380
+ elif key == glfw.KEY_H:
381
+ self._hide_menu = not self._hide_menu
382
+ elif key == glfw.KEY_R:
383
+ self._transparent = not self._transparent
384
+ if self._transparent:
385
+ self.model.geom_rgba[:, 3] /= 5.0
386
+ else:
387
+ self.model.geom_rgba[:, 3] *= 5.0
388
+ elif key in (glfw.KEY_0, glfw.KEY_1, glfw.KEY_2, glfw.KEY_3, glfw.KEY_4):
389
+ self.vopt.geomgroup[key - glfw.KEY_0] ^= 1
390
+ if key == glfw.KEY_ESCAPE:
391
+ print("Pressed ESC")
392
+ print("Quitting.")
393
+ glfw.destroy_window(window)
394
+ glfw.terminate()
395
+
396
+ def _cursor_pos_callback(self, window, xpos, ypos):
397
+ if not (self._button_left_pressed or self._button_right_pressed):
398
+ return
399
+
400
+ mod_shift = (
401
+ glfw.get_key(window, glfw.KEY_LEFT_SHIFT) == glfw.PRESS
402
+ or glfw.get_key(window, glfw.KEY_RIGHT_SHIFT) == glfw.PRESS
403
+ )
404
+ if self._button_right_pressed:
405
+ action = (
406
+ mujoco.mjtMouse.mjMOUSE_MOVE_H
407
+ if mod_shift
408
+ else mujoco.mjtMouse.mjMOUSE_MOVE_V
409
+ )
410
+ elif self._button_left_pressed:
411
+ action = (
412
+ mujoco.mjtMouse.mjMOUSE_ROTATE_H
413
+ if mod_shift
414
+ else mujoco.mjtMouse.mjMOUSE_ROTATE_V
415
+ )
416
+ else:
417
+ action = mujoco.mjtMouse.mjMOUSE_ZOOM
418
+
419
+ dx = int(self._scale * xpos) - self._last_mouse_x
420
+ dy = int(self._scale * ypos) - self._last_mouse_y
421
+ width, height = glfw.get_framebuffer_size(window)
422
+
423
+ with self._gui_lock:
424
+ mujoco.mjv_moveCamera(
425
+ self.model, action, dx / height, dy / height, self.scn, self.cam
426
+ )
427
+
428
+ self._last_mouse_x = int(self._scale * xpos)
429
+ self._last_mouse_y = int(self._scale * ypos)
430
+
431
+ def _mouse_button_callback(self, window, button, act, mods):
432
+ self._button_left_pressed = (
433
+ glfw.get_mouse_button(window, glfw.MOUSE_BUTTON_LEFT) == glfw.PRESS
434
+ )
435
+ self._button_right_pressed = (
436
+ glfw.get_mouse_button(window, glfw.MOUSE_BUTTON_RIGHT) == glfw.PRESS
437
+ )
438
+
439
+ x, y = glfw.get_cursor_pos(window)
440
+ self._last_mouse_x = int(self._scale * x)
441
+ self._last_mouse_y = int(self._scale * y)
442
+
443
+ def _scroll_callback(self, window, x_offset, y_offset):
444
+ with self._gui_lock:
445
+ mujoco.mjv_moveCamera(
446
+ self.model,
447
+ mujoco.mjtMouse.mjMOUSE_ZOOM,
448
+ 0,
449
+ -0.05 * y_offset,
450
+ self.scn,
451
+ self.cam,
452
+ )
453
+
454
+ def _create_overlay(self):
455
+ topleft = mujoco.mjtGridPos.mjGRID_TOPLEFT
456
+ bottomleft = mujoco.mjtGridPos.mjGRID_BOTTOMLEFT
457
+
458
+ if self._render_every_frame:
459
+ self.add_overlay(topleft, "", "")
460
+ else:
461
+ self.add_overlay(
462
+ topleft,
463
+ "Run speed = %.3f x real time" % self._run_speed,
464
+ "[S]lower, [F]aster",
465
+ )
466
+ self.add_overlay(
467
+ topleft, "Ren[d]er every frame", "On" if self._render_every_frame else "Off"
468
+ )
469
+ self.add_overlay(
470
+ topleft,
471
+ "Switch camera (#cams = %d)" % (self.model.ncam + 1),
472
+ "[Tab] (camera ID = %d)" % self.cam.fixedcamid,
473
+ )
474
+ self.add_overlay(topleft, "[C]ontact forces", "On" if self._contacts else "Off")
475
+ self.add_overlay(topleft, "T[r]ansparent", "On" if self._transparent else "Off")
476
+ self.add_overlay(topleft, "Camera detach", "[A]")
477
+ self.add_overlay(topleft, "Print camera position", "[p]")
478
+ if self._paused is not None:
479
+ if not self._paused:
480
+ self.add_overlay(topleft, "Stop", "[Space]")
481
+ else:
482
+ self.add_overlay(topleft, "Start", "[Space]")
483
+ self.add_overlay(
484
+ topleft, "Advance simulation by one step", "[right arrow]"
485
+ )
486
+ self.add_overlay(
487
+ topleft, "Referenc[e] frames", "On" if self.vopt.frame == 1 else "Off"
488
+ )
489
+ self.add_overlay(topleft, "[H]ide Menu", "")
490
+ if self._image_idx > 0:
491
+ fname = self._image_path % (self._image_idx - 1)
492
+ self.add_overlay(topleft, "Cap[t]ure frame", "Saved as %s" % fname)
493
+ else:
494
+ self.add_overlay(topleft, "Cap[t]ure frame", "")
495
+ self.add_overlay(topleft, "Toggle geomgroup visibility", "0-4")
496
+
497
+ self.add_overlay(
498
+ bottomleft, "Solver iterations", str(self.data.solver_iter + 1)
499
+ )
500
+ self.add_overlay(
501
+ bottomleft, "Step", str(round(self.data.time / self.model.opt.timestep))
502
+ )
503
+ self.add_overlay(bottomleft, "timestep", "%.5f" % self.model.opt.timestep)
504
+
505
+ def render(self):
506
+ def get_scaled_time():
507
+ return (1.0 / self._run_speed) * self.data.time
508
+
509
+ def time_for_next_frame(next_frame_after=1.0 / 30.0):
510
+ if (
511
+ get_scaled_time() < self.last_time_rendered
512
+ or self.last_time_rendered == 0.0
513
+ ):
514
+ return True
515
+ return (get_scaled_time() - self.last_time_rendered) >= next_frame_after
516
+
517
+ def update():
518
+ for i, wc in enumerate(zip(self.windows, self.cams)):
519
+ window, cam_id = wc
520
+ if i == 0:
521
+ self._create_overlay()
522
+ self.cam.fixedcamid = cam_id
523
+ self.cam.type = mujoco.mjtCamera.mjCAMERA_FIXED
524
+ if self.cam.fixedcamid == -1:
525
+ self.cam.type = mujoco.mjtCamera.mjCAMERA_FREE
526
+
527
+ if window is None:
528
+ continue
529
+ elif glfw.window_should_close(window):
530
+ if i == 0:
531
+ glfw.terminate()
532
+ glfw.destroy_window(window)
533
+ self.windows.remove(window)
534
+ self.cams.pop(i)
535
+ continue
536
+ self.viewport.width, self.viewport.height = glfw.get_framebuffer_size(
537
+ window
538
+ )
539
+ with self._gui_lock:
540
+ mujoco.mjv_updateScene(
541
+ self.model,
542
+ self.data,
543
+ self.vopt,
544
+ mujoco.MjvPerturb(),
545
+ self.cam,
546
+ mujoco.mjtCatBit.mjCAT_ALL.value,
547
+ self.scn,
548
+ )
549
+ for marker in self._markers:
550
+ self._add_marker_to_scene(marker)
551
+ glfw.make_context_current(window)
552
+ mujoco.mjr_render(self.viewport, self.scn, self.con)
553
+ if not self._hide_menu:
554
+ for gridpos, [t1, t2] in self._overlays.items():
555
+ mujoco.mjr_overlay(
556
+ mujoco.mjtFontScale.mjFONTSCALE_150,
557
+ gridpos,
558
+ self.viewport,
559
+ t1,
560
+ t2,
561
+ self.con,
562
+ )
563
+ glfw.swap_buffers(window)
564
+ glfw.poll_events()
565
+ if i == 0:
566
+ self._overlays.clear()
567
+
568
+ if self._paused:
569
+ while self._paused:
570
+ update()
571
+ if self._advance_by_one_step:
572
+ self._advance_by_one_step = False
573
+ break
574
+ else:
575
+ if self._render_every_frame or time_for_next_frame():
576
+ update()
577
+ self.last_time_rendered = get_scaled_time()
578
+
579
+ self._markers[:] = []
580
+
581
+ def close(self):
582
+ for window in self.windows:
583
+ glfw.destroy_window(window)
584
+ glfw.terminate()
585
+
586
+ def reinit(self, model, data):
587
+ self.model = model
588
+ self.data = data
589
+ max_geom = 1000
590
+ mujoco.mj_forward(self.model, self.data)
591
+ self.scn = mujoco.MjvScene(self.model, max_geom)
592
+ glfw.make_context_current(self.windows[-1])
593
+ self.con = mujoco.MjrContext(self.model, mujoco.mjtFontScale.mjFONTSCALE_150)
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/mj_utils/mj_scene_object.py ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import xml.etree.ElementTree as Et
3
+ from typing import Tuple
4
+
5
+ import numpy as np
6
+ import yaml
7
+
8
+ import d3il.environments.d3il.d3il_sim.sims.mj_beta.MjLoadable as mj_load
9
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.mj_utils.mj_helper import IncludeType
10
+ from d3il.environments.d3il.d3il_sim.utils import sim_path
11
+
12
+
13
+ class MujocoObject(mj_load.MjXmlLoadable):
14
+ def __init__(self, object_name, pos, quat, root=sim_path.D3IL_DIR):
15
+ if pos is None:
16
+ pos = [0, 0, 0]
17
+ else:
18
+ assert len(pos) == 3, "Error, parameter pos has to be three dimensional."
19
+
20
+ if quat is None:
21
+ quat = [0, 0, 0, 0]
22
+ else:
23
+ assert len(quat) == 4, "Error, parameter quat has to be four dimensional."
24
+
25
+ self.obj_dir_path = "models/mj/common-objects/" + object_name
26
+ self.obj_file_name = object_name + ".xml"
27
+ self.root = root
28
+ self.pos = pos
29
+ self.quat = quat
30
+ self.name = object_name
31
+ super().__init__(os.path.join(root, self.obj_dir_path, self.obj_file_name))
32
+
33
+ def mj_load(self) -> Tuple[Et.Element, list, IncludeType]:
34
+ include_et, xml, is_include = super(MujocoObject, self).mj_load()
35
+ xml_file = xml[0]
36
+ obj = Et.ElementTree(Et.fromstring(xml_file))
37
+ worldbody = obj.find("worldbody")
38
+ body = worldbody.find("body")
39
+
40
+ obj_pos_str = " ".join(map(str, self.pos))
41
+ obj_quat_str = " ".join(map(str, self.quat))
42
+
43
+ body.set("pos", obj_pos_str)
44
+ body.set("quat", obj_quat_str)
45
+
46
+ return include_et, Et.tostring(obj), IncludeType.FILE_INCLUDE
47
+
48
+ def get_poi(self) -> list:
49
+ return [self.name]
50
+
51
+
52
+ class CompositeMujocoObject(mj_load.MjLoadable, mj_load.MjFreezable):
53
+ def __init__(self, object_folder, object_name, pos, quat):
54
+ if pos is None:
55
+ pos = [0, 0, 0]
56
+ else:
57
+ assert len(pos) == 3, "Error, parameter pos has to be three dimensional."
58
+
59
+ if quat is None:
60
+ quat = [0, 0, 0, 0]
61
+ else:
62
+ assert len(quat) == 4, "Error, parameter quat has to be four dimensional."
63
+
64
+ self.object_folder = object_folder
65
+ self.pos = pos
66
+ self.quat = quat
67
+ self.name = object_name
68
+ self.file_name = f"{self.name}.xml"
69
+
70
+ def mj_load(self) -> Tuple[Et.Element, list, bool]:
71
+ et_include = Et.Element("include")
72
+ et_include.set("file", self.file_name)
73
+
74
+ xml_string = self.generate_xml()
75
+ return (
76
+ et_include,
77
+ {os.path.join(self.object_folder, self.file_name): xml_string},
78
+ IncludeType.FILE_INCLUDE,
79
+ )
80
+
81
+ def generate_xml(self) -> str:
82
+ info_file = os.path.join(self.object_folder, "info.yml")
83
+ assert os.path.isfile(
84
+ info_file
85
+ ), f"The file {info_file} was not found. Did you specify the path to the object folder correctly?"
86
+
87
+ with open(info_file, "r") as f:
88
+ info_dict = yaml.safe_load(f)
89
+
90
+ original_file = info_dict["original_file"]
91
+ submesh_files = info_dict["submesh_files"]
92
+ submesh_props = info_dict["submesh_props"]
93
+ weight = info_dict["weight"]
94
+ material_map = info_dict["material_map"]
95
+
96
+ root = Et.Element("mujoco", attrib={"model": self.name})
97
+
98
+ assets = Et.SubElement(root, "asset")
99
+ worldbody = Et.SubElement(root, "worldbody")
100
+ body_attributes = {
101
+ "name": f"{self.name}",
102
+ "pos": " ".join(map(str, self.pos)),
103
+ "quat": " ".join(map(str, self.quat)),
104
+ }
105
+ body = Et.SubElement(worldbody, "body", attrib=body_attributes)
106
+
107
+ texture_attributes = {
108
+ "type": "2d",
109
+ "name": f"{self.name}_tex",
110
+ "file": os.path.join(self.object_folder, material_map),
111
+ }
112
+ texture = Et.SubElement(assets, "texture", attrib=texture_attributes)
113
+
114
+ material_attributes = {
115
+ "name": f"{self.name}_mat",
116
+ "texture": texture_attributes["name"],
117
+ "specular": "0.5",
118
+ "shininess": "0.5",
119
+ }
120
+ material = Et.SubElement(assets, "material", attrib=material_attributes)
121
+
122
+ orig_mesh_attributes = {
123
+ "name": f"{self.name}_orig",
124
+ "file": os.path.join(self.object_folder, original_file),
125
+ }
126
+ orig_mesh = Et.SubElement(assets, "mesh", attrib=orig_mesh_attributes)
127
+
128
+ orig_geom_attributes = {
129
+ "material": material_attributes["name"],
130
+ "mesh": orig_mesh_attributes["name"],
131
+ "group": "2",
132
+ "type": "mesh",
133
+ "contype": "0",
134
+ "conaffinity": "0",
135
+ }
136
+ orig_geom = Et.SubElement(body, "geom", attrib=orig_geom_attributes)
137
+
138
+ for i, (submesh_file, submesh_prop) in enumerate(
139
+ zip(submesh_files, submesh_props)
140
+ ):
141
+ collision_mesh_attributes = {
142
+ "name": f"{self.name}_coll_{i}",
143
+ "file": os.path.join(self.object_folder, submesh_file),
144
+ }
145
+ collision_mesh = Et.SubElement(
146
+ assets, "mesh", attrib=collision_mesh_attributes
147
+ )
148
+ collision_geom_attributes = {
149
+ "mesh": collision_mesh_attributes["name"],
150
+ "mass": str(weight * submesh_prop),
151
+ "group": "3",
152
+ "type": "mesh",
153
+ "conaffinity": "1",
154
+ "contype": "1",
155
+ "condim": "4",
156
+ "friction": "0.95 0.3 0.1",
157
+ "rgba": "1 1 1 1",
158
+ "solimp": "0.998 0.998 0.001",
159
+ "solref": "0.001 1",
160
+ }
161
+ collision_geom = Et.SubElement(
162
+ body, "geom", attrib=collision_geom_attributes
163
+ )
164
+
165
+ joint_attributes = {
166
+ "damping": "0.0001",
167
+ "name": f"{self.name}:joint",
168
+ "type": "free",
169
+ }
170
+ joint = Et.SubElement(body, "joint", attrib=joint_attributes)
171
+
172
+ return Et.tostring(root)
173
+
174
+ def get_poi(self) -> list:
175
+ return [self.name]
176
+
177
+ def freeze(self, model, data):
178
+ pos: np.ndarray = data.jnt(self.name + ":joint").qpos
179
+ self.pos = pos[0:3].tolist()
180
+ self.quat = pos[3:].tolist()
181
+
182
+ def unfreeze(self, data, model):
183
+ pass
184
+
185
+
186
+ class YCBMujocoObject(CompositeMujocoObject):
187
+ def __init__(self, ycb_base_folder, object_id, object_name, pos, quat):
188
+ self.ycb_base_folder = ycb_base_folder
189
+ self.ycb_object_folder = os.path.join(ycb_base_folder, object_id)
190
+
191
+ super().__init__(self.ycb_object_folder, object_name, pos, quat)
192
+
193
+
194
+ class CustomMujocoObject(mj_load.MjXmlLoadable):
195
+ def __init__(self, object_name, object_dir_path, pos, quat, root=sim_path.D3IL_DIR):
196
+ if pos is None:
197
+ pos = [0, 0, 0]
198
+ else:
199
+ assert len(pos) == 3, "Error, parameter pos has to be three dimensional."
200
+
201
+ if quat is None:
202
+ quat = [0, 0, 0, 0]
203
+ else:
204
+ assert len(quat) == 4, "Error, parameter quat has to be four dimensional."
205
+
206
+ self.obj_dir_path = object_dir_path
207
+ self.obj_file_name = object_name + ".xml"
208
+ self.root = root
209
+ self.pos = pos
210
+ self.quat = quat
211
+ self.name = object_name
212
+
213
+ super().__init__(os.path.join(root, self.obj_dir_path, self.obj_file_name))
214
+
215
+ def mj_load(self) -> Tuple[Et.Element, list, bool]:
216
+ include_et, xml, is_include = super(CustomMujocoObject, self).mj_load()
217
+ xml_file = list(xml.values())[0]
218
+ obj = Et.ElementTree(Et.fromstring(xml_file))
219
+ worldbody = obj.find("worldbody")
220
+ body = worldbody.find("body")
221
+
222
+ obj_pos_str = " ".join(map(str, self.pos))
223
+ obj_quat_str = " ".join(map(str, self.quat))
224
+
225
+ body.set("pos", obj_pos_str)
226
+ body.set("quat", obj_quat_str)
227
+
228
+ return (
229
+ include_et,
230
+ {
231
+ os.path.join(self.loadable_dir, self.file_name): Et.tostring(
232
+ obj.getroot()
233
+ )
234
+ },
235
+ is_include,
236
+ )
237
+
238
+ def get_poi(self) -> list:
239
+ return [self.name]
240
+
241
+
242
+ class MjWorkspace(mj_load.MjXmlLoadable):
243
+ def __init__(self, size: str, root=sim_path.D3IL_DIR):
244
+ if size not in ["small", "medium", "large"]:
245
+ raise ValueError(
246
+ "Error, please choose a size between <small>, <medium> or <large> ."
247
+ )
248
+ self.size = size
249
+ self.root = root
250
+ super().__init__(
251
+ os.path.join(root, "models/mj/workspace/{}".format(self.size), "ws.xml")
252
+ )
253
+
254
+
255
+ class MjSurrounding(mj_load.MjXmlLoadable):
256
+ def __init__(self, surrounding_name, root=None):
257
+ self.surrounding_name = surrounding_name
258
+ if root is None:
259
+ root = os.path.join(sim_path.D3IL_DIR, "models/mj/surroundings")
260
+ self.root = root
261
+
262
+ super().__init__(os.path.join(root, "{}.xml".format(self.surrounding_name)))
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/mj_beta/mj_utils/mj_scene_parser.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import xml.etree.ElementTree as Et
2
+ from itertools import chain
3
+ from xml.etree.ElementTree import Element
4
+
5
+ import mujoco
6
+
7
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.mj_utils.mj_helper import IncludeType
8
+ from d3il.environments.d3il.d3il_sim.sims.mj_beta.MjLoadable import (
9
+ MjLoadable,
10
+ MjIncludeTemplate,
11
+ )
12
+ from d3il.environments.d3il.d3il_sim.utils.sim_path import d3il_path
13
+
14
+
15
+ class MjSceneParser:
16
+
17
+ def __init__(self, main_xml_path=None):
18
+ if main_xml_path is None:
19
+ main_xml_path = "./models/mj/surroundings/base.xml"
20
+
21
+ with open(d3il_path(main_xml_path), "r") as file:
22
+ self.scene_xml = file.read()
23
+
24
+ self.assets = {}
25
+ self.mj_xml_string = ""
26
+
27
+ self._tree = Et.ElementTree(Et.fromstring(self.scene_xml))
28
+ self._root = self._tree.getroot()
29
+ self._worldbody = self._root.find("worldbody")
30
+ assert self._worldbody, "Error, xml file does contain a world body."
31
+
32
+ def create_scene(self, mj_robots, mj_surrounding, object_list: list, dt):
33
+ if object_list is None:
34
+ object_list = []
35
+ if not isinstance(object_list, list):
36
+ object_list = [object_list]
37
+
38
+ all_objects = chain([mj_surrounding], object_list, mj_robots)
39
+
40
+ for obj in all_objects:
41
+ self.load_mj_loadable(obj)
42
+
43
+ self.set_dt(dt)
44
+
45
+ model = mujoco.MjModel.from_xml_string(self.mj_xml_string, self.assets)
46
+ data = mujoco.MjData(model)
47
+
48
+ self.cleanup(all_objects)
49
+ return model, data
50
+
51
+ def load_mj_loadable(self, mj_loadable: MjLoadable):
52
+ xml_element, assets, include_type = mj_loadable.mj_load()
53
+ if include_type == IncludeType.FILE_INCLUDE:
54
+ self._root.append(xml_element)
55
+ elif include_type == IncludeType.WORLD_BODY:
56
+ self._worldbody.append(xml_element)
57
+ elif include_type == IncludeType.MJ_INCLUDE:
58
+ for child in xml_element:
59
+ self._root.append(child)
60
+ elif include_type == IncludeType.VIRTUAL_INCLUDE:
61
+ return
62
+ else:
63
+ raise ValueError("Unknown IncludeType")
64
+
65
+ self.indent(self._root)
66
+
67
+ self.mj_xml_string = Et.tostring(self._root, encoding="unicode", method="xml")
68
+ self.assets.update(assets)
69
+
70
+ def set_dt(self, dt=0.001):
71
+ options = self._root.find("option")
72
+ options.set("timestep", str(dt))
73
+ self.indent(self._root)
74
+ self.mj_xml_string = Et.tostring(self._root, encoding="unicode", method="xml")
75
+
76
+ def indent(self, elem: Element, level=0):
77
+ i = "\n" + level * " "
78
+ if len(elem):
79
+ if not elem.text or not elem.text.strip():
80
+ elem.text = i + " "
81
+ if not elem.tail or not elem.tail.strip():
82
+ elem.tail = i
83
+ for elem in elem:
84
+ self.indent(elem, level + 1)
85
+ if not elem.tail or not elem.tail.strip():
86
+ elem.tail = i
87
+ else:
88
+ if level and (not elem.tail or not elem.tail.strip()):
89
+ elem.tail = i
90
+
91
+ def cleanup(self, objects: list):
92
+ for obj in objects:
93
+ if isinstance(obj, MjIncludeTemplate):
94
+ obj.cleanup()
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/universal_sim/PrimitiveObjects.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from enum import Enum
2
+ from typing import List, Tuple
3
+
4
+ from d3il.environments.d3il.d3il_sim.core.sim_object.sim_object import SimObject
5
+
6
+
7
+ class PrimitiveObject(SimObject):
8
+ class Shape(Enum):
9
+ BOX = "box"
10
+ SPHERE = "sphere"
11
+ CYLINDER = "cylinder"
12
+
13
+ def __init__(
14
+ self,
15
+ name: str,
16
+ init_pos,
17
+ init_quat,
18
+ mass: float,
19
+ size,
20
+ rgba,
21
+ static: bool,
22
+ visual_only: bool,
23
+ obj_type: Shape,
24
+ solimp: List[float] = None,
25
+ solref: List[float] = None,
26
+ ):
27
+ super(PrimitiveObject, self).__init__(name, init_pos, init_quat)
28
+ self.type = obj_type
29
+ self.mass = mass
30
+ self.size = size
31
+ self.static = static
32
+ self.visual_only = visual_only
33
+
34
+ if rgba is None:
35
+ rgba = [0.5, 0.5, 0.5, 1.0]
36
+ self.rgba = rgba
37
+
38
+ self.solimp = solimp
39
+ self.solref = solref
40
+
41
+ def get_poi(self) -> list:
42
+ return [self.name]
43
+
44
+
45
+ class Box(PrimitiveObject):
46
+ def __init__(
47
+ self,
48
+ name: str,
49
+ init_pos,
50
+ init_quat,
51
+ mass: float = 0.1,
52
+ size=None,
53
+ rgba=None,
54
+ static: bool = False,
55
+ visual_only: bool = False,
56
+ solimp: List[float] = None,
57
+ solref: List[float] = None,
58
+ ):
59
+ if size is None:
60
+ size = [0.02, 0.02, 0.02]
61
+
62
+ if len(size) != 3:
63
+ raise ValueError("Expected list of size three for size attribute.")
64
+ super(Box, self).__init__(
65
+ name,
66
+ init_pos,
67
+ init_quat,
68
+ mass,
69
+ size,
70
+ rgba,
71
+ static,
72
+ visual_only,
73
+ self.Shape.BOX,
74
+ solimp,
75
+ solref,
76
+ )
77
+
78
+
79
+ class Sphere(PrimitiveObject):
80
+ def __init__(
81
+ self,
82
+ name: str,
83
+ init_pos,
84
+ init_quat,
85
+ mass: float = 0.1,
86
+ size=None,
87
+ rgba=None,
88
+ static: bool = False,
89
+ visual_only: bool = False,
90
+ solimp: List[float] = None,
91
+ solref: List[float] = None,
92
+ ):
93
+ if size is None:
94
+ size = [0.02]
95
+
96
+ if len(size) != 1:
97
+ raise ValueError("Expected list of size one for size attribute")
98
+ super(Sphere, self).__init__(
99
+ name,
100
+ init_pos,
101
+ init_quat,
102
+ mass,
103
+ size,
104
+ rgba,
105
+ static,
106
+ visual_only,
107
+ self.Shape.SPHERE,
108
+ solimp,
109
+ solref,
110
+ )
111
+
112
+
113
+ class Cylinder(PrimitiveObject):
114
+ def __init__(
115
+ self,
116
+ name: str,
117
+ init_pos,
118
+ init_quat,
119
+ mass: float = 0.1,
120
+ size=None,
121
+ rgba=None,
122
+ static: bool = False,
123
+ visual_only: bool = False,
124
+ solimp: List[float] = None,
125
+ solref: List[float] = None,
126
+ ):
127
+ if size is None:
128
+ size = [0.02, 0.02]
129
+
130
+ if len(size) != 2:
131
+ raise ValueError("Expected list of size two for size attribute.")
132
+ super(Cylinder, self).__init__(
133
+ name,
134
+ init_pos,
135
+ init_quat,
136
+ mass,
137
+ size,
138
+ rgba,
139
+ static,
140
+ visual_only,
141
+ self.Shape.CYLINDER,
142
+ solimp,
143
+ solref,
144
+ )
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/sims/universal_sim/__init__.py ADDED
File without changes
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/utils/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from .geometric_transformation import *
applications/avoiding/avoiding_baselines/DiRecT/d3il/environments/d3il/d3il_sim/utils/geometric_transformation.py ADDED
@@ -0,0 +1,319 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import itertools
2
+
3
+ import numpy as np
4
+
5
+ _FLOAT_EPS = np.finfo(np.float64).eps
6
+ _EPS4 = _FLOAT_EPS * 4.0
7
+
8
+
9
+ def get_quaternion_error(curr_quat, des_quat):
10
+
11
+ quatError = np.zeros((3,))
12
+
13
+ quatError[0] = (
14
+ curr_quat[0] * des_quat[1]
15
+ - des_quat[0] * curr_quat[1]
16
+ - curr_quat[3] * des_quat[2]
17
+ + curr_quat[2] * des_quat[3]
18
+ )
19
+
20
+ quatError[1] = (
21
+ curr_quat[0] * des_quat[2]
22
+ - des_quat[0] * curr_quat[2]
23
+ + curr_quat[3] * des_quat[1]
24
+ - curr_quat[1] * des_quat[3]
25
+ )
26
+
27
+ quatError[2] = (
28
+ curr_quat[0] * des_quat[3]
29
+ - des_quat[0] * curr_quat[3]
30
+ - curr_quat[2] * des_quat[1]
31
+ + curr_quat[1] * des_quat[2]
32
+ )
33
+
34
+ return quatError
35
+
36
+
37
+ def euler2mat(euler):
38
+ euler = np.asarray(euler, dtype=np.float64)
39
+ assert euler.shape[-1] == 3, "Invalid shaped euler {}".format(euler)
40
+
41
+ ai, aj, ak = -euler[..., 2], -euler[..., 1], -euler[..., 0]
42
+ si, sj, sk = np.sin(ai), np.sin(aj), np.sin(ak)
43
+ ci, cj, ck = np.cos(ai), np.cos(aj), np.cos(ak)
44
+ cc, cs = ci * ck, ci * sk
45
+ sc, ss = si * ck, si * sk
46
+
47
+ mat = np.empty(euler.shape[:-1] + (3, 3), dtype=np.float64)
48
+ mat[..., 2, 2] = cj * ck
49
+ mat[..., 2, 1] = sj * sc - cs
50
+ mat[..., 2, 0] = sj * cc + ss
51
+ mat[..., 1, 2] = cj * sk
52
+ mat[..., 1, 1] = sj * ss + cc
53
+ mat[..., 1, 0] = sj * cs - sc
54
+ mat[..., 0, 2] = -sj
55
+ mat[..., 0, 1] = cj * si
56
+ mat[..., 0, 0] = cj * ci
57
+ return mat
58
+
59
+
60
+ def euler2quat(euler):
61
+ euler = np.asarray(euler, dtype=np.float64)
62
+ assert euler.shape[-1] == 3, "Invalid shape euler {}".format(euler)
63
+
64
+ ai, aj, ak = euler[..., 2] / 2, -euler[..., 1] / 2, euler[..., 0] / 2
65
+ si, sj, sk = np.sin(ai), np.sin(aj), np.sin(ak)
66
+ ci, cj, ck = np.cos(ai), np.cos(aj), np.cos(ak)
67
+ cc, cs = ci * ck, ci * sk
68
+ sc, ss = si * ck, si * sk
69
+
70
+ quat = np.empty(euler.shape[:-1] + (4,), dtype=np.float64)
71
+ quat[..., 0] = cj * cc + sj * ss
72
+ quat[..., 3] = cj * sc - sj * cs
73
+ quat[..., 2] = -(cj * ss + sj * cc)
74
+ quat[..., 1] = cj * cs - sj * sc
75
+ return quat
76
+
77
+
78
+ def mat2euler(mat):
79
+ mat = np.asarray(mat, dtype=np.float64)
80
+ assert mat.shape[-2:] == (3, 3), "Invalid shape matrix {}".format(mat)
81
+
82
+ cy = np.sqrt(mat[..., 2, 2] * mat[..., 2, 2] + mat[..., 1, 2] * mat[..., 1, 2])
83
+ condition = cy > _EPS4
84
+ euler = np.empty(mat.shape[:-1], dtype=np.float64)
85
+ euler[..., 2] = np.where(
86
+ condition,
87
+ -np.arctan2(mat[..., 0, 1], mat[..., 0, 0]),
88
+ -np.arctan2(-mat[..., 1, 0], mat[..., 1, 1]),
89
+ )
90
+ euler[..., 1] = np.where(
91
+ condition, -np.arctan2(-mat[..., 0, 2], cy), -np.arctan2(-mat[..., 0, 2], cy)
92
+ )
93
+ euler[..., 0] = np.where(
94
+ condition, -np.arctan2(mat[..., 1, 2], mat[..., 2, 2]), 0.0
95
+ )
96
+ return euler
97
+
98
+
99
+ def mat2quat(mat):
100
+ mat = np.asarray(mat, dtype=np.float64)
101
+ assert mat.shape[-2:] == (3, 3), "Invalid shape matrix {}".format(mat)
102
+
103
+ Qxx, Qyx, Qzx = mat[..., 0, 0], mat[..., 0, 1], mat[..., 0, 2]
104
+ Qxy, Qyy, Qzy = mat[..., 1, 0], mat[..., 1, 1], mat[..., 1, 2]
105
+ Qxz, Qyz, Qzz = mat[..., 2, 0], mat[..., 2, 1], mat[..., 2, 2]
106
+ K = np.zeros(mat.shape[:-2] + (4, 4), dtype=np.float64)
107
+ K[..., 0, 0] = Qxx - Qyy - Qzz
108
+ K[..., 1, 0] = Qyx + Qxy
109
+ K[..., 1, 1] = Qyy - Qxx - Qzz
110
+ K[..., 2, 0] = Qzx + Qxz
111
+ K[..., 2, 1] = Qzy + Qyz
112
+ K[..., 2, 2] = Qzz - Qxx - Qyy
113
+ K[..., 3, 0] = Qyz - Qzy
114
+ K[..., 3, 1] = Qzx - Qxz
115
+ K[..., 3, 2] = Qxy - Qyx
116
+ K[..., 3, 3] = Qxx + Qyy + Qzz
117
+ K /= 3.0
118
+ q = np.empty(K.shape[:-2] + (4,))
119
+ it = np.nditer(q[..., 0], flags=["multi_index"])
120
+ while not it.finished:
121
+ vals, vecs = np.linalg.eigh(K[it.multi_index])
122
+ q[it.multi_index] = vecs[[3, 0, 1, 2], np.argmax(vals)]
123
+ if q[it.multi_index][0] < 0:
124
+ q[it.multi_index] *= -1
125
+ it.iternext()
126
+ return q
127
+
128
+
129
+ def quat2euler(quat):
130
+ return mat2euler(quat2mat(quat))
131
+
132
+
133
+ def subtract_euler(e1, e2):
134
+ assert e1.shape == e2.shape
135
+ assert e1.shape[-1] == 3
136
+ q1 = euler2quat(e1)
137
+ q2 = euler2quat(e2)
138
+ q_diff = quat_mul(q1, quat_conjugate(q2))
139
+ return quat2euler(q_diff)
140
+
141
+
142
+ def quat2mat(quat):
143
+ quat = np.asarray(quat, dtype=np.float64)
144
+ assert quat.shape[-1] == 4, "Invalid shape quat {}".format(quat)
145
+
146
+ w, x, y, z = quat[..., 0], quat[..., 1], quat[..., 2], quat[..., 3]
147
+ Nq = np.sum(quat * quat, axis=-1)
148
+ s = 2.0 / Nq
149
+ X, Y, Z = x * s, y * s, z * s
150
+ wX, wY, wZ = w * X, w * Y, w * Z
151
+ xX, xY, xZ = x * X, x * Y, x * Z
152
+ yY, yZ, zZ = y * Y, y * Z, z * Z
153
+
154
+ mat = np.empty(quat.shape[:-1] + (3, 3), dtype=np.float64)
155
+ mat[..., 0, 0] = 1.0 - (yY + zZ)
156
+ mat[..., 0, 1] = xY - wZ
157
+ mat[..., 0, 2] = xZ + wY
158
+ mat[..., 1, 0] = xY + wZ
159
+ mat[..., 1, 1] = 1.0 - (xX + zZ)
160
+ mat[..., 1, 2] = yZ - wX
161
+ mat[..., 2, 0] = xZ - wY
162
+ mat[..., 2, 1] = yZ + wX
163
+ mat[..., 2, 2] = 1.0 - (xX + yY)
164
+ return np.where((Nq > _FLOAT_EPS)[..., np.newaxis, np.newaxis], mat, np.eye(3))
165
+
166
+
167
+ def quat_conjugate(q):
168
+ inv_q = -q
169
+ inv_q[..., 0] *= -1
170
+ return inv_q
171
+
172
+
173
+ def quat_mul(q0, q1):
174
+ assert q0.shape == q1.shape
175
+ assert q0.shape[-1] == 4
176
+ assert q1.shape[-1] == 4
177
+
178
+ w0 = q0[..., 0]
179
+ x0 = q0[..., 1]
180
+ y0 = q0[..., 2]
181
+ z0 = q0[..., 3]
182
+
183
+ w1 = q1[..., 0]
184
+ x1 = q1[..., 1]
185
+ y1 = q1[..., 2]
186
+ z1 = q1[..., 3]
187
+
188
+ w = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1
189
+ x = w0 * x1 + x0 * w1 + y0 * z1 - z0 * y1
190
+ y = w0 * y1 + y0 * w1 + z0 * x1 - x0 * z1
191
+ z = w0 * z1 + z0 * w1 + x0 * y1 - y0 * x1
192
+ q = np.array([w, x, y, z])
193
+ if q.ndim == 2:
194
+ q = q.swapaxes(0, 1)
195
+ assert q.shape == q0.shape
196
+ return q
197
+
198
+
199
+ def quat_rot_vec(q, v0):
200
+ q_v0 = np.array([0, v0[0], v0[1], v0[2]])
201
+ q_v = quat_mul(q, quat_mul(q_v0, quat_conjugate(q)))
202
+ v = q_v[1:]
203
+ return v
204
+
205
+
206
+ def quat_identity():
207
+ return np.array([1, 0, 0, 0])
208
+
209
+
210
+ def quat2axisangle(quat):
211
+ theta = 0
212
+ axis = np.array([0, 0, 1])
213
+ sin_theta = np.linalg.norm(quat[1:])
214
+
215
+ if sin_theta > 0.0001:
216
+ theta = 2 * np.arcsin(sin_theta)
217
+ theta *= 1 if quat[0] >= 0 else -1
218
+ axis = quat[1:] / sin_theta
219
+
220
+ return axis, theta
221
+
222
+
223
+ def euler2point_euler(euler):
224
+ _euler = euler.copy()
225
+ if len(_euler.shape) < 2:
226
+ _euler = np.expand_dims(_euler, 0)
227
+ assert _euler.shape[1] == 3
228
+ _euler_sin = np.sin(_euler)
229
+ _euler_cos = np.cos(_euler)
230
+ return np.concatenate([_euler_sin, _euler_cos], axis=-1)
231
+
232
+
233
+ def point_euler2euler(euler):
234
+ _euler = euler.copy()
235
+ if len(_euler.shape) < 2:
236
+ _euler = np.expand_dims(_euler, 0)
237
+ assert _euler.shape[1] == 6
238
+ angle = np.arctan(_euler[..., :3] / _euler[..., 3:])
239
+ angle[_euler[..., 3:] < 0] += np.pi
240
+ return angle
241
+
242
+
243
+ def quat2point_quat(quat):
244
+ _quat = quat.copy()
245
+ if len(_quat.shape) < 2:
246
+ _quat = np.expand_dims(_quat, 0)
247
+ assert _quat.shape[1] == 4
248
+ angle = np.arccos(_quat[:, [0]]) * 2
249
+ xyz = _quat[:, 1:]
250
+ xyz[np.squeeze(np.abs(np.sin(angle / 2))) >= 1e-5] = (xyz / np.sin(angle / 2))[
251
+ np.squeeze(np.abs(np.sin(angle / 2))) >= 1e-5
252
+ ]
253
+ return np.concatenate([np.sin(angle), np.cos(angle), xyz], axis=-1)
254
+
255
+
256
+ def point_quat2quat(quat):
257
+ _quat = quat.copy()
258
+ if len(_quat.shape) < 2:
259
+ _quat = np.expand_dims(_quat, 0)
260
+ assert _quat.shape[1] == 5
261
+ angle = np.arctan(_quat[:, [0]] / _quat[:, [1]])
262
+ qw = np.cos(angle / 2)
263
+
264
+ qxyz = _quat[:, 2:]
265
+ qxyz[np.squeeze(np.abs(np.sin(angle / 2))) >= 1e-5] = (qxyz * np.sin(angle / 2))[
266
+ np.squeeze(np.abs(np.sin(angle / 2))) >= 1e-5
267
+ ]
268
+ return np.concatenate([qw, qxyz], axis=-1)
269
+
270
+
271
+ def normalize_angles(angles):
272
+ angles = angles.copy()
273
+ if angles.size > 0:
274
+ angles = (angles + np.pi) % (2 * np.pi) - np.pi
275
+ assert -np.pi - 1e-6 <= angles.min() and angles.max() <= np.pi + 1e-6
276
+ return angles
277
+
278
+
279
+ def round_to_straight_angles(angles):
280
+ angles = np.round(angles / (np.pi / 2)) * (np.pi / 2)
281
+ return normalize_angles(angles)
282
+
283
+
284
+ def get_parallel_rotations():
285
+ mult90 = [0, np.pi / 2, -np.pi / 2, np.pi]
286
+ parallel_rotations = []
287
+ for euler in itertools.product(mult90, repeat=3):
288
+ canonical = mat2euler(euler2mat(euler))
289
+ canonical = np.round(canonical / (np.pi / 2))
290
+ if canonical[0] == -2:
291
+ canonical[0] = 2
292
+ if canonical[2] == -2:
293
+ canonical[2] = 2
294
+ canonical *= np.pi / 2
295
+ if all([(canonical != rot).any() for rot in parallel_rotations]):
296
+ parallel_rotations += [canonical]
297
+ assert len(parallel_rotations) == 24
298
+ return parallel_rotations
299
+
300
+
301
+ def posRotMat2TFMat(pos, rot_mat):
302
+ t_mat = np.eye(4)
303
+ t_mat[:3, :3] = rot_mat
304
+ t_mat[:3, 3] = np.array(pos)
305
+ return t_mat
306
+
307
+
308
+ def mat2posQuat(mat):
309
+ pos = mat[:3, 3]
310
+ quat = mat2quat(mat[:3, :3])
311
+ return pos, quat
312
+
313
+
314
+ def wxyz_to_xyzw(quat):
315
+ return np.roll(quat, -1)
316
+
317
+
318
+ def xyzw_to_wxyz(quat):
319
+ return np.roll(quat, 1)