Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +2 -0
- README.md +47 -3
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/bundle.yaml +107 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/centauro_big_wheels_no_yaw_ub_2026_01_19_14_51_36_ID.srdf +147 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/centauro_big_wheels_no_yaw_ub_2026_01_19_14_51_36_ID.urdf +1569 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/centauro_rhc.py +144 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/centauro_rhc_wheels_continuous_no_yaw_ub.yaml +368 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl_model +3 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/fake_pos_track_env_phase_control.py +198 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/flight_phase_control_env.py +219 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/hybrid_quad_rhc.py +1243 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/isaac_world_interface.py +0 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/jnt_imp_config.yaml +44 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/jnt_imp_config_no_yaw.yaml +44 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/launch_control_cluster.py +106 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/launch_train_env.py +357 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/launch_world_interface.py +202 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/__init__.py +0 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/augmpc_cluster_client.py +105 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/augmpc_cluster_server.py +43 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/__init__.py +0 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/config/rhc_horizon_config.yaml +200 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/gait_manager.py +565 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/horizon_imports.py +18 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/horizon_imports_glob.py +28 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/hybrid_quad_rhc.py +1243 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/hybrid_quad_rhc_refs.py +381 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/utils/__init__.py +0 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/utils/math_utils.py +165 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/hybrid_quad_client.py +95 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/rhc.py +1226 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/sac.py +680 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/sactor_critic_algo.py +0 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/training_env_base.py +2000 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/twist_tracking_env.py +1396 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/world_interface_base.py +1486 -0
- bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/xbot2_basic.yaml +81 -0
- bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/bundle.yaml +107 -0
- bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/centauro_big_wheels_ub_2026_02_21_13_59_20_ID.srdf +147 -0
- bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/centauro_big_wheels_ub_2026_02_21_13_59_20_ID.urdf +1569 -0
- bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/centauro_rhc.py +145 -0
- bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/centauro_rhc_config_no_wheels_ub.yaml +295 -0
- bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv_model +3 -0
- bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/fake_pos_tracking_env.py +202 -0
- bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/hybrid_quad_rhc.py +1324 -0
- bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/isaac_world_interface.py +0 -0
- bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/jnt_imp_config.yaml +46 -0
- bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/jnt_imp_config_with_ub.yaml +46 -0
- bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/launch_control_cluster.py +106 -0
- bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/launch_train_env.py +358 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
|
| 37 |
+
*_model filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -1,3 +1,47 @@
|
|
| 1 |
-
---
|
| 2 |
-
license: gpl-2.0
|
| 3 |
-
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: gpl-2.0
|
| 3 |
+
---
|
| 4 |
+
|
| 5 |
+
# AugMPCModels
|
| 6 |
+
|
| 7 |
+
Deployment bundles for [AugMPC](https://github.com/AndrePatri/AugMPC), published alongside the preprint:
|
| 8 |
+
|
| 9 |
+
- Andrea Patrizi, Carlo Rizzardo, Arturo Laurenzi, Francesco Ruscelli, Luca Rossini, Nikos G. Tsagarakis
|
| 10 |
+
- *RL-Augmented MPC for Non-Gaited Legged and Hybrid Locomotion*
|
| 11 |
+
- arXiv: [2603.10878](https://arxiv.org/abs/2603.10878)
|
| 12 |
+
|
| 13 |
+
## Repository structure
|
| 14 |
+
|
| 15 |
+
Each model is distributed as a **bundle**, not just as a checkpoint file. A bundle may include:
|
| 16 |
+
|
| 17 |
+
- the policy checkpoint
|
| 18 |
+
- environment and deployment configuration files
|
| 19 |
+
- robot description files (`URDF`, `SRDF`)
|
| 20 |
+
- controller/world-interface helpers needed for reproduction
|
| 21 |
+
- a `bundle.yaml` manifest describing the contents
|
| 22 |
+
|
| 23 |
+
Current layout:
|
| 24 |
+
|
| 25 |
+
```text
|
| 26 |
+
bundles/
|
| 27 |
+
centauro/
|
| 28 |
+
<bundle_name>/
|
| 29 |
+
bundle.yaml
|
| 30 |
+
<checkpoint>_model
|
| 31 |
+
*.yaml
|
| 32 |
+
*.py
|
| 33 |
+
*.urdf
|
| 34 |
+
*.srdf
|
| 35 |
+
other/
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
## Usage model
|
| 39 |
+
|
| 40 |
+
The intended runtime flow is:
|
| 41 |
+
|
| 42 |
+
1. resolve or download a bundle locally,
|
| 43 |
+
2. read `bundle.yaml`,
|
| 44 |
+
3. locate the checkpoint file and companion configs,
|
| 45 |
+
4. launch AugMPC using the resolved local bundle path.
|
| 46 |
+
|
| 47 |
+
This repository is therefore meant to back a bundle resolver, rather than a direct `torch.load()` call on a remote file.
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/bundle.yaml
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
bundle_format: augmpc_model_bundle_v1
|
| 2 |
+
bundle_name: d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl
|
| 3 |
+
checkpoint_file: d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl_model
|
| 4 |
+
preserved_training_cfgs:
|
| 5 |
+
- ibrido_run__2026_01_19_14_51_36_ID/training_cfg_centauro_no_yaw_ub_cloop_perception.sh
|
| 6 |
+
framework:
|
| 7 |
+
repos:
|
| 8 |
+
AugMPC:
|
| 9 |
+
commit: f2ff28085ea76d2b548841de6f363f7183480f86
|
| 10 |
+
branch: ibrido
|
| 11 |
+
remote: git@github.com:AndrePatri/AugMPC.git
|
| 12 |
+
dirty: false
|
| 13 |
+
AugMPCEnvs:
|
| 14 |
+
commit: 46c5d4161cb4b249b3a2e50c93c6bc2aa087f027
|
| 15 |
+
branch: ibrido
|
| 16 |
+
remote: git@github.com:AndrePatri/AugMPCEnvs.git
|
| 17 |
+
dirty: false
|
| 18 |
+
AugMPCModels:
|
| 19 |
+
commit: 8b15c800c0f5684c61fdaf4847156ff71df61ebc
|
| 20 |
+
branch: main
|
| 21 |
+
remote: https://huggingface.co/AndrePatri/AugMPCModels
|
| 22 |
+
dirty: true
|
| 23 |
+
CentauroHybridMPC:
|
| 24 |
+
commit: 640889d4c3b9c8d360b5a3ccde6fc2bd8f139891
|
| 25 |
+
branch: ibrido
|
| 26 |
+
remote: git@github.com:ADVRHumanoids/CentauroHybridMPC.git
|
| 27 |
+
dirty: false
|
| 28 |
+
EigenIPC:
|
| 29 |
+
commit: 7c1c3ecd08716e61ed164a6e0bb788aa716705ca
|
| 30 |
+
branch: devel
|
| 31 |
+
remote: git@github.com:AndrePatri/EigenIPC.git
|
| 32 |
+
dirty: false
|
| 33 |
+
IBRIDO:
|
| 34 |
+
commit: 0ceb5f3e0508b6ecdce12bcc8f0dcbcde8f29a93
|
| 35 |
+
branch: main
|
| 36 |
+
remote: git@github.com:AndrePatri/IBRIDO.git
|
| 37 |
+
dirty: false
|
| 38 |
+
IsaacLab:
|
| 39 |
+
commit: a520a883ce996d855cc9d5255d71fd1c1307633f
|
| 40 |
+
branch: HEAD
|
| 41 |
+
remote: git@github.com:isaac-sim/IsaacLab.git
|
| 42 |
+
dirty: true
|
| 43 |
+
KyonRLStepping:
|
| 44 |
+
commit: 2bea2b8d70078974869df0549e90fc27ff31f851
|
| 45 |
+
branch: ibrido
|
| 46 |
+
remote: git@github.com:ADVRHumanoids/KyonRLStepping.git
|
| 47 |
+
dirty: false
|
| 48 |
+
MPCHive:
|
| 49 |
+
commit: 45b4fc692850cef607020dda2e32fd708e7fff62
|
| 50 |
+
branch: devel
|
| 51 |
+
remote: git@github.com:AndrePatri/MPCHive.git
|
| 52 |
+
dirty: false
|
| 53 |
+
MPCViz:
|
| 54 |
+
commit: 806d03efcc9d8ab1fb04991a159c19ba89bfb85b
|
| 55 |
+
branch: ros2_humble
|
| 56 |
+
remote: git@github.com:AndrePatri/MPCViz.git
|
| 57 |
+
dirty: false
|
| 58 |
+
adarl:
|
| 59 |
+
commit: f585499e49fa05fdd070a77f3211c0996599b87b
|
| 60 |
+
branch: ibrido
|
| 61 |
+
remote: git@github.com:c-rizz/adarl.git
|
| 62 |
+
dirty: false
|
| 63 |
+
casadi:
|
| 64 |
+
commit: 79cebe3b416dee22abc87de0076b80a5b97bd345
|
| 65 |
+
branch: optional_float
|
| 66 |
+
remote: git@github.com:AndrePatri/casadi.git
|
| 67 |
+
dirty: true
|
| 68 |
+
horizon:
|
| 69 |
+
commit: 3b084317709ff9b88d4a07ac5436f5988b39eece
|
| 70 |
+
branch: ibrido
|
| 71 |
+
remote: git@github.com:AndrePatri/horizon.git
|
| 72 |
+
dirty: true
|
| 73 |
+
iit-centauro-ros-pkg:
|
| 74 |
+
commit: 6069807ebb37a6d7df39430a02685e09ed9b167a
|
| 75 |
+
branch: ibrido_ros2
|
| 76 |
+
remote: git@github.com:AndrePatri/iit-centauro-ros-pkg.git
|
| 77 |
+
dirty: false
|
| 78 |
+
iit-dagana-ros-pkg:
|
| 79 |
+
commit: f7ecd6c84a0b7f3320c1b7de6449cbcd4445d2fe
|
| 80 |
+
branch: ibrido_ros2
|
| 81 |
+
remote: git@github.com:AndrePatri/iit-dagana-ros-pkg.git
|
| 82 |
+
dirty: false
|
| 83 |
+
iit-kyon-description:
|
| 84 |
+
commit: 50fd7c8909b3ddfd1ebbe67c61d6b775b86df6b1
|
| 85 |
+
branch: ibrido_ros2
|
| 86 |
+
remote: git@github.com:ADVRHumanoids/iit-kyon-ros-pkg.git
|
| 87 |
+
dirty: false
|
| 88 |
+
iit-kyon-description-mpc:
|
| 89 |
+
commit: 3a92bee28405172e8f6c628b4498703724d35bf5
|
| 90 |
+
branch: ibrido_ros2
|
| 91 |
+
remote: git@github.com:ADVRHumanoids/iit-kyon-ros-pkg.git
|
| 92 |
+
dirty: false
|
| 93 |
+
iit-kyon-ros-pkg:
|
| 94 |
+
commit: 298917efffb63dbca540e0aedbd21b41bf393fbf
|
| 95 |
+
branch: ibrido_ros2_simple
|
| 96 |
+
remote: git@github.com:ADVRHumanoids/iit-kyon-ros-pkg.git
|
| 97 |
+
dirty: false
|
| 98 |
+
phase_manager:
|
| 99 |
+
commit: 9925d18c0d7a55d013cbaa4998c61d85a3a8944f
|
| 100 |
+
branch: ibrido
|
| 101 |
+
remote: git@github.com:AndrePatri/phase_manager.git
|
| 102 |
+
dirty: false
|
| 103 |
+
unitree_ros:
|
| 104 |
+
commit: c75a622b8782d11dd6aa4c2ebd3b0f9c13a56aae
|
| 105 |
+
branch: ibrido
|
| 106 |
+
remote: git@github.com:AndrePatri/unitree_ros.git
|
| 107 |
+
dirty: true
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/centauro_big_wheels_no_yaw_ub_2026_01_19_14_51_36_ID.srdf
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?xml version="1.0" ?>
|
| 2 |
+
<!-- =================================================================================== -->
|
| 3 |
+
<!-- | This document was autogenerated by xacro from /root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_srdf/srdf/centauro.srdf.xacro | -->
|
| 4 |
+
<!-- | EDITING THIS FILE BY HAND IS NOT RECOMMENDED | -->
|
| 5 |
+
<!-- =================================================================================== -->
|
| 6 |
+
<!--This does not replace URDF, and is not an extension of URDF.
|
| 7 |
+
This is a format for representing semantic information about the robot structure.
|
| 8 |
+
A URDF file must exist for this robot as well, where the joints and the links that are referenced are defined
|
| 9 |
+
-->
|
| 10 |
+
<robot name="centauro">
|
| 11 |
+
<!-- none, ball, dagana_fixed, dagana -->
|
| 12 |
+
<group name="base">
|
| 13 |
+
<link name="pelvis"/>
|
| 14 |
+
</group>
|
| 15 |
+
<group name="imu_sensors">
|
| 16 |
+
<link name="imu_link"/>
|
| 17 |
+
</group>
|
| 18 |
+
<group name="front_left_leg">
|
| 19 |
+
<chain base_link="pelvis" tip_link="wheel_1"/>
|
| 20 |
+
</group>
|
| 21 |
+
<group name="front_right_leg">
|
| 22 |
+
<chain base_link="pelvis" tip_link="wheel_2"/>
|
| 23 |
+
</group>
|
| 24 |
+
<group name="rear_right_leg">
|
| 25 |
+
<chain base_link="pelvis" tip_link="wheel_4"/>
|
| 26 |
+
</group>
|
| 27 |
+
<group name="rear_left_leg">
|
| 28 |
+
<chain base_link="pelvis" tip_link="wheel_3"/>
|
| 29 |
+
</group>
|
| 30 |
+
<group name="left_arm">
|
| 31 |
+
<chain base_link="torso_2" tip_link="arm1_8"/>
|
| 32 |
+
</group>
|
| 33 |
+
<group name="right_arm">
|
| 34 |
+
<chain base_link="torso_2" tip_link="arm2_8"/>
|
| 35 |
+
</group>
|
| 36 |
+
<group name="torso">
|
| 37 |
+
<chain base_link="pelvis" tip_link="torso_2"/>
|
| 38 |
+
</group>
|
| 39 |
+
<group name="velodyne">
|
| 40 |
+
<chain base_link="torso_2" tip_link="velodyne_motor"/>
|
| 41 |
+
</group>
|
| 42 |
+
<group name="d435_head">
|
| 43 |
+
<chain base_link="torso_2" tip_link="d435_head_motor"/>
|
| 44 |
+
</group>
|
| 45 |
+
<group name="chains">
|
| 46 |
+
<group name="front_left_leg"/>
|
| 47 |
+
<group name="front_right_leg"/>
|
| 48 |
+
<group name="rear_right_leg"/>
|
| 49 |
+
<group name="rear_left_leg"/>
|
| 50 |
+
<group name="left_arm"/>
|
| 51 |
+
<group name="right_arm"/>
|
| 52 |
+
<group name="torso"/>
|
| 53 |
+
<group name="velodyne"/>
|
| 54 |
+
<group name="d435_head"/>
|
| 55 |
+
</group>
|
| 56 |
+
<!-- Homing posture -->
|
| 57 |
+
<!-- <group_state name="home" group="chains">
|
| 58 |
+
<joint name="hip_yaw_1" value="-0.746874"/>
|
| 59 |
+
<joint name="hip_pitch_1" value="-1.25409"/>
|
| 60 |
+
<joint name="knee_pitch_1" value="-1.55576"/>
|
| 61 |
+
<joint name="ankle_pitch_1" value="-0.301666"/>
|
| 62 |
+
<joint name="ankle_yaw_1" value="0.746874"/>
|
| 63 |
+
<joint name="hip_yaw_2" value="0.746874"/>
|
| 64 |
+
<joint name="hip_pitch_2" value="1.25409"/>
|
| 65 |
+
<joint name="knee_pitch_2" value="1.55576"/>
|
| 66 |
+
<joint name="ankle_pitch_2" value="0.301666"/>
|
| 67 |
+
<joint name="ankle_yaw_2" value="-0.746874"/>
|
| 68 |
+
<joint name="hip_yaw_3" value="0.746874"/>
|
| 69 |
+
<joint name="hip_pitch_3" value="1.25409"/>
|
| 70 |
+
<joint name="knee_pitch_3" value="1.55576"/>
|
| 71 |
+
<joint name="ankle_pitch_3" value="0.301667"/>
|
| 72 |
+
<joint name="ankle_yaw_3" value="-0.746874"/>
|
| 73 |
+
<joint name="hip_yaw_4" value="-0.746874"/>
|
| 74 |
+
<joint name="hip_pitch_4" value="-1.25409"/>
|
| 75 |
+
<joint name="knee_pitch_4" value="-1.55576"/>
|
| 76 |
+
<joint name="ankle_pitch_4" value="-0.301667"/>
|
| 77 |
+
<joint name="ankle_yaw_4" value="0.746874"/>
|
| 78 |
+
<joint name="torso_yaw" value="3.56617e-13"/>
|
| 79 |
+
<joint name="velodyne_joint" value="0"/>
|
| 80 |
+
<joint name="d435_head_joint" value="0"/>
|
| 81 |
+
<joint name="j_arm1_1" value="0.520149"/>
|
| 82 |
+
<joint name="j_arm1_2" value="0.320865"/>
|
| 83 |
+
<joint name="j_arm1_3" value="0.274669"/>
|
| 84 |
+
<joint name="j_arm1_4" value="-2.23604"/>
|
| 85 |
+
<joint name="j_arm1_5" value="0.0500815"/>
|
| 86 |
+
<joint name="j_arm1_6" value="-0.781461"/>
|
| 87 |
+
<joint name="j_arm2_1" value="0.520149"/>
|
| 88 |
+
<joint name="j_arm2_2" value="-0.320865"/>
|
| 89 |
+
<joint name="j_arm2_3" value="-0.274669"/>
|
| 90 |
+
<joint name="j_arm2_4" value="-2.23604"/>
|
| 91 |
+
<joint name="j_arm2_5" value="-0.0500815"/>
|
| 92 |
+
<joint name="j_arm2_6" value="-0.781461"/>
|
| 93 |
+
<joint name="j_wheel_1" value="0.0"/>
|
| 94 |
+
<joint name="j_wheel_2" value="0.0"/>
|
| 95 |
+
<joint name="j_wheel_3" value="0.0"/>
|
| 96 |
+
<joint name="j_wheel_4" value="0.0"/>
|
| 97 |
+
<xacro:if value="${END_EFFECTOR_LEFT == 'dagana'}">
|
| 98 |
+
<joint name="dagana_1_claw_joint" value="0"/>
|
| 99 |
+
</xacro:if>
|
| 100 |
+
<xacro:if value="${END_EFFECTOR_RIGHT == 'dagana'}">
|
| 101 |
+
<joint name="dagana_2_claw_joint" value="0"/>
|
| 102 |
+
</xacro:if>
|
| 103 |
+
|
| 104 |
+
</group_state> -->
|
| 105 |
+
<!-- Balanced weight homing -->
|
| 106 |
+
<group_state group="chains" name="home">
|
| 107 |
+
<joint name="hip_yaw_1" value="-0.5"/>
|
| 108 |
+
<joint name="hip_pitch_1" value="-1.37"/>
|
| 109 |
+
<joint name="knee_pitch_1" value="-1.34"/>
|
| 110 |
+
<joint name="ankle_pitch_1" value="-0.03"/>
|
| 111 |
+
<joint name="ankle_yaw_1" value="0.6"/>
|
| 112 |
+
<joint name="hip_yaw_2" value="0.5"/>
|
| 113 |
+
<joint name="hip_pitch_2" value="1.37"/>
|
| 114 |
+
<joint name="knee_pitch_2" value="1.34"/>
|
| 115 |
+
<joint name="ankle_pitch_2" value="-0.03"/>
|
| 116 |
+
<joint name="ankle_yaw_2" value="-0.6"/>
|
| 117 |
+
<joint name="hip_yaw_3" value="1.28"/>
|
| 118 |
+
<joint name="hip_pitch_3" value="1.29"/>
|
| 119 |
+
<joint name="knee_pitch_3" value="1.71"/>
|
| 120 |
+
<joint name="ankle_pitch_3" value="0.43"/>
|
| 121 |
+
<joint name="ankle_yaw_3" value="-1.3"/>
|
| 122 |
+
<joint name="hip_yaw_4" value="-1.28"/>
|
| 123 |
+
<joint name="hip_pitch_4" value="-1.29"/>
|
| 124 |
+
<joint name="knee_pitch_4" value="-1.71"/>
|
| 125 |
+
<joint name="ankle_pitch_4" value="-0.43"/>
|
| 126 |
+
<joint name="ankle_yaw_4" value="1.3"/>
|
| 127 |
+
<joint name="torso_yaw" value="3.56617e-13"/>
|
| 128 |
+
<joint name="velodyne_joint" value="0"/>
|
| 129 |
+
<joint name="d435_head_joint" value="0"/>
|
| 130 |
+
<joint name="j_arm1_1" value="0.520149"/>
|
| 131 |
+
<joint name="j_arm1_2" value="0.320865"/>
|
| 132 |
+
<joint name="j_arm1_3" value="0.274669"/>
|
| 133 |
+
<joint name="j_arm1_4" value="-2.23604"/>
|
| 134 |
+
<joint name="j_arm1_5" value="0.0500815"/>
|
| 135 |
+
<joint name="j_arm1_6" value="-0.781461"/>
|
| 136 |
+
<joint name="j_arm2_1" value="0.520149"/>
|
| 137 |
+
<joint name="j_arm2_2" value="-0.320865"/>
|
| 138 |
+
<joint name="j_arm2_3" value="-0.274669"/>
|
| 139 |
+
<joint name="j_arm2_4" value="-2.23604"/>
|
| 140 |
+
<joint name="j_arm2_5" value="-0.0500815"/>
|
| 141 |
+
<joint name="j_arm2_6" value="-0.781461"/>
|
| 142 |
+
<joint name="j_wheel_1" value="0.0"/>
|
| 143 |
+
<joint name="j_wheel_2" value="0.0"/>
|
| 144 |
+
<joint name="j_wheel_3" value="0.0"/>
|
| 145 |
+
<joint name="j_wheel_4" value="0.0"/>
|
| 146 |
+
</group_state>
|
| 147 |
+
</robot>
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/centauro_big_wheels_no_yaw_ub_2026_01_19_14_51_36_ID.urdf
ADDED
|
@@ -0,0 +1,1569 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?xml version="1.0" ?>
|
| 2 |
+
<!-- =================================================================================== -->
|
| 3 |
+
<!-- | This document was autogenerated by xacro from /root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/urdf/centauro.urdf.xacro | -->
|
| 4 |
+
<!-- | EDITING THIS FILE BY HAND IS NOT RECOMMENDED | -->
|
| 5 |
+
<!-- =================================================================================== -->
|
| 6 |
+
<robot name="centauro">
|
| 7 |
+
<!-- none, ball, dagana_fixed, dagana -->
|
| 8 |
+
<!-- scaling facto for available peack torque link side, from 0 to 1 -->
|
| 9 |
+
<material name="black">
|
| 10 |
+
<color rgba="0.4 0.4 0.4 1"/>
|
| 11 |
+
</material>
|
| 12 |
+
<material name="dark">
|
| 13 |
+
<color rgba="0.1 0.1 0.1 1"/>
|
| 14 |
+
</material>
|
| 15 |
+
<material name="dark_grey">
|
| 16 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 17 |
+
</material>
|
| 18 |
+
<!-- Note that the "23" suffix denotes the new bigger-size wheel -->
|
| 19 |
+
<!-- ??? -->
|
| 20 |
+
<!-- ??? -->
|
| 21 |
+
<!-- Origin -->
|
| 22 |
+
<!-- <xacro:property name="hip_yaw_lower" value="${[-2.827,-2.583, -2.583 ,-2.827]}"/>
|
| 23 |
+
<xacro:property name="hip_yaw_upper" value="${[ 2.583, 2.827, 2.827 , 2.583]}"/> -->
|
| 24 |
+
<link name="base_link"/>
|
| 25 |
+
<joint name="base_joint" type="fixed">
|
| 26 |
+
<parent link="base_link"/>
|
| 27 |
+
<child link="pelvis"/>
|
| 28 |
+
<origin rpy="0 0 0" xyz="0 0 0"/>
|
| 29 |
+
</joint>
|
| 30 |
+
<link name="pelvis">
|
| 31 |
+
<inertial>
|
| 32 |
+
<origin xyz="-0.0016320207 0.0026534004000000003 0.079167428"/>
|
| 33 |
+
<mass value="26.584529"/>
|
| 34 |
+
<inertia ixx="0.39195477" ixy="0.024781258999999996" ixz="0.017108606999999998" iyy="1.0000708999999999" iyz="0.0052627106000000005" izz="1.0679988999999999"/>
|
| 35 |
+
</inertial>
|
| 36 |
+
<visual>
|
| 37 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 38 |
+
<geometry>
|
| 39 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/pelvis.stl" scale="0.001 0.001 0.001"/>
|
| 40 |
+
</geometry>
|
| 41 |
+
</visual>
|
| 42 |
+
<collision>
|
| 43 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 44 |
+
<geometry>
|
| 45 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/pelvis_reduced.stl" scale="0.001 0.001 0.001"/>
|
| 46 |
+
</geometry>
|
| 47 |
+
</collision>
|
| 48 |
+
</link>
|
| 49 |
+
<link name="imu_link"/>
|
| 50 |
+
<joint name="imu_joint" type="fixed">
|
| 51 |
+
<parent link="pelvis"/>
|
| 52 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.248316 0.0 0.015"/>
|
| 53 |
+
<child link="imu_link"/>
|
| 54 |
+
</joint>
|
| 55 |
+
<!-- torso links -->
|
| 56 |
+
<link name="torso_2">
|
| 57 |
+
<inertial>
|
| 58 |
+
<origin xyz="-0.019497794 0.0045317835 0.13768283"/>
|
| 59 |
+
<mass value="12.553731"/>
|
| 60 |
+
<inertia ixx="0.063643392" ixy="8.939e-05" ixz="-0.00086873" iyy="0.02680235" iyz="-4.657e-05" izz="0.04743015"/>
|
| 61 |
+
</inertial>
|
| 62 |
+
<visual>
|
| 63 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 64 |
+
<geometry>
|
| 65 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/link1_no_head.stl" scale="0.001 0.001 0.001"/>
|
| 66 |
+
</geometry>
|
| 67 |
+
</visual>
|
| 68 |
+
<collision>
|
| 69 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 70 |
+
<geometry>
|
| 71 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/link1_no_head.stl" scale="0.001 0.001 0.001"/>
|
| 72 |
+
</geometry>
|
| 73 |
+
</collision>
|
| 74 |
+
</link>
|
| 75 |
+
<!-- /torso links -->
|
| 76 |
+
<!-- torso joints -->
|
| 77 |
+
<joint name="torso_yaw" type="revolute">
|
| 78 |
+
<parent link="pelvis"/>
|
| 79 |
+
<origin xyz="0.2 0.0 0.256"/>
|
| 80 |
+
<child link="torso_2"/>
|
| 81 |
+
<axis xyz="0 0 1"/>
|
| 82 |
+
<limit effort="147" lower="-2.618" upper="2.618" velocity="5.7"/>
|
| 83 |
+
<!-- TODO -->
|
| 84 |
+
</joint>
|
| 85 |
+
<!-- /torso joints -->
|
| 86 |
+
<!-- /macro arms -->
|
| 87 |
+
<!-- LINKS -->
|
| 88 |
+
<!-- shoulder yaw-roll-->
|
| 89 |
+
<link name="arm1_1">
|
| 90 |
+
<inertial>
|
| 91 |
+
<origin xyz="-0.0074457212 0.03410796 0.00010978102"/>
|
| 92 |
+
<mass value="1.9628675"/>
|
| 93 |
+
<inertia ixx="0.0053547717" ixy="0.00036428926" ixz="1.5089568e-05" iyy="0.0033923328" iyz="5.5692312e-05" izz="0.0068921413"/>
|
| 94 |
+
</inertial>
|
| 95 |
+
<visual>
|
| 96 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 97 |
+
<geometry>
|
| 98 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/ShoulderPitch.STL" scale="0.001 -0.001 0.001"/>
|
| 99 |
+
</geometry>
|
| 100 |
+
<material name="dark_grey"/>
|
| 101 |
+
</visual>
|
| 102 |
+
<collision>
|
| 103 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 104 |
+
<geometry>
|
| 105 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/ShoulderPitch.STL" scale="0.001 -0.001 0.001"/>
|
| 106 |
+
</geometry>
|
| 107 |
+
</collision>
|
| 108 |
+
</link>
|
| 109 |
+
<!-- shoulder yaw-roll-->
|
| 110 |
+
<!-- shoulder roll-pitch-->
|
| 111 |
+
<link name="arm1_2">
|
| 112 |
+
<inertial>
|
| 113 |
+
<origin xyz="0.058142302 5.7450803e-05 -0.077477683"/>
|
| 114 |
+
<mass value="1.8595811"/>
|
| 115 |
+
<inertia ixx="0.013776643" ixy="3.7788675e-05" ixz="0.0037690171" iyy="0.015677464" iyz="-9.4893549e-06" izz="0.0046317657"/>
|
| 116 |
+
</inertial>
|
| 117 |
+
<visual>
|
| 118 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 119 |
+
<geometry>
|
| 120 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/ShoulderRoll.STL" scale="0.001 -0.001 0.001"/>
|
| 121 |
+
</geometry>
|
| 122 |
+
</visual>
|
| 123 |
+
<collision>
|
| 124 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 125 |
+
<geometry>
|
| 126 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/ShoulderRoll.STL" scale="0.001 -0.001 0.001"/>
|
| 127 |
+
</geometry>
|
| 128 |
+
</collision>
|
| 129 |
+
</link>
|
| 130 |
+
<!-- shoulder roll-pitch-->
|
| 131 |
+
<!-- shoulder-elbow -->
|
| 132 |
+
<link name="arm1_3">
|
| 133 |
+
<inertial>
|
| 134 |
+
<origin xyz="0.014625194 0.0008172672 -0.028333545"/>
|
| 135 |
+
<mass value="1.6678109"/>
|
| 136 |
+
<inertia ixx="0.0064480435" ixy="-0.00015639093" ixz="0.0012205359" iyy="0.0073372077" iyz="8.9941532e-05" izz="0.0036738448"/>
|
| 137 |
+
</inertial>
|
| 138 |
+
<visual>
|
| 139 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 140 |
+
<geometry>
|
| 141 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/ShoulderYaw.STL" scale="0.001 -0.001 0.001"/>
|
| 142 |
+
</geometry>
|
| 143 |
+
<material name="dark_grey"/>
|
| 144 |
+
</visual>
|
| 145 |
+
<collision>
|
| 146 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 147 |
+
<geometry>
|
| 148 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/ShoulderYaw.STL" scale="0.001 -0.001 0.001"/>
|
| 149 |
+
</geometry>
|
| 150 |
+
</collision>
|
| 151 |
+
</link>
|
| 152 |
+
<!-- /shoulder-elbow -->
|
| 153 |
+
<!-- elbow yaw-pitch -->
|
| 154 |
+
<link name="arm1_4">
|
| 155 |
+
<inertial>
|
| 156 |
+
<origin xyz="-0.0076833067 -0.040302205 -0.043492779"/>
|
| 157 |
+
<mass value="1.3157289"/>
|
| 158 |
+
<inertia ixx="0.004330394" ixy="-0.00011737391" ixz="-0.00041923199" iyy="0.0038539919" iyz="-0.00079573038" izz="0.0017594689"/>
|
| 159 |
+
</inertial>
|
| 160 |
+
<visual>
|
| 161 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 162 |
+
<geometry>
|
| 163 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/Elbow.STL" scale="0.001 -0.001 0.001"/>
|
| 164 |
+
</geometry>
|
| 165 |
+
</visual>
|
| 166 |
+
<collision>
|
| 167 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 168 |
+
<geometry>
|
| 169 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/Elbow.STL" scale="0.001 -0.001 0.001"/>
|
| 170 |
+
</geometry>
|
| 171 |
+
</collision>
|
| 172 |
+
</link>
|
| 173 |
+
<!-- /elbow yaw-pitch -->
|
| 174 |
+
<!-- elbow-wrist -->
|
| 175 |
+
<link name="arm1_5">
|
| 176 |
+
<inertial>
|
| 177 |
+
<origin xyz="-0.00011079615 0.011590836 -0.07816026"/>
|
| 178 |
+
<mass value="1.4908547"/>
|
| 179 |
+
<inertia ixx="0.0085692128" ixy="1.7856252e-05" ixz="1.9379365e-05" iyy="0.0077454159" iyz="-0.00032860094" izz="0.0027441921"/>
|
| 180 |
+
</inertial>
|
| 181 |
+
<visual>
|
| 182 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 183 |
+
<geometry>
|
| 184 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/Forearm.STL" scale="0.001 -0.001 0.001"/>
|
| 185 |
+
</geometry>
|
| 186 |
+
<material name="dark_grey"/>
|
| 187 |
+
</visual>
|
| 188 |
+
<collision>
|
| 189 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 190 |
+
<geometry>
|
| 191 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/Forearm.STL" scale="0.001 -0.001 0.001"/>
|
| 192 |
+
</geometry>
|
| 193 |
+
</collision>
|
| 194 |
+
</link>
|
| 195 |
+
<!-- /elbow-wrist -->
|
| 196 |
+
<!-- wrist yaw-pitch -->
|
| 197 |
+
<link name="arm1_6">
|
| 198 |
+
<inertial>
|
| 199 |
+
<origin xyz="-4.6502396e-06 -0.038014094 -0.069926878"/>
|
| 200 |
+
<mass value="1.1263612"/>
|
| 201 |
+
<inertia ixx="0.0051871784" ixy="2.724437e-05" ixz="2.2833496e-06" iyy="0.0048037789" iyz="-0.00072165653" izz="0.0012771388"/>
|
| 202 |
+
</inertial>
|
| 203 |
+
<visual>
|
| 204 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 205 |
+
<geometry>
|
| 206 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/wrist_pitch_right.stl" scale="0.001 -0.001 0.001"/>
|
| 207 |
+
</geometry>
|
| 208 |
+
</visual>
|
| 209 |
+
<collision>
|
| 210 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 211 |
+
<geometry>
|
| 212 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/wrist_pitch_right.stl" scale="0.001 -0.001 0.001"/>
|
| 213 |
+
</geometry>
|
| 214 |
+
</collision>
|
| 215 |
+
</link>
|
| 216 |
+
<!-- /wrist yaw-pitch -->
|
| 217 |
+
<!-- <link name="arm${arm_num}_7">
|
| 218 |
+
<inertial>
|
| 219 |
+
<origin xyz="${Wrist_3_x} ${rot*Wrist_3_y} ${Wrist_3_z}"/>
|
| 220 |
+
<mass value="${Wrist_3_mass}"/>
|
| 221 |
+
<inertia ixx="${Wrist_3_xx}" ixy="${rot*Wrist_3_xy}" ixz="${Wrist_3_xz}" iyy="${Wrist_3_yy}" iyz="${rot*Wrist_3_yz}" izz="${Wrist_3_zz}"/>
|
| 222 |
+
</inertial>
|
| 223 |
+
|
| 224 |
+
<visual>
|
| 225 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
|
| 226 |
+
<geometry>
|
| 227 |
+
<mesh filename="${MESH_PATH}/ForearmYaw.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 228 |
+
</geometry>
|
| 229 |
+
<material name="dark_grey"/>
|
| 230 |
+
</visual>
|
| 231 |
+
|
| 232 |
+
<collision>
|
| 233 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
|
| 234 |
+
<geometry>
|
| 235 |
+
<mesh filename="${MESH_PATH}/simple/ForearmYaw.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 236 |
+
</geometry>
|
| 237 |
+
</collision>
|
| 238 |
+
</link> -->
|
| 239 |
+
<!-- /LINKS -->
|
| 240 |
+
<!-- JOINTS -->
|
| 241 |
+
<!-- shoulder yaw -->
|
| 242 |
+
<joint name="j_arm1_1" type="revolute">
|
| 243 |
+
<parent link="torso_2"/>
|
| 244 |
+
<child link="arm1_1"/>
|
| 245 |
+
<origin rpy="0.174533 0.0 -0.5235988" xyz="0.0457475 0.169137 0.116626"/>
|
| 246 |
+
<axis xyz="0 1 0"/>
|
| 247 |
+
<limit effort="147.0" lower="-3.312" upper="1.615" velocity="3.86"/>
|
| 248 |
+
</joint>
|
| 249 |
+
<!-- /shoulder yaw -->
|
| 250 |
+
<!-- shoulder roll -->
|
| 251 |
+
<joint name="j_arm1_2" type="revolute">
|
| 252 |
+
<parent link="arm1_1"/>
|
| 253 |
+
<child link="arm1_2"/>
|
| 254 |
+
<origin rpy="-0.1745327 0.0 0.0" xyz="-0.09015 0.062 0.0"/>
|
| 255 |
+
<axis xyz="1 0 0"/>
|
| 256 |
+
<limit effort="147.0" lower="0.02" upper="3.431" velocity="3.86"/>
|
| 257 |
+
</joint>
|
| 258 |
+
<!-- /shoulder roll -->
|
| 259 |
+
<!-- shoulder pitch-->
|
| 260 |
+
<joint name="j_arm1_3" type="revolute">
|
| 261 |
+
<parent link="arm1_2"/>
|
| 262 |
+
<child link="arm1_3"/>
|
| 263 |
+
<origin xyz="0.09015 0.0 -0.21815"/>
|
| 264 |
+
<axis xyz="0 0 1"/>
|
| 265 |
+
<limit effort="147.0" lower="-2.552" upper="2.566" velocity="6.06"/>
|
| 266 |
+
</joint>
|
| 267 |
+
<!-- /shoulder pitch -->
|
| 268 |
+
<!-- elbow yaw -->
|
| 269 |
+
<joint name="j_arm1_4" type="revolute">
|
| 270 |
+
<parent link="arm1_3"/>
|
| 271 |
+
<child link="arm1_4"/>
|
| 272 |
+
<origin xyz="0.045 0.05515 -0.074"/>
|
| 273 |
+
<axis xyz="0 1 0"/>
|
| 274 |
+
<limit effort="147.0" lower="-2.465" upper="0.28" velocity="6.06"/>
|
| 275 |
+
</joint>
|
| 276 |
+
<!-- /elbow yaw -->
|
| 277 |
+
<!-- elbow pitch-->
|
| 278 |
+
<joint name="j_arm1_5" type="revolute">
|
| 279 |
+
<parent link="arm1_4"/>
|
| 280 |
+
<child link="arm1_5"/>
|
| 281 |
+
<origin xyz="-0.015 -0.05515 -0.095"/>
|
| 282 |
+
<axis xyz="0 0 1"/>
|
| 283 |
+
<limit effort="55.0" lower="-2.569" upper="2.562" velocity="11.72"/>
|
| 284 |
+
</joint>
|
| 285 |
+
<!-- /elbow pitch-->
|
| 286 |
+
<!-- wrist yaw-->
|
| 287 |
+
<joint name="j_arm1_6" type="revolute">
|
| 288 |
+
<parent link="arm1_5"/>
|
| 289 |
+
<child link="arm1_6"/>
|
| 290 |
+
<origin xyz="0.0 0.049 -0.156"/>
|
| 291 |
+
<axis xyz="0 1 0"/>
|
| 292 |
+
<limit effort="55.0" lower="-1.529" upper="1.509" velocity="11.72"/>
|
| 293 |
+
</joint>
|
| 294 |
+
<!-- /wrist yaw-->
|
| 295 |
+
<!-- wrist pitch-->
|
| 296 |
+
<!-- <joint name="j_arm${arm_num}_7" type="fixed">
|
| 297 |
+
<parent link="arm${arm_num}_6"/>
|
| 298 |
+
<child link="arm${arm_num}_7"/>
|
| 299 |
+
<origin xyz="${Wrist_3_Ox} ${rot*Wrist_3_Oy} ${Wrist_3_Oz}"/>
|
| 300 |
+
<axis xyz="0 0 1"/>
|
| 301 |
+
<limit lower="${j_arm_7_lower[arm_num-1]}" upper="${j_arm_7_upper[arm_num-1]}" effort="${j_arm_7_torque[arm_num-1]}" velocity="${j_arm_7_velocity[arm_num-1]}"/>
|
| 302 |
+
</joint> -->
|
| 303 |
+
<!-- wrist pitch-->
|
| 304 |
+
<!-- force-troque sensor -->
|
| 305 |
+
<!-- end-effector -->
|
| 306 |
+
<!-- wrist pitch-->
|
| 307 |
+
<!-- <joint name="j_ft_${arm_num}" type="fixed">
|
| 308 |
+
<parent link="arm${arm_num}_7"/>
|
| 309 |
+
<child link="ft_arm${arm_num}"/>
|
| 310 |
+
<origin xyz="${Ft_arm_Ox} ${Ft_arm_Oy} ${Ft_arm_Oz}" rpy="${Ft_arm_roll} ${Ft_arm_pitch} ${Ft_arm_yaw}" />
|
| 311 |
+
<axis xyz="0 0 1"/>
|
| 312 |
+
<limit lower="0.0" upper="0.0" effort="0" velocity="0"/>
|
| 313 |
+
</joint> -->
|
| 314 |
+
<!-- wrist pitch-->
|
| 315 |
+
<!-- <link name="ft_arm${arm_num}">
|
| 316 |
+
<inertial>
|
| 317 |
+
<origin xyz="${Ft_arm_x} ${rot*Ft_arm_y} ${Ft_arm_z}"/>
|
| 318 |
+
<mass value="${Ft_arm_mass}"/>
|
| 319 |
+
<inertia ixx="${Ft_arm_xx}" ixy="${rot*Ft_arm_xy}" ixz="${Ft_arm_xz}" iyy="${Ft_arm_yy}" iyz="${rot*Ft_arm_yz}" izz="${Ft_arm_zz}"/>
|
| 320 |
+
</inertial> -->
|
| 321 |
+
<!--visual>
|
| 322 |
+
<origin xyz="0.0 0.0 0.0" rpy="${PI} 0.0 0.0"/>
|
| 323 |
+
<geometry>
|
| 324 |
+
<mesh filename="${MESH_PATH}/Wrist.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 325 |
+
</geometry>
|
| 326 |
+
</visual-->
|
| 327 |
+
<!--collision>
|
| 328 |
+
<origin xyz="0.0 0.0 0.0" rpy="${PI} 0.0 0.0"/>
|
| 329 |
+
<geometry>
|
| 330 |
+
<mesh filename="${MESH_PATH}/simple/Wrist.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 331 |
+
</geometry>
|
| 332 |
+
</collision-->
|
| 333 |
+
<!-- </link> -->
|
| 334 |
+
<!-- LINKS -->
|
| 335 |
+
<!-- shoulder yaw-roll-->
|
| 336 |
+
<link name="arm2_1">
|
| 337 |
+
<inertial>
|
| 338 |
+
<origin xyz="-0.0074457212 -0.03410796 0.00010978102"/>
|
| 339 |
+
<mass value="1.9628675"/>
|
| 340 |
+
<inertia ixx="0.0053547717" ixy="-0.00036428926" ixz="1.5089568e-05" iyy="0.0033923328" iyz="-5.5692312e-05" izz="0.0068921413"/>
|
| 341 |
+
</inertial>
|
| 342 |
+
<visual>
|
| 343 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 344 |
+
<geometry>
|
| 345 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/ShoulderPitch.STL" scale="0.001 0.001 0.001"/>
|
| 346 |
+
</geometry>
|
| 347 |
+
<material name="dark_grey"/>
|
| 348 |
+
</visual>
|
| 349 |
+
<collision>
|
| 350 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 351 |
+
<geometry>
|
| 352 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/ShoulderPitch.STL" scale="0.001 0.001 0.001"/>
|
| 353 |
+
</geometry>
|
| 354 |
+
</collision>
|
| 355 |
+
</link>
|
| 356 |
+
<!-- shoulder yaw-roll-->
|
| 357 |
+
<!-- shoulder roll-pitch-->
|
| 358 |
+
<link name="arm2_2">
|
| 359 |
+
<inertial>
|
| 360 |
+
<origin xyz="0.058142302 -5.7450803e-05 -0.077477683"/>
|
| 361 |
+
<mass value="1.8595811"/>
|
| 362 |
+
<inertia ixx="0.013776643" ixy="-3.7788675e-05" ixz="0.0037690171" iyy="0.015677464" iyz="9.4893549e-06" izz="0.0046317657"/>
|
| 363 |
+
</inertial>
|
| 364 |
+
<visual>
|
| 365 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 366 |
+
<geometry>
|
| 367 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/ShoulderRoll.STL" scale="0.001 0.001 0.001"/>
|
| 368 |
+
</geometry>
|
| 369 |
+
</visual>
|
| 370 |
+
<collision>
|
| 371 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 372 |
+
<geometry>
|
| 373 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/ShoulderRoll.STL" scale="0.001 0.001 0.001"/>
|
| 374 |
+
</geometry>
|
| 375 |
+
</collision>
|
| 376 |
+
</link>
|
| 377 |
+
<!-- shoulder roll-pitch-->
|
| 378 |
+
<!-- shoulder-elbow -->
|
| 379 |
+
<link name="arm2_3">
|
| 380 |
+
<inertial>
|
| 381 |
+
<origin xyz="0.014625194 -0.0008172672 -0.028333545"/>
|
| 382 |
+
<mass value="1.6678109"/>
|
| 383 |
+
<inertia ixx="0.0064480435" ixy="0.00015639093" ixz="0.0012205359" iyy="0.0073372077" iyz="-8.9941532e-05" izz="0.0036738448"/>
|
| 384 |
+
</inertial>
|
| 385 |
+
<visual>
|
| 386 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 387 |
+
<geometry>
|
| 388 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/ShoulderYaw.STL" scale="0.001 0.001 0.001"/>
|
| 389 |
+
</geometry>
|
| 390 |
+
<material name="dark_grey"/>
|
| 391 |
+
</visual>
|
| 392 |
+
<collision>
|
| 393 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 394 |
+
<geometry>
|
| 395 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/ShoulderYaw.STL" scale="0.001 0.001 0.001"/>
|
| 396 |
+
</geometry>
|
| 397 |
+
</collision>
|
| 398 |
+
</link>
|
| 399 |
+
<!-- /shoulder-elbow -->
|
| 400 |
+
<!-- elbow yaw-pitch -->
|
| 401 |
+
<link name="arm2_4">
|
| 402 |
+
<inertial>
|
| 403 |
+
<origin xyz="-0.0076833067 0.040302205 -0.043492779"/>
|
| 404 |
+
<mass value="1.3157289"/>
|
| 405 |
+
<inertia ixx="0.004330394" ixy="0.00011737391" ixz="-0.00041923199" iyy="0.0038539919" iyz="0.00079573038" izz="0.0017594689"/>
|
| 406 |
+
</inertial>
|
| 407 |
+
<visual>
|
| 408 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 409 |
+
<geometry>
|
| 410 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/Elbow.STL" scale="0.001 0.001 0.001"/>
|
| 411 |
+
</geometry>
|
| 412 |
+
</visual>
|
| 413 |
+
<collision>
|
| 414 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 415 |
+
<geometry>
|
| 416 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/Elbow.STL" scale="0.001 0.001 0.001"/>
|
| 417 |
+
</geometry>
|
| 418 |
+
</collision>
|
| 419 |
+
</link>
|
| 420 |
+
<!-- /elbow yaw-pitch -->
|
| 421 |
+
<!-- elbow-wrist -->
|
| 422 |
+
<link name="arm2_5">
|
| 423 |
+
<inertial>
|
| 424 |
+
<origin xyz="-0.00011079615 -0.011590836 -0.07816026"/>
|
| 425 |
+
<mass value="1.4908547"/>
|
| 426 |
+
<inertia ixx="0.0085692128" ixy="-1.7856252e-05" ixz="1.9379365e-05" iyy="0.0077454159" iyz="0.00032860094" izz="0.0027441921"/>
|
| 427 |
+
</inertial>
|
| 428 |
+
<visual>
|
| 429 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 430 |
+
<geometry>
|
| 431 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/Forearm.STL" scale="0.001 0.001 0.001"/>
|
| 432 |
+
</geometry>
|
| 433 |
+
<material name="dark_grey"/>
|
| 434 |
+
</visual>
|
| 435 |
+
<collision>
|
| 436 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 437 |
+
<geometry>
|
| 438 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/Forearm.STL" scale="0.001 0.001 0.001"/>
|
| 439 |
+
</geometry>
|
| 440 |
+
</collision>
|
| 441 |
+
</link>
|
| 442 |
+
<!-- /elbow-wrist -->
|
| 443 |
+
<!-- wrist yaw-pitch -->
|
| 444 |
+
<link name="arm2_6">
|
| 445 |
+
<inertial>
|
| 446 |
+
<origin xyz="-4.6502396e-06 0.038014094 -0.069926878"/>
|
| 447 |
+
<mass value="1.1263612"/>
|
| 448 |
+
<inertia ixx="0.0051871784" ixy="-2.724437e-05" ixz="2.2833496e-06" iyy="0.0048037789" iyz="0.00072165653" izz="0.0012771388"/>
|
| 449 |
+
</inertial>
|
| 450 |
+
<visual>
|
| 451 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 452 |
+
<geometry>
|
| 453 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/wrist_pitch_right.stl" scale="0.001 0.001 0.001"/>
|
| 454 |
+
</geometry>
|
| 455 |
+
</visual>
|
| 456 |
+
<collision>
|
| 457 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 458 |
+
<geometry>
|
| 459 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/wrist_pitch_right.stl" scale="0.001 0.001 0.001"/>
|
| 460 |
+
</geometry>
|
| 461 |
+
</collision>
|
| 462 |
+
</link>
|
| 463 |
+
<!-- /wrist yaw-pitch -->
|
| 464 |
+
<!-- <link name="arm${arm_num}_7">
|
| 465 |
+
<inertial>
|
| 466 |
+
<origin xyz="${Wrist_3_x} ${rot*Wrist_3_y} ${Wrist_3_z}"/>
|
| 467 |
+
<mass value="${Wrist_3_mass}"/>
|
| 468 |
+
<inertia ixx="${Wrist_3_xx}" ixy="${rot*Wrist_3_xy}" ixz="${Wrist_3_xz}" iyy="${Wrist_3_yy}" iyz="${rot*Wrist_3_yz}" izz="${Wrist_3_zz}"/>
|
| 469 |
+
</inertial>
|
| 470 |
+
|
| 471 |
+
<visual>
|
| 472 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
|
| 473 |
+
<geometry>
|
| 474 |
+
<mesh filename="${MESH_PATH}/ForearmYaw.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 475 |
+
</geometry>
|
| 476 |
+
<material name="dark_grey"/>
|
| 477 |
+
</visual>
|
| 478 |
+
|
| 479 |
+
<collision>
|
| 480 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
|
| 481 |
+
<geometry>
|
| 482 |
+
<mesh filename="${MESH_PATH}/simple/ForearmYaw.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 483 |
+
</geometry>
|
| 484 |
+
</collision>
|
| 485 |
+
</link> -->
|
| 486 |
+
<!-- /LINKS -->
|
| 487 |
+
<!-- JOINTS -->
|
| 488 |
+
<!-- shoulder yaw -->
|
| 489 |
+
<joint name="j_arm2_1" type="revolute">
|
| 490 |
+
<parent link="torso_2"/>
|
| 491 |
+
<child link="arm2_1"/>
|
| 492 |
+
<origin rpy="-0.174533 0.0 0.5235988" xyz="0.0457475 -0.169137 0.116626"/>
|
| 493 |
+
<axis xyz="0 1 0"/>
|
| 494 |
+
<limit effort="147.0" lower="-3.3458" upper="1.6012" velocity="3.86"/>
|
| 495 |
+
</joint>
|
| 496 |
+
<!-- /shoulder yaw -->
|
| 497 |
+
<!-- shoulder roll -->
|
| 498 |
+
<joint name="j_arm2_2" type="revolute">
|
| 499 |
+
<parent link="arm2_1"/>
|
| 500 |
+
<child link="arm2_2"/>
|
| 501 |
+
<origin rpy="0.1745327 0.0 0.0" xyz="-0.09015 -0.062 0.0"/>
|
| 502 |
+
<axis xyz="1 0 0"/>
|
| 503 |
+
<limit effort="147.0" lower="-3.4258" upper="-0.0138" velocity="3.86"/>
|
| 504 |
+
</joint>
|
| 505 |
+
<!-- /shoulder roll -->
|
| 506 |
+
<!-- shoulder pitch-->
|
| 507 |
+
<joint name="j_arm2_3" type="revolute">
|
| 508 |
+
<parent link="arm2_2"/>
|
| 509 |
+
<child link="arm2_3"/>
|
| 510 |
+
<origin xyz="0.09015 0.0 -0.21815"/>
|
| 511 |
+
<axis xyz="0 0 1"/>
|
| 512 |
+
<limit effort="147.0" lower="-2.5614" upper="2.5606" velocity="6.06"/>
|
| 513 |
+
</joint>
|
| 514 |
+
<!-- /shoulder pitch -->
|
| 515 |
+
<!-- elbow yaw -->
|
| 516 |
+
<joint name="j_arm2_4" type="revolute">
|
| 517 |
+
<parent link="arm2_3"/>
|
| 518 |
+
<child link="arm2_4"/>
|
| 519 |
+
<origin xyz="0.045 -0.05515 -0.074"/>
|
| 520 |
+
<axis xyz="0 1 0"/>
|
| 521 |
+
<limit effort="147.0" lower="-2.4794" upper="0.2886" velocity="6.06"/>
|
| 522 |
+
</joint>
|
| 523 |
+
<!-- /elbow yaw -->
|
| 524 |
+
<!-- elbow pitch-->
|
| 525 |
+
<joint name="j_arm2_5" type="revolute">
|
| 526 |
+
<parent link="arm2_4"/>
|
| 527 |
+
<child link="arm2_5"/>
|
| 528 |
+
<origin xyz="-0.015 0.05515 -0.095"/>
|
| 529 |
+
<axis xyz="0 0 1"/>
|
| 530 |
+
<limit effort="55.0" lower="-2.5394" upper="2.5546" velocity="11.72"/>
|
| 531 |
+
</joint>
|
| 532 |
+
<!-- /elbow pitch-->
|
| 533 |
+
<!-- wrist yaw-->
|
| 534 |
+
<joint name="j_arm2_6" type="revolute">
|
| 535 |
+
<parent link="arm2_5"/>
|
| 536 |
+
<child link="arm2_6"/>
|
| 537 |
+
<origin xyz="0.0 -0.049 -0.156"/>
|
| 538 |
+
<axis xyz="0 1 0"/>
|
| 539 |
+
<limit effort="55.0" lower="-1.5154" upper="1.5156" velocity="11.72"/>
|
| 540 |
+
</joint>
|
| 541 |
+
<!-- /wrist yaw-->
|
| 542 |
+
<!-- wrist pitch-->
|
| 543 |
+
<!-- <joint name="j_arm${arm_num}_7" type="fixed">
|
| 544 |
+
<parent link="arm${arm_num}_6"/>
|
| 545 |
+
<child link="arm${arm_num}_7"/>
|
| 546 |
+
<origin xyz="${Wrist_3_Ox} ${rot*Wrist_3_Oy} ${Wrist_3_Oz}"/>
|
| 547 |
+
<axis xyz="0 0 1"/>
|
| 548 |
+
<limit lower="${j_arm_7_lower[arm_num-1]}" upper="${j_arm_7_upper[arm_num-1]}" effort="${j_arm_7_torque[arm_num-1]}" velocity="${j_arm_7_velocity[arm_num-1]}"/>
|
| 549 |
+
</joint> -->
|
| 550 |
+
<!-- wrist pitch-->
|
| 551 |
+
<!-- force-troque sensor -->
|
| 552 |
+
<!-- end-effector -->
|
| 553 |
+
<!-- wrist pitch-->
|
| 554 |
+
<!-- <joint name="j_ft_${arm_num}" type="fixed">
|
| 555 |
+
<parent link="arm${arm_num}_7"/>
|
| 556 |
+
<child link="ft_arm${arm_num}"/>
|
| 557 |
+
<origin xyz="${Ft_arm_Ox} ${Ft_arm_Oy} ${Ft_arm_Oz}" rpy="${Ft_arm_roll} ${Ft_arm_pitch} ${Ft_arm_yaw}" />
|
| 558 |
+
<axis xyz="0 0 1"/>
|
| 559 |
+
<limit lower="0.0" upper="0.0" effort="0" velocity="0"/>
|
| 560 |
+
</joint> -->
|
| 561 |
+
<!-- wrist pitch-->
|
| 562 |
+
<!-- <link name="ft_arm${arm_num}">
|
| 563 |
+
<inertial>
|
| 564 |
+
<origin xyz="${Ft_arm_x} ${rot*Ft_arm_y} ${Ft_arm_z}"/>
|
| 565 |
+
<mass value="${Ft_arm_mass}"/>
|
| 566 |
+
<inertia ixx="${Ft_arm_xx}" ixy="${rot*Ft_arm_xy}" ixz="${Ft_arm_xz}" iyy="${Ft_arm_yy}" iyz="${rot*Ft_arm_yz}" izz="${Ft_arm_zz}"/>
|
| 567 |
+
</inertial> -->
|
| 568 |
+
<!--visual>
|
| 569 |
+
<origin xyz="0.0 0.0 0.0" rpy="${PI} 0.0 0.0"/>
|
| 570 |
+
<geometry>
|
| 571 |
+
<mesh filename="${MESH_PATH}/Wrist.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 572 |
+
</geometry>
|
| 573 |
+
</visual-->
|
| 574 |
+
<!--collision>
|
| 575 |
+
<origin xyz="0.0 0.0 0.0" rpy="${PI} 0.0 0.0"/>
|
| 576 |
+
<geometry>
|
| 577 |
+
<mesh filename="${MESH_PATH}/simple/Wrist.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 578 |
+
</geometry>
|
| 579 |
+
</collision-->
|
| 580 |
+
<!-- </link> -->
|
| 581 |
+
<link name="ball1">
|
| 582 |
+
<inertial>
|
| 583 |
+
<origin rpy="0 0 0" xyz="-1.0072498e-05 3.7590658e-05 0.019772332"/>
|
| 584 |
+
<mass value="1.27"/>
|
| 585 |
+
<inertia ixx="0.0023061092" ixy="2.9181758e-07" ixz="-2.1246683999999997e-07" iyy="0.0023053155000000002" iyz="7.9290978e-07" izz="0.0030675615999999997"/>
|
| 586 |
+
</inertial>
|
| 587 |
+
<visual>
|
| 588 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 589 |
+
<geometry name="ball1_visual">
|
| 590 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/BallHand.stl" scale="0.001 0.001 0.001"/>
|
| 591 |
+
</geometry>
|
| 592 |
+
<material name="dark_grey"/>
|
| 593 |
+
</visual>
|
| 594 |
+
<collision>
|
| 595 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 596 |
+
<geometry name="ball1_collision">
|
| 597 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/BallHand.stl" scale="0.001 0.001 0.001"/>
|
| 598 |
+
</geometry>
|
| 599 |
+
</collision>
|
| 600 |
+
</link>
|
| 601 |
+
<link name="ball1_tip"/>
|
| 602 |
+
<joint name="j_arm1_8" type="fixed">
|
| 603 |
+
<parent link="arm1_6"/>
|
| 604 |
+
<child link="ball1"/>
|
| 605 |
+
<origin rpy="0. 0. 0." xyz="0. -0.05 -0.105"/>
|
| 606 |
+
</joint>
|
| 607 |
+
<joint name="j_ball1_tip" type="fixed">
|
| 608 |
+
<parent link="ball1"/>
|
| 609 |
+
<child link="ball1_tip"/>
|
| 610 |
+
<origin rpy="0 0 0" xyz="0 0 -0.07"/>
|
| 611 |
+
</joint>
|
| 612 |
+
<!-- add armX_8 link for legacy reasons (same as ballX) -->
|
| 613 |
+
<joint name="j_ball1_fixed" type="fixed">
|
| 614 |
+
<parent link="ball1"/>
|
| 615 |
+
<child link="arm1_8"/>
|
| 616 |
+
</joint>
|
| 617 |
+
<link name="arm1_8">
|
| 618 |
+
<inertial>
|
| 619 |
+
<mass value="0"/>
|
| 620 |
+
<inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0"/>
|
| 621 |
+
</inertial>
|
| 622 |
+
</link>
|
| 623 |
+
<link name="ball2">
|
| 624 |
+
<inertial>
|
| 625 |
+
<origin rpy="0 0 0" xyz="-1.0072498e-05 3.7590658e-05 0.019772332"/>
|
| 626 |
+
<mass value="1.27"/>
|
| 627 |
+
<inertia ixx="0.0023061092" ixy="2.9181758e-07" ixz="-2.1246683999999997e-07" iyy="0.0023053155000000002" iyz="7.9290978e-07" izz="0.0030675615999999997"/>
|
| 628 |
+
</inertial>
|
| 629 |
+
<visual>
|
| 630 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 631 |
+
<geometry name="ball2_visual">
|
| 632 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/BallHand.stl" scale="0.001 0.001 0.001"/>
|
| 633 |
+
</geometry>
|
| 634 |
+
<material name="dark_grey"/>
|
| 635 |
+
</visual>
|
| 636 |
+
<collision>
|
| 637 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 638 |
+
<geometry name="ball2_collision">
|
| 639 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/BallHand.stl" scale="0.001 0.001 0.001"/>
|
| 640 |
+
</geometry>
|
| 641 |
+
</collision>
|
| 642 |
+
</link>
|
| 643 |
+
<link name="ball2_tip"/>
|
| 644 |
+
<joint name="j_arm2_8" type="fixed">
|
| 645 |
+
<parent link="arm2_6"/>
|
| 646 |
+
<child link="ball2"/>
|
| 647 |
+
<origin rpy="0. 0. 0." xyz="0. 0.05 -0.105"/>
|
| 648 |
+
</joint>
|
| 649 |
+
<joint name="j_ball2_tip" type="fixed">
|
| 650 |
+
<parent link="ball2"/>
|
| 651 |
+
<child link="ball2_tip"/>
|
| 652 |
+
<origin rpy="0 0 0" xyz="0 0 -0.07"/>
|
| 653 |
+
</joint>
|
| 654 |
+
<!-- add armX_8 link for legacy reasons (same as ballX) -->
|
| 655 |
+
<joint name="j_ball2_fixed" type="fixed">
|
| 656 |
+
<parent link="ball2"/>
|
| 657 |
+
<child link="arm2_8"/>
|
| 658 |
+
</joint>
|
| 659 |
+
<link name="arm2_8">
|
| 660 |
+
<inertial>
|
| 661 |
+
<mass value="0"/>
|
| 662 |
+
<inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0"/>
|
| 663 |
+
</inertial>
|
| 664 |
+
</link>
|
| 665 |
+
<!-- LINKS -->
|
| 666 |
+
<link name="neck_1">
|
| 667 |
+
<inertial>
|
| 668 |
+
<origin xyz="0 0 0"/>
|
| 669 |
+
<mass value="0.33878686"/>
|
| 670 |
+
<!-- MASS/INERTIA TO DO -->
|
| 671 |
+
<inertia ixx="0.0003718568" ixy="-9.42983e-05" ixz="-2.80644e-05" iyy="0.0001886879" iyz="-1.54534e-05" izz="0.0005023443"/>
|
| 672 |
+
</inertial>
|
| 673 |
+
<visual>
|
| 674 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 675 |
+
<geometry>
|
| 676 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/head-base_mesh.stl" scale="0.001 0.001 0.001"/>
|
| 677 |
+
</geometry>
|
| 678 |
+
</visual>
|
| 679 |
+
<collision>
|
| 680 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 681 |
+
<geometry>
|
| 682 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/head-base_mesh.stl" scale="0.001 0.001 0.001"/>
|
| 683 |
+
</geometry>
|
| 684 |
+
</collision>
|
| 685 |
+
</link>
|
| 686 |
+
<link name="velodyne_motor">
|
| 687 |
+
<inertial>
|
| 688 |
+
<origin xyz="0 0 0"/>
|
| 689 |
+
<mass value="0.33878686"/>
|
| 690 |
+
<!-- MASS/INERTIA TO DO -->
|
| 691 |
+
<inertia ixx="0.0003718568" ixy="-9.42983e-05" ixz="-2.80644e-05" iyy="0.0001886879" iyz="-1.54534e-05" izz="0.0005023443"/>
|
| 692 |
+
</inertial>
|
| 693 |
+
<visual>
|
| 694 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 695 |
+
<geometry>
|
| 696 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/lidar_mesh.stl" scale="0.001 0.001 0.001"/>
|
| 697 |
+
</geometry>
|
| 698 |
+
</visual>
|
| 699 |
+
<collision>
|
| 700 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 701 |
+
<geometry>
|
| 702 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/lidar_mesh.stl" scale="0.001 0.001 0.001"/>
|
| 703 |
+
</geometry>
|
| 704 |
+
</collision>
|
| 705 |
+
</link>
|
| 706 |
+
<link name="d435_head_motor">
|
| 707 |
+
<inertial>
|
| 708 |
+
<origin xyz="0 0 0"/>
|
| 709 |
+
<mass value="0.33878686"/>
|
| 710 |
+
<!-- MASS/INERTIA TO DO -->
|
| 711 |
+
<inertia ixx="0.0003718568" ixy="-9.42983e-05" ixz="-2.80644e-05" iyy="0.0001886879" iyz="-1.54534e-05" izz="0.0005023443"/>
|
| 712 |
+
</inertial>
|
| 713 |
+
<visual>
|
| 714 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 715 |
+
<geometry>
|
| 716 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/neck-pitch_mesh.stl" scale="0.001 0.001 0.001"/>
|
| 717 |
+
</geometry>
|
| 718 |
+
</visual>
|
| 719 |
+
<collision>
|
| 720 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 721 |
+
<geometry>
|
| 722 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/neck-pitch_mesh.stl" scale="0.001 0.001 0.001"/>
|
| 723 |
+
</geometry>
|
| 724 |
+
</collision>
|
| 725 |
+
</link>
|
| 726 |
+
<!--JOINTS -->
|
| 727 |
+
<joint name="neck_base" type="fixed">
|
| 728 |
+
<parent link="torso_2"/>
|
| 729 |
+
<origin rpy="0 0 0" xyz="0.0030637045 0.0061607221 0.158"/>
|
| 730 |
+
<child link="neck_1"/>
|
| 731 |
+
<axis xyz="0 0 1"/>
|
| 732 |
+
</joint>
|
| 733 |
+
<joint name="velodyne_joint" type="revolute">
|
| 734 |
+
<parent link="neck_1"/>
|
| 735 |
+
<origin rpy="0 0 0" xyz="0.0822724 0 0.242"/>
|
| 736 |
+
<child link="velodyne_motor"/>
|
| 737 |
+
<axis xyz="0 -1 0"/>
|
| 738 |
+
<limit effort="35" lower="-1.1" upper="1.1" velocity="5.7"/>
|
| 739 |
+
<dynamics friction="10.0"/>
|
| 740 |
+
</joint>
|
| 741 |
+
<joint name="d435_head_joint" type="revolute">
|
| 742 |
+
<parent link="neck_1"/>
|
| 743 |
+
<origin rpy="0 0 0" xyz="0.06 0 0.1375"/>
|
| 744 |
+
<child link="d435_head_motor"/>
|
| 745 |
+
<axis xyz="0 -1 0"/>
|
| 746 |
+
<limit effort="35" lower="-1.1" upper="1.1" velocity="5.7"/>
|
| 747 |
+
<dynamics friction="10.0"/>
|
| 748 |
+
</joint>
|
| 749 |
+
<!-- camera body, with origin at bottom screw mount -->
|
| 750 |
+
<joint name="D435_head_camera_joint" type="fixed">
|
| 751 |
+
<origin rpy="0 0 0" xyz="0.03015 0 -0.0125"/>
|
| 752 |
+
<parent link="d435_head_motor"/>
|
| 753 |
+
<child link="D435_head_camera_bottom_screw_frame"/>
|
| 754 |
+
</joint>
|
| 755 |
+
<link name="D435_head_camera_bottom_screw_frame"/>
|
| 756 |
+
<joint name="D435_head_camera_link_joint" type="fixed">
|
| 757 |
+
<origin rpy="0 0 0" xyz="0 0.0175 0.0125"/>
|
| 758 |
+
<parent link="D435_head_camera_bottom_screw_frame"/>
|
| 759 |
+
<child link="D435_head_camera_link"/>
|
| 760 |
+
</joint>
|
| 761 |
+
<link name="D435_head_camera_link">
|
| 762 |
+
<visual>
|
| 763 |
+
<origin rpy="1.570796326795 0 1.570796326795" xyz="0.0149 -0.0175 0"/>
|
| 764 |
+
<geometry>
|
| 765 |
+
<box size="0.09 0.025 0.02505"/>
|
| 766 |
+
<!-- <mesh filename="${MESH_PATH}/realsense/d435.dae"/> -->
|
| 767 |
+
</geometry>
|
| 768 |
+
<material name="D435_head_camera_aluminum"/>
|
| 769 |
+
</visual>
|
| 770 |
+
<collision>
|
| 771 |
+
<origin rpy="0 0 0" xyz="0 -0.0175 0"/>
|
| 772 |
+
<geometry>
|
| 773 |
+
<box size="0.02505 0.09 0.025"/>
|
| 774 |
+
</geometry>
|
| 775 |
+
</collision>
|
| 776 |
+
<inertial>
|
| 777 |
+
<!-- The following are not reliable values, and should not be used for modeling -->
|
| 778 |
+
<mass value="0.564"/>
|
| 779 |
+
<origin xyz="0 0 0"/>
|
| 780 |
+
<inertia ixx="0.003881243" ixy="0.0" ixz="0.0" iyy="0.000498940" iyz="0.0" izz="0.003879257"/>
|
| 781 |
+
</inertial>
|
| 782 |
+
</link>
|
| 783 |
+
<!-- camera body, with origin at bottom screw mount -->
|
| 784 |
+
<joint name="D435i_camera_joint" type="fixed">
|
| 785 |
+
<origin rpy="0 0.54 0" xyz="0.272 0 0.084"/>
|
| 786 |
+
<parent link="pelvis"/>
|
| 787 |
+
<child link="D435i_camera_bottom_screw_frame"/>
|
| 788 |
+
</joint>
|
| 789 |
+
<link name="D435i_camera_bottom_screw_frame"/>
|
| 790 |
+
<joint name="D435i_camera_link_joint" type="fixed">
|
| 791 |
+
<origin rpy="0 0.0050 -0.008" xyz="0.053 0.0 -0.035"/>
|
| 792 |
+
<parent link="D435i_camera_bottom_screw_frame"/>
|
| 793 |
+
<child link="D435i_camera_link"/>
|
| 794 |
+
</joint>
|
| 795 |
+
<link name="D435i_camera_link">
|
| 796 |
+
<visual>
|
| 797 |
+
<origin rpy="1.570796326795 0 1.570796326795" xyz="0.053 -0.0 0"/>
|
| 798 |
+
<geometry>
|
| 799 |
+
<!-- <box size="${d435_cam_width} ${d435_cam_height} ${d435_cam_depth}"/> -->
|
| 800 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/realsense/d435.dae"/>
|
| 801 |
+
</geometry>
|
| 802 |
+
<material name="D435i_camera_aluminum"/>
|
| 803 |
+
</visual>
|
| 804 |
+
<collision>
|
| 805 |
+
<origin rpy="0 0 0" xyz="0 -0.0 0"/>
|
| 806 |
+
<geometry>
|
| 807 |
+
<box size="0.02505 0.09 0.025"/>
|
| 808 |
+
</geometry>
|
| 809 |
+
</collision>
|
| 810 |
+
<inertial>
|
| 811 |
+
<!-- The following are not reliable values, and should not be used for modeling -->
|
| 812 |
+
<mass value="0.564"/>
|
| 813 |
+
<origin xyz="0 0 0"/>
|
| 814 |
+
<inertia ixx="0.003881243" ixy="0.0" ixz="0.0" iyy="0.000498940" iyz="0.0" izz="0.003879257"/>
|
| 815 |
+
</inertial>
|
| 816 |
+
</link>
|
| 817 |
+
<!-- /macro centauro_wheel -->
|
| 818 |
+
<!-- /macro arms -->
|
| 819 |
+
<!-- /macro legs -->
|
| 820 |
+
<link name="hip1_1">
|
| 821 |
+
<inertial>
|
| 822 |
+
<origin xyz="0.0003595855 0.033338818000000006 -0.059190309"/>
|
| 823 |
+
<mass value="2.3349153"/>
|
| 824 |
+
<!-- org 2 -->
|
| 825 |
+
<inertia ixx="0.0068405374" ixy="1.8572633e-05" ixz="-4.8325972e-05" iyy="0.0026261815" iyz="0.0001564273" izz="0.0066933354"/>
|
| 826 |
+
</inertial>
|
| 827 |
+
<visual>
|
| 828 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 829 |
+
<geometry>
|
| 830 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-yaw.stl" scale="0.001 -0.001 0.001"/>
|
| 831 |
+
</geometry>
|
| 832 |
+
<material name="dark_grey"/>
|
| 833 |
+
</visual>
|
| 834 |
+
<collision>
|
| 835 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 836 |
+
<geometry>
|
| 837 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-yaw.stl" scale="0.001 -0.001 0.001"/>
|
| 838 |
+
</geometry>
|
| 839 |
+
</collision>
|
| 840 |
+
</link>
|
| 841 |
+
<link name="hip2_1">
|
| 842 |
+
<inertial>
|
| 843 |
+
<origin xyz="-4.6285952e-06 -0.2214019 0.03316685"/>
|
| 844 |
+
<mass value="3.4572118"/>
|
| 845 |
+
<!-- org 4.5 -->
|
| 846 |
+
<inertia ixx="0.050469853" ixy="-7.784938699999999e-06" ixz="-9.220580999999999e-06" iyy="0.008181596999999999" iyz="0.0059796848" izz="0.048213808999999996"/>
|
| 847 |
+
</inertial>
|
| 848 |
+
<visual>
|
| 849 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 850 |
+
<geometry>
|
| 851 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 852 |
+
</geometry>
|
| 853 |
+
</visual>
|
| 854 |
+
<collision>
|
| 855 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 856 |
+
<geometry>
|
| 857 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 858 |
+
</geometry>
|
| 859 |
+
</collision>
|
| 860 |
+
</link>
|
| 861 |
+
<link name="knee_1">
|
| 862 |
+
<inertial>
|
| 863 |
+
<origin xyz="0.00012063381 0.14620674 0.029740711000000003"/>
|
| 864 |
+
<mass value="2.1199315"/>
|
| 865 |
+
<!-- org 3.5, foot un modeled-->
|
| 866 |
+
<inertia ixx="0.018426402999999997" ixy="2.8226635999999997e-05" ixz="-2.9204348e-05" iyy="0.0047685615" iyz="-0.002640771" izz="0.017793722"/>
|
| 867 |
+
</inertial>
|
| 868 |
+
<visual>
|
| 869 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 870 |
+
<geometry>
|
| 871 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/knee.stl" scale="0.001 0.001 -0.001"/>
|
| 872 |
+
</geometry>
|
| 873 |
+
<material name="dark_grey"/>
|
| 874 |
+
</visual>
|
| 875 |
+
<collision>
|
| 876 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 877 |
+
<geometry>
|
| 878 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/knee.stl" scale="0.001 0.001 -0.001"/>
|
| 879 |
+
</geometry>
|
| 880 |
+
</collision>
|
| 881 |
+
</link>
|
| 882 |
+
<link name="ankle1_1">
|
| 883 |
+
<inertial>
|
| 884 |
+
<origin xyz="0.00012360094 -0.06274712 -0.0049068453"/>
|
| 885 |
+
<mass value="1.4023368"/>
|
| 886 |
+
<!-- org 3.5, foot un modeled-->
|
| 887 |
+
<inertia ixx="0.0049928829" ixy="5.762355699999999e-06" ixz="1.9606394e-05" iyy="0.0017621464" iyz="0.00045315091" izz="0.0048706328"/>
|
| 888 |
+
</inertial>
|
| 889 |
+
<visual>
|
| 890 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 891 |
+
<geometry>
|
| 892 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/ankle-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 893 |
+
</geometry>
|
| 894 |
+
</visual>
|
| 895 |
+
<collision>
|
| 896 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 897 |
+
<geometry>
|
| 898 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/ankle-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 899 |
+
</geometry>
|
| 900 |
+
</collision>
|
| 901 |
+
</link>
|
| 902 |
+
<link name="ankle2_1">
|
| 903 |
+
<inertial>
|
| 904 |
+
<origin xyz="0.00018512273 0.0017369405000000001 -0.091340683"/>
|
| 905 |
+
<mass value="2.440929"/>
|
| 906 |
+
<!-- org 3.5, foot un modeled-->
|
| 907 |
+
<inertia ixx="0.017711499" ixy="1.0713141e-05" ixz="-2.2094697e-05" iyy="0.014263485" iyz="0.00033426702" izz="0.0080747557"/>
|
| 908 |
+
</inertial>
|
| 909 |
+
<visual>
|
| 910 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 911 |
+
<geometry>
|
| 912 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_ankle-yaw_wheel23.stl" scale="0.001 -0.001 0.001"/>
|
| 913 |
+
</geometry>
|
| 914 |
+
<material name="dark_grey"/>
|
| 915 |
+
</visual>
|
| 916 |
+
<!-- <collision>
|
| 917 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
|
| 918 |
+
<geometry>
|
| 919 |
+
<mesh
|
| 920 |
+
filename="${MESH_PATH}/v2/collision/mesh_ankle-yaw_wheel23.stl"
|
| 921 |
+
scale="0.001 ${mirror*0.001} 0.001" />
|
| 922 |
+
</geometry>
|
| 923 |
+
</collision> -->
|
| 924 |
+
</link>
|
| 925 |
+
<joint name="j_wheel_1" type="continuous">
|
| 926 |
+
<parent link="ankle2_1"/>
|
| 927 |
+
<child link="wheel_1"/>
|
| 928 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 -0.0 -0.14435"/>
|
| 929 |
+
<axis xyz="0 0 -1"/>
|
| 930 |
+
<limit effort="35" velocity="20.0"/>
|
| 931 |
+
<!-- 23 Nm, 1
|
| 932 |
+
rad/s-->
|
| 933 |
+
</joint>
|
| 934 |
+
<link name="wheel_1">
|
| 935 |
+
<inertial>
|
| 936 |
+
<origin xyz="0.0 0.0 0.00015403767"/>
|
| 937 |
+
<mass value="1.8569388"/>
|
| 938 |
+
<inertia ixx="0.008637359099999999" ixy="0.0" ixz="-0.0" iyy="0.0086373644" iyz="-0.0" izz="0.016376551"/>
|
| 939 |
+
</inertial>
|
| 940 |
+
<visual>
|
| 941 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 942 |
+
<geometry>
|
| 943 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_wheel23.stl" scale="0.001 0.001 -0.001"/>
|
| 944 |
+
</geometry>
|
| 945 |
+
<material name="black"/>
|
| 946 |
+
</visual>
|
| 947 |
+
<collision>
|
| 948 |
+
<origin rpy="0 0 0" xyz="0 0 0"/>
|
| 949 |
+
<geometry>
|
| 950 |
+
<cylinder length="0.03" radius="0.124"/>
|
| 951 |
+
</geometry>
|
| 952 |
+
<!-- <geometry>
|
| 953 |
+
<mesh filename="${MESH_PATH}/v2/collision/wheel23_donut.stl"
|
| 954 |
+
scale="0.001 0.001 ${mirror*0.001}" />
|
| 955 |
+
</geometry> -->
|
| 956 |
+
<material name="black"/>
|
| 957 |
+
</collision>
|
| 958 |
+
</link>
|
| 959 |
+
<!-- *********** CONTACT FRAME ******************-->
|
| 960 |
+
<link name="contact_1"/>
|
| 961 |
+
<joint name="contact_joint_1" type="fixed">
|
| 962 |
+
<parent link="ankle2_1"/>
|
| 963 |
+
<child link="contact_1"/>
|
| 964 |
+
<origin rpy="0 0 0" xyz="0 0 -0.26835"/>
|
| 965 |
+
</joint>
|
| 966 |
+
<!-- ******************************** -->
|
| 967 |
+
<joint name="hip_yaw_1" type="revolute">
|
| 968 |
+
<parent link="pelvis"/>
|
| 969 |
+
<child link="hip1_1"/>
|
| 970 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.25 0.125 -0.056600000000000004"/>
|
| 971 |
+
<axis xyz="0 0 -1"/>
|
| 972 |
+
<limit effort="304" lower="-2.03" upper="2.51" velocity="8.8"/>
|
| 973 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 974 |
+
</joint>
|
| 975 |
+
<joint name="hip_pitch_1" type="revolute">
|
| 976 |
+
<parent link="hip1_1"/>
|
| 977 |
+
<child link="hip2_1"/>
|
| 978 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 0.1146 -0.0625"/>
|
| 979 |
+
<axis xyz="0 0 -1"/>
|
| 980 |
+
<limit effort="304" lower="-2.0226" upper="2.02748" velocity="8.8"/>
|
| 981 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 982 |
+
</joint>
|
| 983 |
+
<joint name="knee_pitch_1" type="revolute">
|
| 984 |
+
<parent link="hip2_1"/>
|
| 985 |
+
<child link="knee_1"/>
|
| 986 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 -0.3 0.1182"/>
|
| 987 |
+
<axis xyz="0 0 -1"/>
|
| 988 |
+
<limit effort="304" lower="-2.4056" upper="2.3994" velocity="8.8"/>
|
| 989 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 990 |
+
</joint>
|
| 991 |
+
<joint name="ankle_pitch_1" type="revolute">
|
| 992 |
+
<parent link="knee_1"/>
|
| 993 |
+
<child link="ankle1_1"/>
|
| 994 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 0.2 0.10015"/>
|
| 995 |
+
<axis xyz="0 0 -1"/>
|
| 996 |
+
<limit effort="147" lower="-2.4056" upper="2.3184" velocity="8.1"/>
|
| 997 |
+
<!-- 98 Nm, 1 rad/s-->
|
| 998 |
+
</joint>
|
| 999 |
+
<joint name="ankle_yaw_1" type="revolute">
|
| 1000 |
+
<parent link="ankle1_1"/>
|
| 1001 |
+
<child link="ankle2_1"/>
|
| 1002 |
+
<origin rpy="-1.57079632679 0.0 0.0" xyz="0.0 -0.139 -0.00085"/>
|
| 1003 |
+
<axis xyz="0 0 -1"/>
|
| 1004 |
+
<limit effort="35" lower="-2.5626" upper="2.5384" velocity="20.0"/>
|
| 1005 |
+
<!-- 23 Nm, 1 rad/s-->
|
| 1006 |
+
</joint>
|
| 1007 |
+
<link name="hip1_2">
|
| 1008 |
+
<inertial>
|
| 1009 |
+
<origin xyz="0.0003595855 -0.033338818000000006 -0.059190309"/>
|
| 1010 |
+
<mass value="2.3349153"/>
|
| 1011 |
+
<!-- org 2 -->
|
| 1012 |
+
<inertia ixx="0.0068405374" ixy="-1.8572633e-05" ixz="-4.8325972e-05" iyy="0.0026261815" iyz="-0.0001564273" izz="0.0066933354"/>
|
| 1013 |
+
</inertial>
|
| 1014 |
+
<visual>
|
| 1015 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1016 |
+
<geometry>
|
| 1017 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-yaw.stl" scale="0.001 0.001 0.001"/>
|
| 1018 |
+
</geometry>
|
| 1019 |
+
<material name="dark_grey"/>
|
| 1020 |
+
</visual>
|
| 1021 |
+
<collision>
|
| 1022 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1023 |
+
<geometry>
|
| 1024 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-yaw.stl" scale="0.001 0.001 0.001"/>
|
| 1025 |
+
</geometry>
|
| 1026 |
+
</collision>
|
| 1027 |
+
</link>
|
| 1028 |
+
<link name="hip2_2">
|
| 1029 |
+
<inertial>
|
| 1030 |
+
<origin xyz="-4.6285952e-06 -0.2214019 -0.03316685"/>
|
| 1031 |
+
<mass value="3.4572118"/>
|
| 1032 |
+
<!-- org 4.5 -->
|
| 1033 |
+
<inertia ixx="0.050469853" ixy="-7.784938699999999e-06" ixz="9.220580999999999e-06" iyy="0.008181596999999999" iyz="-0.0059796848" izz="0.048213808999999996"/>
|
| 1034 |
+
</inertial>
|
| 1035 |
+
<visual>
|
| 1036 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1037 |
+
<geometry>
|
| 1038 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1039 |
+
</geometry>
|
| 1040 |
+
</visual>
|
| 1041 |
+
<collision>
|
| 1042 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1043 |
+
<geometry>
|
| 1044 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1045 |
+
</geometry>
|
| 1046 |
+
</collision>
|
| 1047 |
+
</link>
|
| 1048 |
+
<link name="knee_2">
|
| 1049 |
+
<inertial>
|
| 1050 |
+
<origin xyz="0.00012063381 0.14620674 -0.029740711000000003"/>
|
| 1051 |
+
<mass value="2.1199315"/>
|
| 1052 |
+
<!-- org 3.5, foot un modeled-->
|
| 1053 |
+
<inertia ixx="0.018426402999999997" ixy="2.8226635999999997e-05" ixz="2.9204348e-05" iyy="0.0047685615" iyz="0.002640771" izz="0.017793722"/>
|
| 1054 |
+
</inertial>
|
| 1055 |
+
<visual>
|
| 1056 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1057 |
+
<geometry>
|
| 1058 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/knee.stl" scale="0.001 0.001 0.001"/>
|
| 1059 |
+
</geometry>
|
| 1060 |
+
<material name="dark_grey"/>
|
| 1061 |
+
</visual>
|
| 1062 |
+
<collision>
|
| 1063 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1064 |
+
<geometry>
|
| 1065 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/knee.stl" scale="0.001 0.001 0.001"/>
|
| 1066 |
+
</geometry>
|
| 1067 |
+
</collision>
|
| 1068 |
+
</link>
|
| 1069 |
+
<link name="ankle1_2">
|
| 1070 |
+
<inertial>
|
| 1071 |
+
<origin xyz="0.00012360094 -0.06274712 0.0049068453"/>
|
| 1072 |
+
<mass value="1.4023368"/>
|
| 1073 |
+
<!-- org 3.5, foot un modeled-->
|
| 1074 |
+
<inertia ixx="0.0049928829" ixy="5.762355699999999e-06" ixz="-1.9606394e-05" iyy="0.0017621464" iyz="-0.00045315091" izz="0.0048706328"/>
|
| 1075 |
+
</inertial>
|
| 1076 |
+
<visual>
|
| 1077 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1078 |
+
<geometry>
|
| 1079 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/ankle-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1080 |
+
</geometry>
|
| 1081 |
+
</visual>
|
| 1082 |
+
<collision>
|
| 1083 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1084 |
+
<geometry>
|
| 1085 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/ankle-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1086 |
+
</geometry>
|
| 1087 |
+
</collision>
|
| 1088 |
+
</link>
|
| 1089 |
+
<link name="ankle2_2">
|
| 1090 |
+
<inertial>
|
| 1091 |
+
<origin xyz="0.00018512273 -0.0017369405000000001 -0.091340683"/>
|
| 1092 |
+
<mass value="2.440929"/>
|
| 1093 |
+
<!-- org 3.5, foot un modeled-->
|
| 1094 |
+
<inertia ixx="0.017711499" ixy="-1.0713141e-05" ixz="-2.2094697e-05" iyy="0.014263485" iyz="-0.00033426702" izz="0.0080747557"/>
|
| 1095 |
+
</inertial>
|
| 1096 |
+
<visual>
|
| 1097 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1098 |
+
<geometry>
|
| 1099 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_ankle-yaw_wheel23.stl" scale="0.001 0.001 0.001"/>
|
| 1100 |
+
</geometry>
|
| 1101 |
+
<material name="dark_grey"/>
|
| 1102 |
+
</visual>
|
| 1103 |
+
<!-- <collision>
|
| 1104 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
|
| 1105 |
+
<geometry>
|
| 1106 |
+
<mesh
|
| 1107 |
+
filename="${MESH_PATH}/v2/collision/mesh_ankle-yaw_wheel23.stl"
|
| 1108 |
+
scale="0.001 ${mirror*0.001} 0.001" />
|
| 1109 |
+
</geometry>
|
| 1110 |
+
</collision> -->
|
| 1111 |
+
</link>
|
| 1112 |
+
<joint name="j_wheel_2" type="continuous">
|
| 1113 |
+
<parent link="ankle2_2"/>
|
| 1114 |
+
<child link="wheel_2"/>
|
| 1115 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 0.0 -0.14435"/>
|
| 1116 |
+
<axis xyz="0 0 1"/>
|
| 1117 |
+
<limit effort="35" velocity="20.0"/>
|
| 1118 |
+
<!-- 23 Nm, 1
|
| 1119 |
+
rad/s-->
|
| 1120 |
+
</joint>
|
| 1121 |
+
<link name="wheel_2">
|
| 1122 |
+
<inertial>
|
| 1123 |
+
<origin xyz="0.0 0.0 -0.00015403767"/>
|
| 1124 |
+
<mass value="1.8569388"/>
|
| 1125 |
+
<inertia ixx="0.008637359099999999" ixy="0.0" ixz="0.0" iyy="0.0086373644" iyz="0.0" izz="0.016376551"/>
|
| 1126 |
+
</inertial>
|
| 1127 |
+
<visual>
|
| 1128 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1129 |
+
<geometry>
|
| 1130 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_wheel23.stl" scale="0.001 0.001 0.001"/>
|
| 1131 |
+
</geometry>
|
| 1132 |
+
<material name="black"/>
|
| 1133 |
+
</visual>
|
| 1134 |
+
<collision>
|
| 1135 |
+
<origin rpy="0 0 0" xyz="0 0 0"/>
|
| 1136 |
+
<geometry>
|
| 1137 |
+
<cylinder length="0.03" radius="0.124"/>
|
| 1138 |
+
</geometry>
|
| 1139 |
+
<!-- <geometry>
|
| 1140 |
+
<mesh filename="${MESH_PATH}/v2/collision/wheel23_donut.stl"
|
| 1141 |
+
scale="0.001 0.001 ${mirror*0.001}" />
|
| 1142 |
+
</geometry> -->
|
| 1143 |
+
<material name="black"/>
|
| 1144 |
+
</collision>
|
| 1145 |
+
</link>
|
| 1146 |
+
<!-- *********** CONTACT FRAME ******************-->
|
| 1147 |
+
<link name="contact_2"/>
|
| 1148 |
+
<joint name="contact_joint_2" type="fixed">
|
| 1149 |
+
<parent link="ankle2_2"/>
|
| 1150 |
+
<child link="contact_2"/>
|
| 1151 |
+
<origin rpy="0 0 0" xyz="0 0 -0.26835"/>
|
| 1152 |
+
</joint>
|
| 1153 |
+
<!-- ******************************** -->
|
| 1154 |
+
<joint name="hip_yaw_2" type="revolute">
|
| 1155 |
+
<parent link="pelvis"/>
|
| 1156 |
+
<child link="hip1_2"/>
|
| 1157 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.25 -0.125 -0.056600000000000004"/>
|
| 1158 |
+
<axis xyz="0 0 -1"/>
|
| 1159 |
+
<limit effort="304" lower="-2.51" upper="2.03" velocity="8.8"/>
|
| 1160 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1161 |
+
</joint>
|
| 1162 |
+
<joint name="hip_pitch_2" type="revolute">
|
| 1163 |
+
<parent link="hip1_2"/>
|
| 1164 |
+
<child link="hip2_2"/>
|
| 1165 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 -0.1146 -0.0625"/>
|
| 1166 |
+
<axis xyz="0 0 1"/>
|
| 1167 |
+
<limit effort="304" lower="-2.0156" upper="2.0354" velocity="8.8"/>
|
| 1168 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1169 |
+
</joint>
|
| 1170 |
+
<joint name="knee_pitch_2" type="revolute">
|
| 1171 |
+
<parent link="hip2_2"/>
|
| 1172 |
+
<child link="knee_2"/>
|
| 1173 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 -0.3 -0.1182"/>
|
| 1174 |
+
<axis xyz="0 0 1"/>
|
| 1175 |
+
<limit effort="304" lower="-2.4006" upper="2.4034" velocity="8.8"/>
|
| 1176 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1177 |
+
</joint>
|
| 1178 |
+
<joint name="ankle_pitch_2" type="revolute">
|
| 1179 |
+
<parent link="knee_2"/>
|
| 1180 |
+
<child link="ankle1_2"/>
|
| 1181 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 0.2 -0.10015"/>
|
| 1182 |
+
<axis xyz="0 0 1"/>
|
| 1183 |
+
<limit effort="147" lower="-2.3266" upper="2.3914" velocity="8.1"/>
|
| 1184 |
+
<!-- 98 Nm, 1 rad/s-->
|
| 1185 |
+
</joint>
|
| 1186 |
+
<joint name="ankle_yaw_2" type="revolute">
|
| 1187 |
+
<parent link="ankle1_2"/>
|
| 1188 |
+
<child link="ankle2_2"/>
|
| 1189 |
+
<origin rpy="-1.57079632679 0.0 0.0" xyz="0.0 -0.139 0.00085"/>
|
| 1190 |
+
<axis xyz="0 0 -1"/>
|
| 1191 |
+
<limit effort="35" lower="-2.5546" upper="2.5484" velocity="20.0"/>
|
| 1192 |
+
<!-- 23 Nm, 1 rad/s-->
|
| 1193 |
+
</joint>
|
| 1194 |
+
<link name="hip1_3">
|
| 1195 |
+
<inertial>
|
| 1196 |
+
<origin xyz="0.0003595855 0.033338818000000006 -0.059190309"/>
|
| 1197 |
+
<mass value="2.3349153"/>
|
| 1198 |
+
<!-- org 2 -->
|
| 1199 |
+
<inertia ixx="0.0068405374" ixy="1.8572633e-05" ixz="-4.8325972e-05" iyy="0.0026261815" iyz="0.0001564273" izz="0.0066933354"/>
|
| 1200 |
+
</inertial>
|
| 1201 |
+
<visual>
|
| 1202 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1203 |
+
<geometry>
|
| 1204 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-yaw.stl" scale="0.001 -0.001 0.001"/>
|
| 1205 |
+
</geometry>
|
| 1206 |
+
<material name="dark_grey"/>
|
| 1207 |
+
</visual>
|
| 1208 |
+
<collision>
|
| 1209 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1210 |
+
<geometry>
|
| 1211 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-yaw.stl" scale="0.001 -0.001 0.001"/>
|
| 1212 |
+
</geometry>
|
| 1213 |
+
</collision>
|
| 1214 |
+
</link>
|
| 1215 |
+
<link name="hip2_3">
|
| 1216 |
+
<inertial>
|
| 1217 |
+
<origin xyz="-4.6285952e-06 -0.2214019 0.03316685"/>
|
| 1218 |
+
<mass value="3.4572118"/>
|
| 1219 |
+
<!-- org 4.5 -->
|
| 1220 |
+
<inertia ixx="0.050469853" ixy="-7.784938699999999e-06" ixz="-9.220580999999999e-06" iyy="0.008181596999999999" iyz="0.0059796848" izz="0.048213808999999996"/>
|
| 1221 |
+
</inertial>
|
| 1222 |
+
<visual>
|
| 1223 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1224 |
+
<geometry>
|
| 1225 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 1226 |
+
</geometry>
|
| 1227 |
+
</visual>
|
| 1228 |
+
<collision>
|
| 1229 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1230 |
+
<geometry>
|
| 1231 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 1232 |
+
</geometry>
|
| 1233 |
+
</collision>
|
| 1234 |
+
</link>
|
| 1235 |
+
<link name="knee_3">
|
| 1236 |
+
<inertial>
|
| 1237 |
+
<origin xyz="0.00012063381 0.14620674 0.029740711000000003"/>
|
| 1238 |
+
<mass value="2.1199315"/>
|
| 1239 |
+
<!-- org 3.5, foot un modeled-->
|
| 1240 |
+
<inertia ixx="0.018426402999999997" ixy="2.8226635999999997e-05" ixz="-2.9204348e-05" iyy="0.0047685615" iyz="-0.002640771" izz="0.017793722"/>
|
| 1241 |
+
</inertial>
|
| 1242 |
+
<visual>
|
| 1243 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1244 |
+
<geometry>
|
| 1245 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/knee.stl" scale="0.001 0.001 -0.001"/>
|
| 1246 |
+
</geometry>
|
| 1247 |
+
<material name="dark_grey"/>
|
| 1248 |
+
</visual>
|
| 1249 |
+
<collision>
|
| 1250 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1251 |
+
<geometry>
|
| 1252 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/knee.stl" scale="0.001 0.001 -0.001"/>
|
| 1253 |
+
</geometry>
|
| 1254 |
+
</collision>
|
| 1255 |
+
</link>
|
| 1256 |
+
<link name="ankle1_3">
|
| 1257 |
+
<inertial>
|
| 1258 |
+
<origin xyz="0.00012360094 -0.06274712 -0.0049068453"/>
|
| 1259 |
+
<mass value="1.4023368"/>
|
| 1260 |
+
<!-- org 3.5, foot un modeled-->
|
| 1261 |
+
<inertia ixx="0.0049928829" ixy="5.762355699999999e-06" ixz="1.9606394e-05" iyy="0.0017621464" iyz="0.00045315091" izz="0.0048706328"/>
|
| 1262 |
+
</inertial>
|
| 1263 |
+
<visual>
|
| 1264 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1265 |
+
<geometry>
|
| 1266 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/ankle-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 1267 |
+
</geometry>
|
| 1268 |
+
</visual>
|
| 1269 |
+
<collision>
|
| 1270 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1271 |
+
<geometry>
|
| 1272 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/ankle-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 1273 |
+
</geometry>
|
| 1274 |
+
</collision>
|
| 1275 |
+
</link>
|
| 1276 |
+
<link name="ankle2_3">
|
| 1277 |
+
<inertial>
|
| 1278 |
+
<origin xyz="0.00018512273 0.0017369405000000001 -0.091340683"/>
|
| 1279 |
+
<mass value="2.440929"/>
|
| 1280 |
+
<!-- org 3.5, foot un modeled-->
|
| 1281 |
+
<inertia ixx="0.017711499" ixy="1.0713141e-05" ixz="-2.2094697e-05" iyy="0.014263485" iyz="0.00033426702" izz="0.0080747557"/>
|
| 1282 |
+
</inertial>
|
| 1283 |
+
<visual>
|
| 1284 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1285 |
+
<geometry>
|
| 1286 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_ankle-yaw_wheel23.stl" scale="0.001 -0.001 0.001"/>
|
| 1287 |
+
</geometry>
|
| 1288 |
+
<material name="dark_grey"/>
|
| 1289 |
+
</visual>
|
| 1290 |
+
<!-- <collision>
|
| 1291 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
|
| 1292 |
+
<geometry>
|
| 1293 |
+
<mesh
|
| 1294 |
+
filename="${MESH_PATH}/v2/collision/mesh_ankle-yaw_wheel23.stl"
|
| 1295 |
+
scale="0.001 ${mirror*0.001} 0.001" />
|
| 1296 |
+
</geometry>
|
| 1297 |
+
</collision> -->
|
| 1298 |
+
</link>
|
| 1299 |
+
<joint name="j_wheel_3" type="continuous">
|
| 1300 |
+
<parent link="ankle2_3"/>
|
| 1301 |
+
<child link="wheel_3"/>
|
| 1302 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 -0.0 -0.14435"/>
|
| 1303 |
+
<axis xyz="0 0 -1"/>
|
| 1304 |
+
<limit effort="35" velocity="20.0"/>
|
| 1305 |
+
<!-- 23 Nm, 1
|
| 1306 |
+
rad/s-->
|
| 1307 |
+
</joint>
|
| 1308 |
+
<link name="wheel_3">
|
| 1309 |
+
<inertial>
|
| 1310 |
+
<origin xyz="0.0 0.0 0.00015403767"/>
|
| 1311 |
+
<mass value="1.8569388"/>
|
| 1312 |
+
<inertia ixx="0.008637359099999999" ixy="0.0" ixz="-0.0" iyy="0.0086373644" iyz="-0.0" izz="0.016376551"/>
|
| 1313 |
+
</inertial>
|
| 1314 |
+
<visual>
|
| 1315 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1316 |
+
<geometry>
|
| 1317 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_wheel23.stl" scale="0.001 0.001 -0.001"/>
|
| 1318 |
+
</geometry>
|
| 1319 |
+
<material name="black"/>
|
| 1320 |
+
</visual>
|
| 1321 |
+
<collision>
|
| 1322 |
+
<origin rpy="0 0 0" xyz="0 0 0"/>
|
| 1323 |
+
<geometry>
|
| 1324 |
+
<cylinder length="0.03" radius="0.124"/>
|
| 1325 |
+
</geometry>
|
| 1326 |
+
<!-- <geometry>
|
| 1327 |
+
<mesh filename="${MESH_PATH}/v2/collision/wheel23_donut.stl"
|
| 1328 |
+
scale="0.001 0.001 ${mirror*0.001}" />
|
| 1329 |
+
</geometry> -->
|
| 1330 |
+
<material name="black"/>
|
| 1331 |
+
</collision>
|
| 1332 |
+
</link>
|
| 1333 |
+
<!-- *********** CONTACT FRAME ******************-->
|
| 1334 |
+
<link name="contact_3"/>
|
| 1335 |
+
<joint name="contact_joint_3" type="fixed">
|
| 1336 |
+
<parent link="ankle2_3"/>
|
| 1337 |
+
<child link="contact_3"/>
|
| 1338 |
+
<origin rpy="0 0 0" xyz="0 0 -0.26835"/>
|
| 1339 |
+
</joint>
|
| 1340 |
+
<!-- ******************************** -->
|
| 1341 |
+
<joint name="hip_yaw_3" type="revolute">
|
| 1342 |
+
<parent link="pelvis"/>
|
| 1343 |
+
<child link="hip1_3"/>
|
| 1344 |
+
<origin rpy="0.0 0.0 0.0" xyz="-0.25 0.125 -0.056600000000000004"/>
|
| 1345 |
+
<axis xyz="0 0 -1"/>
|
| 1346 |
+
<limit effort="304" lower="-2.51" upper="2.03" velocity="8.8"/>
|
| 1347 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1348 |
+
</joint>
|
| 1349 |
+
<joint name="hip_pitch_3" type="revolute">
|
| 1350 |
+
<parent link="hip1_3"/>
|
| 1351 |
+
<child link="hip2_3"/>
|
| 1352 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 0.1146 -0.0625"/>
|
| 1353 |
+
<axis xyz="0 0 -1"/>
|
| 1354 |
+
<limit effort="304" lower="-2.0126" upper="2.0384" velocity="8.8"/>
|
| 1355 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1356 |
+
</joint>
|
| 1357 |
+
<joint name="knee_pitch_3" type="revolute">
|
| 1358 |
+
<parent link="hip2_3"/>
|
| 1359 |
+
<child link="knee_3"/>
|
| 1360 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 -0.3 0.1182"/>
|
| 1361 |
+
<axis xyz="0 0 -1"/>
|
| 1362 |
+
<limit effort="304" lower="-2.4056" upper="2.4064" velocity="8.8"/>
|
| 1363 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1364 |
+
</joint>
|
| 1365 |
+
<joint name="ankle_pitch_3" type="revolute">
|
| 1366 |
+
<parent link="knee_3"/>
|
| 1367 |
+
<child link="ankle1_3"/>
|
| 1368 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 0.2 0.10015"/>
|
| 1369 |
+
<axis xyz="0 0 -1"/>
|
| 1370 |
+
<limit effort="147" lower="-2.4696" upper="2.4464" velocity="8.1"/>
|
| 1371 |
+
<!-- 98 Nm, 1 rad/s-->
|
| 1372 |
+
</joint>
|
| 1373 |
+
<joint name="ankle_yaw_3" type="revolute">
|
| 1374 |
+
<parent link="ankle1_3"/>
|
| 1375 |
+
<child link="ankle2_3"/>
|
| 1376 |
+
<origin rpy="-1.57079632679 0.0 0.0" xyz="0.0 -0.139 -0.00085"/>
|
| 1377 |
+
<axis xyz="0 0 -1"/>
|
| 1378 |
+
<limit effort="35" lower="-2.5606" upper="2.5454" velocity="20.0"/>
|
| 1379 |
+
<!-- 23 Nm, 1 rad/s-->
|
| 1380 |
+
</joint>
|
| 1381 |
+
<link name="hip1_4">
|
| 1382 |
+
<inertial>
|
| 1383 |
+
<origin xyz="0.0003595855 -0.033338818000000006 -0.059190309"/>
|
| 1384 |
+
<mass value="2.3349153"/>
|
| 1385 |
+
<!-- org 2 -->
|
| 1386 |
+
<inertia ixx="0.0068405374" ixy="-1.8572633e-05" ixz="-4.8325972e-05" iyy="0.0026261815" iyz="-0.0001564273" izz="0.0066933354"/>
|
| 1387 |
+
</inertial>
|
| 1388 |
+
<visual>
|
| 1389 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1390 |
+
<geometry>
|
| 1391 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-yaw.stl" scale="0.001 0.001 0.001"/>
|
| 1392 |
+
</geometry>
|
| 1393 |
+
<material name="dark_grey"/>
|
| 1394 |
+
</visual>
|
| 1395 |
+
<collision>
|
| 1396 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1397 |
+
<geometry>
|
| 1398 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-yaw.stl" scale="0.001 0.001 0.001"/>
|
| 1399 |
+
</geometry>
|
| 1400 |
+
</collision>
|
| 1401 |
+
</link>
|
| 1402 |
+
<link name="hip2_4">
|
| 1403 |
+
<inertial>
|
| 1404 |
+
<origin xyz="-4.6285952e-06 -0.2214019 -0.03316685"/>
|
| 1405 |
+
<mass value="3.4572118"/>
|
| 1406 |
+
<!-- org 4.5 -->
|
| 1407 |
+
<inertia ixx="0.050469853" ixy="-7.784938699999999e-06" ixz="9.220580999999999e-06" iyy="0.008181596999999999" iyz="-0.0059796848" izz="0.048213808999999996"/>
|
| 1408 |
+
</inertial>
|
| 1409 |
+
<visual>
|
| 1410 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1411 |
+
<geometry>
|
| 1412 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1413 |
+
</geometry>
|
| 1414 |
+
</visual>
|
| 1415 |
+
<collision>
|
| 1416 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1417 |
+
<geometry>
|
| 1418 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1419 |
+
</geometry>
|
| 1420 |
+
</collision>
|
| 1421 |
+
</link>
|
| 1422 |
+
<link name="knee_4">
|
| 1423 |
+
<inertial>
|
| 1424 |
+
<origin xyz="0.00012063381 0.14620674 -0.029740711000000003"/>
|
| 1425 |
+
<mass value="2.1199315"/>
|
| 1426 |
+
<!-- org 3.5, foot un modeled-->
|
| 1427 |
+
<inertia ixx="0.018426402999999997" ixy="2.8226635999999997e-05" ixz="2.9204348e-05" iyy="0.0047685615" iyz="0.002640771" izz="0.017793722"/>
|
| 1428 |
+
</inertial>
|
| 1429 |
+
<visual>
|
| 1430 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1431 |
+
<geometry>
|
| 1432 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/knee.stl" scale="0.001 0.001 0.001"/>
|
| 1433 |
+
</geometry>
|
| 1434 |
+
<material name="dark_grey"/>
|
| 1435 |
+
</visual>
|
| 1436 |
+
<collision>
|
| 1437 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1438 |
+
<geometry>
|
| 1439 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/knee.stl" scale="0.001 0.001 0.001"/>
|
| 1440 |
+
</geometry>
|
| 1441 |
+
</collision>
|
| 1442 |
+
</link>
|
| 1443 |
+
<link name="ankle1_4">
|
| 1444 |
+
<inertial>
|
| 1445 |
+
<origin xyz="0.00012360094 -0.06274712 0.0049068453"/>
|
| 1446 |
+
<mass value="1.4023368"/>
|
| 1447 |
+
<!-- org 3.5, foot un modeled-->
|
| 1448 |
+
<inertia ixx="0.0049928829" ixy="5.762355699999999e-06" ixz="-1.9606394e-05" iyy="0.0017621464" iyz="-0.00045315091" izz="0.0048706328"/>
|
| 1449 |
+
</inertial>
|
| 1450 |
+
<visual>
|
| 1451 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1452 |
+
<geometry>
|
| 1453 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/ankle-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1454 |
+
</geometry>
|
| 1455 |
+
</visual>
|
| 1456 |
+
<collision>
|
| 1457 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1458 |
+
<geometry>
|
| 1459 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/ankle-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1460 |
+
</geometry>
|
| 1461 |
+
</collision>
|
| 1462 |
+
</link>
|
| 1463 |
+
<link name="ankle2_4">
|
| 1464 |
+
<inertial>
|
| 1465 |
+
<origin xyz="0.00018512273 -0.0017369405000000001 -0.091340683"/>
|
| 1466 |
+
<mass value="2.440929"/>
|
| 1467 |
+
<!-- org 3.5, foot un modeled-->
|
| 1468 |
+
<inertia ixx="0.017711499" ixy="-1.0713141e-05" ixz="-2.2094697e-05" iyy="0.014263485" iyz="-0.00033426702" izz="0.0080747557"/>
|
| 1469 |
+
</inertial>
|
| 1470 |
+
<visual>
|
| 1471 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1472 |
+
<geometry>
|
| 1473 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_ankle-yaw_wheel23.stl" scale="0.001 0.001 0.001"/>
|
| 1474 |
+
</geometry>
|
| 1475 |
+
<material name="dark_grey"/>
|
| 1476 |
+
</visual>
|
| 1477 |
+
<!-- <collision>
|
| 1478 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
|
| 1479 |
+
<geometry>
|
| 1480 |
+
<mesh
|
| 1481 |
+
filename="${MESH_PATH}/v2/collision/mesh_ankle-yaw_wheel23.stl"
|
| 1482 |
+
scale="0.001 ${mirror*0.001} 0.001" />
|
| 1483 |
+
</geometry>
|
| 1484 |
+
</collision> -->
|
| 1485 |
+
</link>
|
| 1486 |
+
<joint name="j_wheel_4" type="continuous">
|
| 1487 |
+
<parent link="ankle2_4"/>
|
| 1488 |
+
<child link="wheel_4"/>
|
| 1489 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 0.0 -0.14435"/>
|
| 1490 |
+
<axis xyz="0 0 1"/>
|
| 1491 |
+
<limit effort="35" velocity="20.0"/>
|
| 1492 |
+
<!-- 23 Nm, 1
|
| 1493 |
+
rad/s-->
|
| 1494 |
+
</joint>
|
| 1495 |
+
<link name="wheel_4">
|
| 1496 |
+
<inertial>
|
| 1497 |
+
<origin xyz="0.0 0.0 -0.00015403767"/>
|
| 1498 |
+
<mass value="1.8569388"/>
|
| 1499 |
+
<inertia ixx="0.008637359099999999" ixy="0.0" ixz="0.0" iyy="0.0086373644" iyz="0.0" izz="0.016376551"/>
|
| 1500 |
+
</inertial>
|
| 1501 |
+
<visual>
|
| 1502 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1503 |
+
<geometry>
|
| 1504 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_wheel23.stl" scale="0.001 0.001 0.001"/>
|
| 1505 |
+
</geometry>
|
| 1506 |
+
<material name="black"/>
|
| 1507 |
+
</visual>
|
| 1508 |
+
<collision>
|
| 1509 |
+
<origin rpy="0 0 0" xyz="0 0 0"/>
|
| 1510 |
+
<geometry>
|
| 1511 |
+
<cylinder length="0.03" radius="0.124"/>
|
| 1512 |
+
</geometry>
|
| 1513 |
+
<!-- <geometry>
|
| 1514 |
+
<mesh filename="${MESH_PATH}/v2/collision/wheel23_donut.stl"
|
| 1515 |
+
scale="0.001 0.001 ${mirror*0.001}" />
|
| 1516 |
+
</geometry> -->
|
| 1517 |
+
<material name="black"/>
|
| 1518 |
+
</collision>
|
| 1519 |
+
</link>
|
| 1520 |
+
<!-- *********** CONTACT FRAME ******************-->
|
| 1521 |
+
<link name="contact_4"/>
|
| 1522 |
+
<joint name="contact_joint_4" type="fixed">
|
| 1523 |
+
<parent link="ankle2_4"/>
|
| 1524 |
+
<child link="contact_4"/>
|
| 1525 |
+
<origin rpy="0 0 0" xyz="0 0 -0.26835"/>
|
| 1526 |
+
</joint>
|
| 1527 |
+
<!-- ******************************** -->
|
| 1528 |
+
<joint name="hip_yaw_4" type="revolute">
|
| 1529 |
+
<parent link="pelvis"/>
|
| 1530 |
+
<child link="hip1_4"/>
|
| 1531 |
+
<origin rpy="0.0 0.0 0.0" xyz="-0.25 -0.125 -0.056600000000000004"/>
|
| 1532 |
+
<axis xyz="0 0 -1"/>
|
| 1533 |
+
<limit effort="304" lower="-2.03" upper="2.51" velocity="8.8"/>
|
| 1534 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1535 |
+
</joint>
|
| 1536 |
+
<joint name="hip_pitch_4" type="revolute">
|
| 1537 |
+
<parent link="hip1_4"/>
|
| 1538 |
+
<child link="hip2_4"/>
|
| 1539 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 -0.1146 -0.0625"/>
|
| 1540 |
+
<axis xyz="0 0 1"/>
|
| 1541 |
+
<limit effort="304" lower="-2.0326" upper="2.0524" velocity="8.8"/>
|
| 1542 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1543 |
+
</joint>
|
| 1544 |
+
<joint name="knee_pitch_4" type="revolute">
|
| 1545 |
+
<parent link="hip2_4"/>
|
| 1546 |
+
<child link="knee_4"/>
|
| 1547 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 -0.3 -0.1182"/>
|
| 1548 |
+
<axis xyz="0 0 1"/>
|
| 1549 |
+
<limit effort="304" lower="-2.4176" upper="2.3884" velocity="8.8"/>
|
| 1550 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1551 |
+
</joint>
|
| 1552 |
+
<joint name="ankle_pitch_4" type="revolute">
|
| 1553 |
+
<parent link="knee_4"/>
|
| 1554 |
+
<child link="ankle1_4"/>
|
| 1555 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 0.2 -0.10015"/>
|
| 1556 |
+
<axis xyz="0 0 1"/>
|
| 1557 |
+
<limit effort="147" lower="-2.3426" upper="2.3934" velocity="8.1"/>
|
| 1558 |
+
<!-- 98 Nm, 1 rad/s-->
|
| 1559 |
+
</joint>
|
| 1560 |
+
<joint name="ankle_yaw_4" type="revolute">
|
| 1561 |
+
<parent link="ankle1_4"/>
|
| 1562 |
+
<child link="ankle2_4"/>
|
| 1563 |
+
<origin rpy="-1.57079632679 0.0 0.0" xyz="0.0 -0.139 0.00085"/>
|
| 1564 |
+
<axis xyz="0 0 -1"/>
|
| 1565 |
+
<limit effort="35" lower="-2.6046" upper="2.5514" velocity="20.0"/>
|
| 1566 |
+
<!-- 23 Nm, 1 rad/s-->
|
| 1567 |
+
</joint>
|
| 1568 |
+
<!-- ************ Control frames ************ -->
|
| 1569 |
+
</robot>
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/centauro_rhc.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from aug_mpc.controllers.rhc.horizon_based.hybrid_quad_rhc import HybridQuadRhc
|
| 2 |
+
|
| 3 |
+
import numpy as np
|
| 4 |
+
|
| 5 |
+
from typing import Dict
|
| 6 |
+
|
| 7 |
+
from centaurohybridmpc.utils.sysutils import PathsGetter
|
| 8 |
+
|
| 9 |
+
class CentauroRhc(HybridQuadRhc):
|
| 10 |
+
|
| 11 |
+
def __init__(self,
|
| 12 |
+
srdf_path: str,
|
| 13 |
+
urdf_path: str,
|
| 14 |
+
robot_name: str, # used for shared memory namespaces
|
| 15 |
+
codegen_dir: str,
|
| 16 |
+
n_nodes: float = 31,
|
| 17 |
+
dt: float = 0.03,
|
| 18 |
+
injection_node: int = 10,
|
| 19 |
+
max_solver_iter = 1, # defaults to rt-iteration
|
| 20 |
+
open_loop: bool = True,
|
| 21 |
+
close_loop_all: bool = False,
|
| 22 |
+
dtype = np.float32,
|
| 23 |
+
verbose = False,
|
| 24 |
+
debug = False,
|
| 25 |
+
refs_in_hor_frame = True,
|
| 26 |
+
timeout_ms: int = 60000,
|
| 27 |
+
custom_opts: Dict = {}
|
| 28 |
+
):
|
| 29 |
+
|
| 30 |
+
paths = PathsGetter()
|
| 31 |
+
self._files_suffix=""
|
| 32 |
+
if open_loop:
|
| 33 |
+
self._files_suffix="_open"
|
| 34 |
+
|
| 35 |
+
self._add_upper_body=False
|
| 36 |
+
if ("add_upper_body" in custom_opts) and \
|
| 37 |
+
(custom_opts["add_upper_body"]):
|
| 38 |
+
self._add_upper_body=True
|
| 39 |
+
self._files_suffix+="_ub"
|
| 40 |
+
|
| 41 |
+
config_path=paths.RHCCONFIGPATH_NO_WHEELS+self._files_suffix+".yaml"
|
| 42 |
+
|
| 43 |
+
super().__init__(srdf_path=srdf_path,
|
| 44 |
+
urdf_path=urdf_path,
|
| 45 |
+
config_path=config_path,
|
| 46 |
+
robot_name=robot_name, # used for shared memory namespaces
|
| 47 |
+
codegen_dir=codegen_dir,
|
| 48 |
+
n_nodes=n_nodes,
|
| 49 |
+
dt=dt,
|
| 50 |
+
injection_node=injection_node,
|
| 51 |
+
max_solver_iter=max_solver_iter, # defaults to rt-iteration
|
| 52 |
+
open_loop=open_loop,
|
| 53 |
+
close_loop_all=close_loop_all,
|
| 54 |
+
dtype=dtype,
|
| 55 |
+
verbose=verbose,
|
| 56 |
+
debug=debug,
|
| 57 |
+
refs_in_hor_frame=refs_in_hor_frame,
|
| 58 |
+
timeout_ms=timeout_ms,
|
| 59 |
+
custom_opts=custom_opts)
|
| 60 |
+
|
| 61 |
+
self._fail_idx_scale=1e-9
|
| 62 |
+
self._fail_idx_thresh_open_loop=1e0
|
| 63 |
+
self._fail_idx_thresh_close_loop=10
|
| 64 |
+
|
| 65 |
+
if open_loop:
|
| 66 |
+
self._fail_idx_thresh=self._fail_idx_thresh_open_loop
|
| 67 |
+
else:
|
| 68 |
+
self._fail_idx_thresh=self._fail_idx_thresh_close_loop
|
| 69 |
+
|
| 70 |
+
# adding some additional config files for jnt imp control
|
| 71 |
+
self._rhc_fpaths.append(paths.JNT_IMP_CONFIG_XBOT+".yaml")
|
| 72 |
+
self._rhc_fpaths.append(paths.JNT_IMP_CONFIG+".yaml")
|
| 73 |
+
|
| 74 |
+
def _set_rhc_pred_idx(self):
|
| 75 |
+
self._pred_node_idx=round((self._n_nodes-1)*2/3)
|
| 76 |
+
|
| 77 |
+
def _set_rhc_cmds_idx(self):
|
| 78 |
+
self._rhc_cmds_node_idx=2
|
| 79 |
+
|
| 80 |
+
def _config_override(self):
|
| 81 |
+
paths = PathsGetter()
|
| 82 |
+
if ("control_wheels" in self._custom_opts):
|
| 83 |
+
if self._custom_opts["control_wheels"]:
|
| 84 |
+
self.config_path = paths.RHCCONFIGPATH_WHEELS+self._files_suffix+".yaml"
|
| 85 |
+
if ("fix_yaw" in self._custom_opts) and \
|
| 86 |
+
(self._custom_opts["fix_yaw"]):
|
| 87 |
+
self.config_path = paths.RHCCONFIGPATH_WHEELS_NO_YAW+self._files_suffix+".yaml"
|
| 88 |
+
if ("replace_continuous_joints" in self._custom_opts) and \
|
| 89 |
+
(not self._custom_opts["replace_continuous_joints"]):
|
| 90 |
+
# use continuous joints -> different config
|
| 91 |
+
self.config_path = paths.RHCCONFIGPATH_WHEELS_CONTINUOUS+self._files_suffix+".yaml"
|
| 92 |
+
if ("fix_yaw" in self._custom_opts) and \
|
| 93 |
+
(self._custom_opts["fix_yaw"]):
|
| 94 |
+
self.config_path = paths.RHCCONFIGPATH_WHEELS_CONTINUOUS_NO_YAW+self._files_suffix+".yaml"
|
| 95 |
+
|
| 96 |
+
else:
|
| 97 |
+
self._custom_opts["control_wheels"]=False
|
| 98 |
+
|
| 99 |
+
if not self._custom_opts["control_wheels"]:
|
| 100 |
+
self._fixed_jnt_patterns=self._fixed_jnt_patterns+\
|
| 101 |
+
["j_wheel",
|
| 102 |
+
"ankle_yaw"]
|
| 103 |
+
self._custom_opts["replace_continuous_joints"]=True
|
| 104 |
+
|
| 105 |
+
def _init_problem(self):
|
| 106 |
+
|
| 107 |
+
if not self._custom_opts["control_wheels"]:
|
| 108 |
+
self._yaw_vertical_weight=120.0
|
| 109 |
+
else:
|
| 110 |
+
self._yaw_vertical_weight=50.0
|
| 111 |
+
|
| 112 |
+
fixed_jnts_patterns=[
|
| 113 |
+
"d435_head",
|
| 114 |
+
"velodyne_joint"]
|
| 115 |
+
|
| 116 |
+
if not self._add_upper_body:
|
| 117 |
+
fixed_jnts_patterns.append("j_arm")
|
| 118 |
+
fixed_jnts_patterns.append("torso")
|
| 119 |
+
|
| 120 |
+
if ("fix_yaw" in self._custom_opts) and \
|
| 121 |
+
(self._custom_opts["fix_yaw"]):
|
| 122 |
+
fixed_jnts_patterns.append("ankle_yaw")
|
| 123 |
+
|
| 124 |
+
flight_duration_sec=0.5 # [s]
|
| 125 |
+
flight_duration=int(flight_duration_sec/self._dt)
|
| 126 |
+
post_flight_duration_sec=0.2 # [s]
|
| 127 |
+
post_flight_duration=int(post_flight_duration_sec/self._dt)
|
| 128 |
+
|
| 129 |
+
step_height=0.1
|
| 130 |
+
if ("step_height" in self._custom_opts):
|
| 131 |
+
step_height=self._custom_opts["step_height"]
|
| 132 |
+
|
| 133 |
+
super()._init_problem(fixed_jnt_patterns=fixed_jnts_patterns,
|
| 134 |
+
wheels_patterns=["wheel_"],
|
| 135 |
+
foot_linkname="wheel_1",
|
| 136 |
+
flight_duration=flight_duration,
|
| 137 |
+
post_flight_stance=post_flight_duration,
|
| 138 |
+
step_height=step_height,
|
| 139 |
+
keep_yaw_vert=True,
|
| 140 |
+
yaw_vertical_weight=self._yaw_vertical_weight,
|
| 141 |
+
vertical_landing=True,
|
| 142 |
+
vertical_land_weight=10.0,
|
| 143 |
+
phase_force_reg=5e-2,
|
| 144 |
+
vel_bounds_weight=1.0)
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/centauro_rhc_wheels_continuous_no_yaw_ub.yaml
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
solver:
|
| 2 |
+
type: ilqr
|
| 3 |
+
ipopt.linear_solver: ma57
|
| 4 |
+
ipopt.tol: 0.1
|
| 5 |
+
# ilqr.merit_der_threshold: 1e-3
|
| 6 |
+
# ilqr.defect_norm_threshold: 1e-3
|
| 7 |
+
ipopt.constr_viol_tol: 0.01
|
| 8 |
+
ilqr.constraint_violation_threshold: 1e-2
|
| 9 |
+
# ipopt.hessian_approximation: exact
|
| 10 |
+
ipopt.print_level: 5
|
| 11 |
+
ipopt.suppress_all_output: 'yes'
|
| 12 |
+
ipopt.sb: 'yes'
|
| 13 |
+
ilqr.suppress_all_output: 'yes'
|
| 14 |
+
ilqr.codegen_enabled: true
|
| 15 |
+
ilqr.codegen_workdir: /tmp/tyhio
|
| 16 |
+
ilqr.enable_gn: true
|
| 17 |
+
ilqr.hxx_reg_base: 0.0
|
| 18 |
+
ilqr.n_threads: 0
|
| 19 |
+
print_time: 0
|
| 20 |
+
|
| 21 |
+
constraints:
|
| 22 |
+
- contact_1
|
| 23 |
+
- contact_2
|
| 24 |
+
- contact_3
|
| 25 |
+
- contact_4
|
| 26 |
+
|
| 27 |
+
costs:
|
| 28 |
+
- z_contact_1
|
| 29 |
+
- z_contact_2
|
| 30 |
+
- z_contact_3
|
| 31 |
+
- z_contact_4
|
| 32 |
+
# - vz_contact_1
|
| 33 |
+
# - vz_contact_2
|
| 34 |
+
# - vz_contact_3
|
| 35 |
+
# - vz_contact_4
|
| 36 |
+
# - xy_contact_1
|
| 37 |
+
# - xy_contact_2
|
| 38 |
+
# - xy_contact_3
|
| 39 |
+
# - xy_contact_4
|
| 40 |
+
# - vxy_contact_1
|
| 41 |
+
# - vxy_contact_2
|
| 42 |
+
# - vxy_contact_3
|
| 43 |
+
# - vxy_contact_4
|
| 44 |
+
- base_lin_velxy
|
| 45 |
+
- base_lin_velz
|
| 46 |
+
- base_omega
|
| 47 |
+
- base_capture
|
| 48 |
+
- joint_posture_capture
|
| 49 |
+
- joint_posture_capture_torso
|
| 50 |
+
- joint_posture_capture_ub
|
| 51 |
+
- v_root_regularization
|
| 52 |
+
- v_jnts_regularization
|
| 53 |
+
- a_regularization
|
| 54 |
+
- joint_v_reg_wheels
|
| 55 |
+
- joint_a_reg_wheels
|
| 56 |
+
# - force_regularization
|
| 57 |
+
|
| 58 |
+
.define:
|
| 59 |
+
- &w_base_omega 15.
|
| 60 |
+
- &w_base_vxy 20.
|
| 61 |
+
- &w_base_vz 20.
|
| 62 |
+
- &w_base_z 15.
|
| 63 |
+
- &w_contact_z 175.0
|
| 64 |
+
- &w_contact_vz 250.0
|
| 65 |
+
- &w_contact_xy 60.0
|
| 66 |
+
- &w_contact_vxy 50.0
|
| 67 |
+
- &w_base_capture 200.
|
| 68 |
+
- &w_capture_postural 30.0
|
| 69 |
+
- &w_capture_postural_torso 30.0
|
| 70 |
+
- &w_capture_postural_ub 5.0
|
| 71 |
+
- &w_v_root 2e-1
|
| 72 |
+
- &w_v_jnts 2e0
|
| 73 |
+
- &w_v_wheels 1e0
|
| 74 |
+
- &w_a 4e-1
|
| 75 |
+
- &w_a_wheels 8e-1
|
| 76 |
+
- &wheel_radius 0.124
|
| 77 |
+
|
| 78 |
+
base_lin_velxy:
|
| 79 |
+
type: Cartesian
|
| 80 |
+
distal_link: base_link
|
| 81 |
+
indices: [0, 1]
|
| 82 |
+
nodes: ${range(1, N-5)}
|
| 83 |
+
cartesian_type: velocity
|
| 84 |
+
weight: *w_base_vxy
|
| 85 |
+
|
| 86 |
+
base_lin_velz:
|
| 87 |
+
type: Cartesian
|
| 88 |
+
distal_link: base_link
|
| 89 |
+
indices: [2]
|
| 90 |
+
nodes: ${range(1, N-5)}
|
| 91 |
+
cartesian_type: velocity
|
| 92 |
+
weight: *w_base_vz
|
| 93 |
+
|
| 94 |
+
base_omega:
|
| 95 |
+
type: Cartesian
|
| 96 |
+
distal_link: base_link
|
| 97 |
+
indices: [3, 4, 5]
|
| 98 |
+
nodes: ${range(1, N-5)}
|
| 99 |
+
cartesian_type: velocity
|
| 100 |
+
weight: *w_base_omega
|
| 101 |
+
|
| 102 |
+
base_capture:
|
| 103 |
+
type: Cartesian
|
| 104 |
+
distal_link: base_link
|
| 105 |
+
indices: [0, 1, 2, 3, 4, 5]
|
| 106 |
+
nodes: ${range(N-5, N+1)}
|
| 107 |
+
cartesian_type: velocity
|
| 108 |
+
weight: *w_base_capture
|
| 109 |
+
|
| 110 |
+
# ===============================
|
| 111 |
+
|
| 112 |
+
rolling_contact_1:
|
| 113 |
+
type: Rolling
|
| 114 |
+
frame: wheel_1
|
| 115 |
+
radius: *wheel_radius
|
| 116 |
+
|
| 117 |
+
rolling_contact_2:
|
| 118 |
+
type: Rolling
|
| 119 |
+
frame: wheel_2
|
| 120 |
+
radius: *wheel_radius
|
| 121 |
+
|
| 122 |
+
rolling_contact_3:
|
| 123 |
+
type: Rolling
|
| 124 |
+
frame: wheel_3
|
| 125 |
+
radius: *wheel_radius
|
| 126 |
+
|
| 127 |
+
rolling_contact_4:
|
| 128 |
+
type: Rolling
|
| 129 |
+
frame: wheel_4
|
| 130 |
+
radius: *wheel_radius
|
| 131 |
+
|
| 132 |
+
# ==================================
|
| 133 |
+
|
| 134 |
+
interaction_contact_1:
|
| 135 |
+
type: VertexForce
|
| 136 |
+
frame: contact_1
|
| 137 |
+
fn_min: 100.0
|
| 138 |
+
enable_fc: true
|
| 139 |
+
friction_coeff: 0.5
|
| 140 |
+
vertex_frames:
|
| 141 |
+
- wheel_1
|
| 142 |
+
|
| 143 |
+
interaction_contact_2:
|
| 144 |
+
type: VertexForce
|
| 145 |
+
frame: contact_2
|
| 146 |
+
fn_min: 100.0
|
| 147 |
+
enable_fc: true
|
| 148 |
+
friction_coeff: 0.5
|
| 149 |
+
vertex_frames:
|
| 150 |
+
- wheel_2
|
| 151 |
+
|
| 152 |
+
interaction_contact_3:
|
| 153 |
+
type: VertexForce
|
| 154 |
+
frame: contact_3
|
| 155 |
+
fn_min: 100.0
|
| 156 |
+
enable_fc: true
|
| 157 |
+
friction_coeff: 0.5
|
| 158 |
+
vertex_frames:
|
| 159 |
+
- wheel_3
|
| 160 |
+
|
| 161 |
+
interaction_contact_4:
|
| 162 |
+
type: VertexForce
|
| 163 |
+
frame: contact_4
|
| 164 |
+
fn_min: 100.0
|
| 165 |
+
enable_fc: true
|
| 166 |
+
friction_coeff: 0.5
|
| 167 |
+
vertex_frames:
|
| 168 |
+
- wheel_4
|
| 169 |
+
|
| 170 |
+
contact_1:
|
| 171 |
+
type: Contact
|
| 172 |
+
subtask: [interaction_contact_1, rolling_contact_1]
|
| 173 |
+
|
| 174 |
+
contact_2:
|
| 175 |
+
type: Contact
|
| 176 |
+
subtask: [interaction_contact_2, rolling_contact_2]
|
| 177 |
+
|
| 178 |
+
contact_3:
|
| 179 |
+
type: Contact
|
| 180 |
+
subtask: [interaction_contact_3, rolling_contact_3]
|
| 181 |
+
|
| 182 |
+
contact_4:
|
| 183 |
+
type: Contact
|
| 184 |
+
subtask: [interaction_contact_4, rolling_contact_4]
|
| 185 |
+
|
| 186 |
+
joint_posture_capture:
|
| 187 |
+
type: Postural
|
| 188 |
+
weight: *w_capture_postural
|
| 189 |
+
indices: [0, 1, 2, 3,
|
| 190 |
+
6, 7, 8, 9,
|
| 191 |
+
12, 13, 14, 15,
|
| 192 |
+
18, 19, 20, 21]
|
| 193 |
+
nodes: ${range(N-5, N+1)}
|
| 194 |
+
|
| 195 |
+
joint_posture_capture_torso:
|
| 196 |
+
type: Postural
|
| 197 |
+
weight: *w_capture_postural_torso
|
| 198 |
+
indices: [24]
|
| 199 |
+
nodes: ${range(N-5, N+1)}
|
| 200 |
+
|
| 201 |
+
joint_posture_capture_ub:
|
| 202 |
+
type: Postural
|
| 203 |
+
weight: *w_capture_postural_ub
|
| 204 |
+
indices: [
|
| 205 |
+
25, 26, 27, 28, 29, 30,
|
| 206 |
+
31, 32, 33, 34, 35, 36]
|
| 207 |
+
nodes: ${range(N-5, N+1)}
|
| 208 |
+
|
| 209 |
+
v_root_regularization:
|
| 210 |
+
type: Regularization
|
| 211 |
+
nodes: ${range(0, 1)}
|
| 212 |
+
indices: [0, 1, 2, 3, 4, 5]
|
| 213 |
+
weight:
|
| 214 |
+
v: *w_v_root
|
| 215 |
+
|
| 216 |
+
v_jnts_regularization:
|
| 217 |
+
type: Regularization
|
| 218 |
+
nodes: ${range(0, N+1)}
|
| 219 |
+
indices: [6, 7, 8, 9,
|
| 220 |
+
11, 12, 13, 14,
|
| 221 |
+
16, 17, 18, 19,
|
| 222 |
+
21, 21, 23, 24,
|
| 223 |
+
26,
|
| 224 |
+
27, 28, 29, 30, 31, 32,
|
| 225 |
+
33, 34, 35, 36, 37, 38]
|
| 226 |
+
weight:
|
| 227 |
+
v: *w_v_jnts
|
| 228 |
+
|
| 229 |
+
a_regularization:
|
| 230 |
+
type: Regularization
|
| 231 |
+
nodes: ${range(0, N+1)}
|
| 232 |
+
indices: [0, 1, 2, 3, 4, 5,
|
| 233 |
+
6, 7, 8, 9,
|
| 234 |
+
11, 12, 13, 14,
|
| 235 |
+
16, 17, 18, 19,
|
| 236 |
+
21, 21, 23, 24,
|
| 237 |
+
26,
|
| 238 |
+
27, 28, 29, 30, 31, 32,
|
| 239 |
+
33, 34, 35, 36, 37, 38]
|
| 240 |
+
weight:
|
| 241 |
+
a: *w_a # 0.01
|
| 242 |
+
|
| 243 |
+
joint_v_reg_wheels:
|
| 244 |
+
type: Regularization
|
| 245 |
+
nodes: ${range(0, N+1)}
|
| 246 |
+
indices: [10, 15, 20, 25]
|
| 247 |
+
weight:
|
| 248 |
+
v: *w_v_wheels
|
| 249 |
+
|
| 250 |
+
joint_a_reg_wheels:
|
| 251 |
+
type: Regularization
|
| 252 |
+
nodes: ${range(0, N+1)}
|
| 253 |
+
indices: [10, 15, 20, 25]
|
| 254 |
+
weight:
|
| 255 |
+
a: *w_a_wheels # 0.01
|
| 256 |
+
|
| 257 |
+
# flight phase traj tracking
|
| 258 |
+
z_contact_1:
|
| 259 |
+
type: Cartesian
|
| 260 |
+
distal_link: contact_1
|
| 261 |
+
indices: [2]
|
| 262 |
+
cartesian_type: position
|
| 263 |
+
weight: *w_contact_z
|
| 264 |
+
|
| 265 |
+
z_contact_2:
|
| 266 |
+
type: Cartesian
|
| 267 |
+
distal_link: contact_2
|
| 268 |
+
indices: [2]
|
| 269 |
+
cartesian_type: position
|
| 270 |
+
weight: *w_contact_z
|
| 271 |
+
|
| 272 |
+
z_contact_3:
|
| 273 |
+
type: Cartesian
|
| 274 |
+
distal_link: contact_3
|
| 275 |
+
indices: [2]
|
| 276 |
+
cartesian_type: position
|
| 277 |
+
weight: *w_contact_z
|
| 278 |
+
|
| 279 |
+
z_contact_4:
|
| 280 |
+
type: Cartesian
|
| 281 |
+
distal_link: contact_4
|
| 282 |
+
indices: [2]
|
| 283 |
+
cartesian_type: position
|
| 284 |
+
weight: *w_contact_z
|
| 285 |
+
|
| 286 |
+
xy_contact_1:
|
| 287 |
+
type: Cartesian
|
| 288 |
+
distal_link: contact_1
|
| 289 |
+
indices: [0, 1]
|
| 290 |
+
cartesian_type: position
|
| 291 |
+
weight: *w_contact_xy
|
| 292 |
+
|
| 293 |
+
xy_contact_2:
|
| 294 |
+
type: Cartesian
|
| 295 |
+
distal_link: contact_2
|
| 296 |
+
indices: [0, 1]
|
| 297 |
+
cartesian_type: position
|
| 298 |
+
weight: *w_contact_xy
|
| 299 |
+
|
| 300 |
+
xy_contact_3:
|
| 301 |
+
type: Cartesian
|
| 302 |
+
distal_link: contact_3
|
| 303 |
+
indices: [0, 1]
|
| 304 |
+
cartesian_type: position
|
| 305 |
+
weight: *w_contact_xy
|
| 306 |
+
|
| 307 |
+
xy_contact_4:
|
| 308 |
+
type: Cartesian
|
| 309 |
+
distal_link: contact_4
|
| 310 |
+
indices: [0, 1]
|
| 311 |
+
cartesian_type: position
|
| 312 |
+
weight: *w_contact_xy
|
| 313 |
+
|
| 314 |
+
vz_contact_1:
|
| 315 |
+
type: Cartesian
|
| 316 |
+
distal_link: contact_1
|
| 317 |
+
indices: [2]
|
| 318 |
+
cartesian_type: velocity
|
| 319 |
+
weight: *w_contact_vz
|
| 320 |
+
|
| 321 |
+
vz_contact_2:
|
| 322 |
+
type: Cartesian
|
| 323 |
+
distal_link: contact_2
|
| 324 |
+
indices: [2]
|
| 325 |
+
cartesian_type: velocity
|
| 326 |
+
weight: *w_contact_vz
|
| 327 |
+
|
| 328 |
+
vz_contact_3:
|
| 329 |
+
type: Cartesian
|
| 330 |
+
distal_link: contact_3
|
| 331 |
+
indices: [2]
|
| 332 |
+
cartesian_type: velocity
|
| 333 |
+
weight: *w_contact_vz
|
| 334 |
+
|
| 335 |
+
vz_contact_4:
|
| 336 |
+
type: Cartesian
|
| 337 |
+
distal_link: contact_4
|
| 338 |
+
indices: [2]
|
| 339 |
+
cartesian_type: velocity
|
| 340 |
+
weight: *w_contact_vz
|
| 341 |
+
|
| 342 |
+
vxy_contact_1:
|
| 343 |
+
type: Cartesian
|
| 344 |
+
distal_link: contact_1
|
| 345 |
+
indices: [0, 1]
|
| 346 |
+
cartesian_type: velocity
|
| 347 |
+
weight: *w_contact_vxy
|
| 348 |
+
|
| 349 |
+
vxy_contact_2:
|
| 350 |
+
type: Cartesian
|
| 351 |
+
distal_link: contact_2
|
| 352 |
+
indices: [0, 1]
|
| 353 |
+
cartesian_type: velocity
|
| 354 |
+
weight: *w_contact_vxy
|
| 355 |
+
|
| 356 |
+
vxy_contact_3:
|
| 357 |
+
type: Cartesian
|
| 358 |
+
distal_link: contact_3
|
| 359 |
+
indices: [0, 1]
|
| 360 |
+
cartesian_type: velocity
|
| 361 |
+
weight: *w_contact_vxy
|
| 362 |
+
|
| 363 |
+
vxy_contact_4:
|
| 364 |
+
type: Cartesian
|
| 365 |
+
distal_link: contact_4
|
| 366 |
+
indices: [0, 1]
|
| 367 |
+
cartesian_type: velocity
|
| 368 |
+
weight: *w_contact_vxy
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl_model
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:0c9df84000339df696ddf1be50309bbbb823ad25881edfe072b9afe15a41fce4
|
| 3 |
+
size 10021303
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/fake_pos_track_env_phase_control.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Dict
|
| 2 |
+
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
import torch
|
| 6 |
+
|
| 7 |
+
from EigenIPC.PyEigenIPC import VLevel
|
| 8 |
+
|
| 9 |
+
from mpc_hive.utilities.math_utils_torch import world2base_frame
|
| 10 |
+
|
| 11 |
+
from aug_mpc_envs.training_envs.flight_phase_control_env import FlightPhaseControl
|
| 12 |
+
|
| 13 |
+
class FakePosTrackEnvPhaseControl(FlightPhaseControl):
|
| 14 |
+
"""Adds positional goals to the flight-parameter control env so agents chase waypoints while directly setting gait contact flags and flight profiles."""
|
| 15 |
+
|
| 16 |
+
def __init__(self,
|
| 17 |
+
namespace: str,
|
| 18 |
+
verbose: bool = False,
|
| 19 |
+
vlevel: VLevel = VLevel.V1,
|
| 20 |
+
use_gpu: bool = True,
|
| 21 |
+
dtype: torch.dtype = torch.float32,
|
| 22 |
+
debug: bool = True,
|
| 23 |
+
override_agent_refs: bool = False,
|
| 24 |
+
timeout_ms: int = 60000,
|
| 25 |
+
env_opts: Dict = {}):
|
| 26 |
+
|
| 27 |
+
self._add_env_opt(env_opts, "max_distance", default=5.0) # [m]
|
| 28 |
+
self._add_env_opt(env_opts, "min_distance", default=0.0) # [m]
|
| 29 |
+
self._add_env_opt(env_opts, "max_vref", default=1.0) # [m/s]
|
| 30 |
+
self._add_env_opt(env_opts, "max_dp", default=5.0) # [m] after this, v ref saturates
|
| 31 |
+
self._add_env_opt(env_opts, "max_dt", default=env_opts["max_dp"]/ env_opts["max_vref"])
|
| 32 |
+
|
| 33 |
+
FlightPhaseControl.__init__(self,
|
| 34 |
+
namespace=namespace,
|
| 35 |
+
verbose=verbose,
|
| 36 |
+
vlevel=vlevel,
|
| 37 |
+
use_gpu=use_gpu,
|
| 38 |
+
dtype=dtype,
|
| 39 |
+
debug=debug,
|
| 40 |
+
override_agent_refs=override_agent_refs,
|
| 41 |
+
timeout_ms=timeout_ms,
|
| 42 |
+
env_opts=env_opts)
|
| 43 |
+
|
| 44 |
+
def get_file_paths(self):
|
| 45 |
+
paths=FlightPhaseControl.get_file_paths(self)
|
| 46 |
+
paths.append(os.path.abspath(__file__))
|
| 47 |
+
return paths
|
| 48 |
+
|
| 49 |
+
def _custom_post_init(self):
|
| 50 |
+
FlightPhaseControl._custom_post_init(self)
|
| 51 |
+
|
| 52 |
+
# position targets to be reached (wrt robot's pos at ep start)
|
| 53 |
+
self._p_trgt_w=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[:, 0:2].detach().clone()
|
| 54 |
+
self._p_delta_w=self._p_trgt_w.detach().clone()
|
| 55 |
+
self._dp_norm=torch.zeros((self._n_envs, 1),dtype=self._dtype,device=self._device)
|
| 56 |
+
self._dp_versor=self._p_trgt_w.detach().clone()
|
| 57 |
+
|
| 58 |
+
self._trgt_d=torch.zeros((self._n_envs, 1),dtype=self._dtype,device=self._device)
|
| 59 |
+
self._trgt_theta=torch.zeros((self._n_envs, 1),dtype=self._dtype,device=self._device)
|
| 60 |
+
|
| 61 |
+
def _update_loc_twist_refs(self):
|
| 62 |
+
# this is called at each env substep
|
| 63 |
+
|
| 64 |
+
self._compute_twist_ref_w()
|
| 65 |
+
|
| 66 |
+
if not self._override_agent_refs:
|
| 67 |
+
agent_p_ref_current=self._agent_refs.rob_refs.root_state.get(data_type="p",
|
| 68 |
+
gpu=self._use_gpu)
|
| 69 |
+
agent_p_ref_current[:, 0:2]=self._p_trgt_w
|
| 70 |
+
|
| 71 |
+
# then convert it to base ref local for the agent
|
| 72 |
+
robot_q = self._robot_state.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 73 |
+
# rotate agent ref from world to robot base
|
| 74 |
+
world2base_frame(t_w=self._agent_twist_ref_current_w, q_b=robot_q,
|
| 75 |
+
t_out=self._agent_twist_ref_current_base_loc)
|
| 76 |
+
# write it to agent refs tensors
|
| 77 |
+
self._agent_refs.rob_refs.root_state.set(data_type="twist", data=self._agent_twist_ref_current_base_loc,
|
| 78 |
+
gpu=self._use_gpu)
|
| 79 |
+
|
| 80 |
+
def _compute_twist_ref_w(self, env_indxs: torch.Tensor = None):
|
| 81 |
+
|
| 82 |
+
# angular refs are not altered
|
| 83 |
+
if env_indxs is None:
|
| 84 |
+
# we update the position error using the current base position
|
| 85 |
+
self._p_delta_w[:, :]=self._p_trgt_w-\
|
| 86 |
+
self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[:, 0:2]
|
| 87 |
+
|
| 88 |
+
self._dp_norm[:, :]=self._p_delta_w.norm(dim=1,keepdim=True)+1e-6
|
| 89 |
+
self._dp_versor[:, :]=self._p_delta_w/self._dp_norm
|
| 90 |
+
|
| 91 |
+
# apply for vref saturation
|
| 92 |
+
to_be_saturated=self._dp_norm[:, :]>self._env_opts["max_dp"]
|
| 93 |
+
self._dp_norm[to_be_saturated.flatten(), :]=self._env_opts["max_dp"]
|
| 94 |
+
|
| 95 |
+
# we compute the twist refs for the agent depending of the position error
|
| 96 |
+
self._agent_twist_ref_current_w[:, 0:2]=self._dp_norm*self._dp_versor/self._env_opts["max_dt"]
|
| 97 |
+
self._agent_twist_ref_current_w[:, 2:3]=0 # no vertical vel
|
| 98 |
+
|
| 99 |
+
# apply pof0 using last value of bernoully coeffs
|
| 100 |
+
self._agent_twist_ref_current_w[:, 0:3] = self._agent_twist_ref_current_w[:, 0:3]*self._bernoulli_coeffs_linvel # linvel
|
| 101 |
+
self._agent_twist_ref_current_w[:, 3:6] = self._agent_twist_ref_current_w[:, 3:6]*self._bernoulli_coeffs_omega # omega
|
| 102 |
+
else:
|
| 103 |
+
self._p_delta_w[env_indxs, :]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[env_indxs, 0:2] -\
|
| 104 |
+
self._p_trgt_w[env_indxs, :]
|
| 105 |
+
|
| 106 |
+
# apply for vref saturation
|
| 107 |
+
to_be_saturated=torch.logical_and((self._dp_norm[:, :]>self._env_opts["max_dp"]).flatten(),env_indxs)
|
| 108 |
+
self._dp_norm[to_be_saturated.flatten(), :]=self._env_opts["max_dp"]
|
| 109 |
+
|
| 110 |
+
self._dp_norm[env_indxs, :]=self._p_delta_w[env_indxs, :].norm(dim=1,keepdim=True)+1e-6
|
| 111 |
+
self._dp_versor[env_indxs, :]=self._p_delta_w[env_indxs, :]/self._dp_norm[env_indxs, :]
|
| 112 |
+
|
| 113 |
+
self._agent_twist_ref_current_w[env_indxs, 0:2]=self._dp_norm[env_indxs, :]*self._dp_versor[env_indxs, :]/self._env_opts["max_dt"]
|
| 114 |
+
self._agent_twist_ref_current_w[env_indxs, 2:3]=0 # no vertical vel
|
| 115 |
+
|
| 116 |
+
# apply pof0 using last value of bernoully coeffs
|
| 117 |
+
self._agent_twist_ref_current_w[env_indxs, 0:3] = self._agent_twist_ref_current_w[env_indxs, 0:3]*self._bernoulli_coeffs_linvel[env_indxs, :]
|
| 118 |
+
self._agent_twist_ref_current_w[env_indxs, 3:6] = self._agent_twist_ref_current_w[env_indxs, 3:6]*self._bernoulli_coeffs_omega[env_indxs, :] # omega
|
| 119 |
+
|
| 120 |
+
def _override_refs(self,
|
| 121 |
+
env_indxs: torch.Tensor = None):
|
| 122 |
+
|
| 123 |
+
# runs at every post_step
|
| 124 |
+
self._agent_refs.rob_refs.root_state.synch_all(read=True,retry=True) # first read from mem
|
| 125 |
+
if self._use_gpu:
|
| 126 |
+
# copies latest refs to GPU
|
| 127 |
+
self._agent_refs.rob_refs.root_state.synch_mirror(from_gpu=False,non_blocking=False)
|
| 128 |
+
|
| 129 |
+
agent_p_ref_current=self._agent_refs.rob_refs.root_state.get(data_type="p",
|
| 130 |
+
gpu=self._use_gpu)
|
| 131 |
+
|
| 132 |
+
agent_yaw_omega_ref_current=self._agent_refs.rob_refs.root_state.get(data_type="omega",
|
| 133 |
+
gpu=self._use_gpu)
|
| 134 |
+
|
| 135 |
+
# self._p_trgt_w[:, :]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[:, 0:2] + \
|
| 136 |
+
# agent_p_ref_current[:, 0:2]
|
| 137 |
+
self._p_trgt_w[:, :]=agent_p_ref_current[:, 0:2] # set p target target from shared mem
|
| 138 |
+
|
| 139 |
+
self._agent_twist_ref_current_w[:, 5:6]=agent_yaw_omega_ref_current[:, 2:3] # set yaw ang. vel target from shared mem
|
| 140 |
+
|
| 141 |
+
def _debug_agent_refs(self):
|
| 142 |
+
if self._use_gpu:
|
| 143 |
+
self._agent_refs.rob_refs.root_state.synch_mirror(from_gpu=True,non_blocking=False)
|
| 144 |
+
self._agent_refs.rob_refs.root_state.synch_all(read=False, retry = True)
|
| 145 |
+
|
| 146 |
+
def _randomize_task_refs(self,
|
| 147 |
+
env_indxs: torch.Tensor = None):
|
| 148 |
+
|
| 149 |
+
# we randomize the target position/omega in world frame
|
| 150 |
+
if env_indxs is None:
|
| 151 |
+
self._trgt_d.uniform_(self._env_opts["min_distance"], self._env_opts["max_distance"])
|
| 152 |
+
self._trgt_theta.uniform_(0.0, 2*torch.pi)
|
| 153 |
+
|
| 154 |
+
self._p_trgt_w[:, :]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[:, 0:2] +\
|
| 155 |
+
torch.cat((self._trgt_d*torch.cos(self._trgt_theta)
|
| 156 |
+
,self._trgt_d*torch.sin(self._trgt_theta)), dim=1)
|
| 157 |
+
|
| 158 |
+
# randomize just omega
|
| 159 |
+
random_uniform=torch.full_like(self._agent_twist_ref_current_w[:, 3:6], fill_value=0.0)
|
| 160 |
+
torch.nn.init.uniform_(random_uniform, a=-1, b=1)
|
| 161 |
+
self._agent_twist_ref_current_w[:, 3:6] = random_uniform*self._twist_ref_scale[:, 3:6] + self._twist_ref_offset[:, 3:6]
|
| 162 |
+
|
| 163 |
+
# sample for all envs pof0
|
| 164 |
+
if self._env_opts["use_pof0"]: # sample from bernoulli distribution and update coefficients
|
| 165 |
+
torch.bernoulli(input=self._pof1_b_linvel,out=self._bernoulli_coeffs_linvel) # by default bernoulli_coeffs are 1 if not self._env_opts["use_pof0"]
|
| 166 |
+
torch.bernoulli(input=self._pof1_b_omega,out=self._bernoulli_coeffs_omega)
|
| 167 |
+
|
| 168 |
+
else:
|
| 169 |
+
|
| 170 |
+
if env_indxs.any():
|
| 171 |
+
integer_idxs=torch.nonzero(env_indxs).flatten()
|
| 172 |
+
|
| 173 |
+
trgt_d_selected=self._trgt_d[integer_idxs, :]
|
| 174 |
+
trgt_d_selected.uniform_(self._env_opts["min_distance"], self._env_opts["max_distance"])
|
| 175 |
+
self._trgt_d[integer_idxs, :]=trgt_d_selected
|
| 176 |
+
|
| 177 |
+
trgt_theta_selected=self._trgt_theta[integer_idxs, :]
|
| 178 |
+
trgt_theta_selected.uniform_(0.0, 2*torch.pi)
|
| 179 |
+
self._trgt_theta[integer_idxs, :]=trgt_theta_selected
|
| 180 |
+
|
| 181 |
+
self._p_trgt_w[integer_idxs, 0:1]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[integer_idxs, 0:1] +\
|
| 182 |
+
self._trgt_d[integer_idxs, :]*torch.cos(self._trgt_theta[integer_idxs, :])
|
| 183 |
+
self._p_trgt_w[integer_idxs, 1:2]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[integer_idxs, 1:2] +\
|
| 184 |
+
self._trgt_d[integer_idxs, :]*torch.sin(self._trgt_theta[integer_idxs, :])
|
| 185 |
+
|
| 186 |
+
# randomize just omega
|
| 187 |
+
random_uniform=torch.full_like(self._agent_twist_ref_current_w[env_indxs, 3:6], fill_value=0.0)
|
| 188 |
+
torch.nn.init.uniform_(random_uniform, a=-1, b=1)
|
| 189 |
+
self._agent_twist_ref_current_w[env_indxs, 3:6] = random_uniform*self._twist_ref_scale[:, 3:6] + self._twist_ref_offset[:, 3:6]
|
| 190 |
+
|
| 191 |
+
# sample for all envs pof0, then reset to 1 for envs which are not to be randomized
|
| 192 |
+
if self._env_opts["use_pof0"]: # sample from bernoulli distribution and update coefficients
|
| 193 |
+
torch.bernoulli(input=self._pof1_b_linvel,out=self._bernoulli_coeffs_linvel) # by default bernoulli_coeffs are 1 if not self._env_opts["use_pof0"]
|
| 194 |
+
torch.bernoulli(input=self._pof1_b_omega,out=self._bernoulli_coeffs_omega)
|
| 195 |
+
self._bernoulli_coeffs_linvel[~env_indxs, :]=1
|
| 196 |
+
self._bernoulli_coeffs_omega[~env_indxs, :]=1
|
| 197 |
+
|
| 198 |
+
self._compute_twist_ref_w(env_indxs=env_indxs) # update linear vel twist refs based on pos error
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/flight_phase_control_env.py
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
from typing import Dict
|
| 3 |
+
|
| 4 |
+
import os
|
| 5 |
+
|
| 6 |
+
import torch
|
| 7 |
+
|
| 8 |
+
from EigenIPC.PyEigenIPC import VLevel
|
| 9 |
+
|
| 10 |
+
from mpc_hive.utilities.shared_data.rhc_data import RobotState
|
| 11 |
+
|
| 12 |
+
from aug_mpc_envs.training_envs.twist_tracking_env import TwistTrackingEnv
|
| 13 |
+
|
| 14 |
+
class FlightPhaseControl(TwistTrackingEnv):
|
| 15 |
+
"""Extends twist tracking with per-contact flight length/apex/end actions so agents learn to modulate aerial phases alongside base velocity tracking."""
|
| 16 |
+
|
| 17 |
+
def __init__(self,
|
| 18 |
+
namespace: str,
|
| 19 |
+
verbose: bool = False,
|
| 20 |
+
vlevel: VLevel = VLevel.V1,
|
| 21 |
+
use_gpu: bool = True,
|
| 22 |
+
dtype: torch.dtype = torch.float32,
|
| 23 |
+
debug: bool = True,
|
| 24 |
+
override_agent_refs: bool = False,
|
| 25 |
+
timeout_ms: int = 60000,
|
| 26 |
+
env_opts: Dict = {}):
|
| 27 |
+
|
| 28 |
+
self._add_env_opt(env_opts, "control_flength", default=True)
|
| 29 |
+
self._add_env_opt(env_opts, "control_fapex", default=True)
|
| 30 |
+
self._add_env_opt(env_opts, "control_fend", default=True)
|
| 31 |
+
self._add_env_opt(env_opts, "control_flanding", default=False)
|
| 32 |
+
|
| 33 |
+
self._add_env_opt(env_opts, "flength_min", default=8) # substeps
|
| 34 |
+
|
| 35 |
+
# temporarily creating robot state client to get some data
|
| 36 |
+
robot_state_tmp = RobotState(namespace=namespace,
|
| 37 |
+
is_server=False,
|
| 38 |
+
safe=False,
|
| 39 |
+
verbose=verbose,
|
| 40 |
+
vlevel=vlevel,
|
| 41 |
+
with_gpu_mirror=False,
|
| 42 |
+
with_torch_view=False)
|
| 43 |
+
robot_state_tmp.run()
|
| 44 |
+
n_contacts = len(robot_state_tmp.contact_names())
|
| 45 |
+
robot_state_tmp.close()
|
| 46 |
+
|
| 47 |
+
actions_dim=10 # base size
|
| 48 |
+
if env_opts["control_flength"]:
|
| 49 |
+
actions_dim+=n_contacts
|
| 50 |
+
if env_opts["control_fapex"]:
|
| 51 |
+
actions_dim+=n_contacts
|
| 52 |
+
if env_opts["control_fend"]:
|
| 53 |
+
actions_dim+=n_contacts
|
| 54 |
+
if env_opts["control_flanding"]:
|
| 55 |
+
actions_dim+=2*n_contacts
|
| 56 |
+
|
| 57 |
+
TwistTrackingEnv.__init__(self,
|
| 58 |
+
namespace=namespace,
|
| 59 |
+
actions_dim=actions_dim,
|
| 60 |
+
verbose=verbose,
|
| 61 |
+
vlevel=vlevel,
|
| 62 |
+
use_gpu=use_gpu,
|
| 63 |
+
dtype=dtype,
|
| 64 |
+
debug=debug,
|
| 65 |
+
override_agent_refs=override_agent_refs,
|
| 66 |
+
timeout_ms=timeout_ms,
|
| 67 |
+
env_opts=env_opts)
|
| 68 |
+
|
| 69 |
+
def get_file_paths(self):
|
| 70 |
+
paths=TwistTrackingEnv.get_file_paths(self)
|
| 71 |
+
paths.append(os.path.abspath(__file__))
|
| 72 |
+
return paths
|
| 73 |
+
|
| 74 |
+
def _custom_post_init(self):
|
| 75 |
+
|
| 76 |
+
TwistTrackingEnv._custom_post_init(self)
|
| 77 |
+
|
| 78 |
+
self._add_env_opt(self._env_opts, "flength_max", default=self._n_nodes_rhc.mean().item()) # MPC steps (substeps)
|
| 79 |
+
|
| 80 |
+
# additional actions bounds
|
| 81 |
+
|
| 82 |
+
# flight params (length)
|
| 83 |
+
if self._env_opts["control_flength"]:
|
| 84 |
+
idx=self._actions_map["flight_len_start"]
|
| 85 |
+
self._actions_lb[:, idx:(idx+self._n_contacts)]=self._env_opts["flength_min"]
|
| 86 |
+
self._actions_ub[:, idx:(idx+self._n_contacts)]=self._env_opts["flength_max"]
|
| 87 |
+
self._is_continuous_actions[idx:(idx+self._n_contacts)]=True
|
| 88 |
+
# flight params (apex)
|
| 89 |
+
if self._env_opts["control_fapex"]:
|
| 90 |
+
idx=self._actions_map["flight_apex_start"]
|
| 91 |
+
self._actions_lb[:, idx:(idx+self._n_contacts)]=0.05
|
| 92 |
+
self._actions_ub[:, idx:(idx+self._n_contacts)]=0.35
|
| 93 |
+
self._is_continuous_actions[idx:(idx+self._n_contacts)]=True
|
| 94 |
+
# flight params (end)
|
| 95 |
+
if self._env_opts["control_fend"]:
|
| 96 |
+
idx=self._actions_map["flight_end_start"]
|
| 97 |
+
self._actions_lb[:, idx:(idx+self._n_contacts)]=0.0
|
| 98 |
+
self._actions_ub[:, idx:(idx+self._n_contacts)]=0.2
|
| 99 |
+
self._is_continuous_actions[idx:(idx+self._n_contacts)]=True
|
| 100 |
+
# flight params (landing dx, dy)
|
| 101 |
+
if self._env_opts["control_flanding"]:
|
| 102 |
+
idx=self._actions_map["flight_land_dx_start"]
|
| 103 |
+
self._actions_lb[:, idx:(idx+self._n_contacts)]=-0.5
|
| 104 |
+
self._actions_ub[:, idx:(idx+self._n_contacts)]=0.5
|
| 105 |
+
self._is_continuous_actions[idx:(idx+self._n_contacts)]=True
|
| 106 |
+
idx=self._actions_map["flight_land_dy_start"]
|
| 107 |
+
self._actions_lb[:, idx:(idx+self._n_contacts)]=-0.5
|
| 108 |
+
self._actions_ub[:, idx:(idx+self._n_contacts)]=0.5
|
| 109 |
+
self._is_continuous_actions[idx:(idx+self._n_contacts)]=True
|
| 110 |
+
|
| 111 |
+
# redefine default actions
|
| 112 |
+
self.default_action[:, :] = (self._actions_ub+self._actions_lb)/2.0
|
| 113 |
+
# self.default_action[:, ~self._is_continuous_actions] = 1.0
|
| 114 |
+
|
| 115 |
+
if self._env_opts["control_flength"]:
|
| 116 |
+
idx=self._actions_map["flight_len_start"]
|
| 117 |
+
self.safe_action[:, idx:(idx+self._n_contacts)]=(self._env_opts["flength_max"]+self._env_opts["flength_min"])/3.0
|
| 118 |
+
|
| 119 |
+
if self._env_opts["control_fapex"]:
|
| 120 |
+
idx=self._actions_map["flight_apex_start"]
|
| 121 |
+
self.safe_action[:, idx:(idx+self._n_contacts)]=0.1
|
| 122 |
+
|
| 123 |
+
if self._env_opts["control_fend"]:
|
| 124 |
+
idx=self._actions_map["flight_end_start"]
|
| 125 |
+
self.safe_action[:, idx:(idx+self._n_contacts)]=0.0
|
| 126 |
+
|
| 127 |
+
if self._env_opts["control_flanding"]:
|
| 128 |
+
idx=self._actions_map["flight_land_dx_start"]
|
| 129 |
+
self.safe_action[:, idx:(idx+self._n_contacts)]=0.0
|
| 130 |
+
idx=self._actions_map["flight_land_dy_start"]
|
| 131 |
+
self.safe_action[:, idx:(idx+self._n_contacts)]=0.0
|
| 132 |
+
|
| 133 |
+
def _set_rhc_refs(self):
|
| 134 |
+
TwistTrackingEnv._set_rhc_refs(self)
|
| 135 |
+
|
| 136 |
+
action_to_be_applied = self.get_actual_actions()
|
| 137 |
+
|
| 138 |
+
if self._env_opts["control_flength"]:
|
| 139 |
+
idx=self._actions_map["flight_len_start"]
|
| 140 |
+
flen_now=self._rhc_refs.flight_settings_req.get(data_type="len_remain", gpu=self._use_gpu)
|
| 141 |
+
flen_now[:, :]=action_to_be_applied[:, idx:(idx+self._n_contacts)]
|
| 142 |
+
self._rhc_refs.flight_settings_req.set(data=flen_now, data_type="len_remain", gpu=self._use_gpu)
|
| 143 |
+
|
| 144 |
+
if self._env_opts["control_fapex"]:
|
| 145 |
+
idx=self._actions_map["flight_apex_start"]
|
| 146 |
+
fapex_now=self._rhc_refs.flight_settings_req.get(data_type="apex_dpos", gpu=self._use_gpu)
|
| 147 |
+
fapex_now[:, :]=action_to_be_applied[:, idx:(idx+self._n_contacts)]
|
| 148 |
+
self._rhc_refs.flight_settings_req.set(data=fapex_now, data_type="apex_dpos", gpu=self._use_gpu)
|
| 149 |
+
|
| 150 |
+
if self._env_opts["control_fend"]:
|
| 151 |
+
idx=self._actions_map["flight_end_start"]
|
| 152 |
+
fend_now=self._rhc_refs.flight_settings_req.get(data_type="end_dpos", gpu=self._use_gpu)
|
| 153 |
+
fend_now[:, :]=action_to_be_applied[:, idx:(idx+self._n_contacts)]
|
| 154 |
+
self._rhc_refs.flight_settings_req.set(data=fend_now, data_type="end_dpos", gpu=self._use_gpu)
|
| 155 |
+
|
| 156 |
+
if self._env_opts["control_flanding"]:
|
| 157 |
+
idx=self._actions_map["flight_land_dx_start"]
|
| 158 |
+
fland_dx_now=self._rhc_refs.flight_settings_req.get(data_type="land_dx", gpu=self._use_gpu)
|
| 159 |
+
fland_dx_now[:, :]=action_to_be_applied[:, idx:(idx+self._n_contacts)]
|
| 160 |
+
self._rhc_refs.flight_settings_req.set(data=fland_dx_now, data_type="land_dx", gpu=self._use_gpu)
|
| 161 |
+
idx=self._actions_map["flight_land_dy_start"]
|
| 162 |
+
fland_dy_now=self._rhc_refs.flight_settings_req.get(data_type="land_dy", gpu=self._use_gpu)
|
| 163 |
+
fland_dy_now[:, :]=action_to_be_applied[:, idx:(idx+self._n_contacts)]
|
| 164 |
+
self._rhc_refs.flight_settings_req.set(data=fland_dy_now, data_type="land_dy", gpu=self._use_gpu)
|
| 165 |
+
|
| 166 |
+
def _write_rhc_refs(self):
|
| 167 |
+
TwistTrackingEnv._write_rhc_refs(self)
|
| 168 |
+
if self._use_gpu:
|
| 169 |
+
self._rhc_refs.flight_settings_req.synch_mirror(from_gpu=True,non_blocking=False)
|
| 170 |
+
self._rhc_refs.flight_settings_req.synch_all(read=False, retry=True)
|
| 171 |
+
|
| 172 |
+
def _get_action_names(self):
|
| 173 |
+
|
| 174 |
+
action_names = [""] * self.actions_dim()
|
| 175 |
+
action_names[0] = "vx_cmd" # twist commands from agent to RHC controller
|
| 176 |
+
action_names[1] = "vy_cmd"
|
| 177 |
+
action_names[2] = "vz_cmd"
|
| 178 |
+
action_names[3] = "roll_omega_cmd"
|
| 179 |
+
action_names[4] = "pitch_omega_cmd"
|
| 180 |
+
action_names[5] = "yaw_omega_cmd"
|
| 181 |
+
|
| 182 |
+
next_idx=6
|
| 183 |
+
self._actions_map["contact_flag_start"]=next_idx
|
| 184 |
+
for i in range(len(self._contact_names)):
|
| 185 |
+
contact=self._contact_names[i]
|
| 186 |
+
action_names[next_idx] = f"contact_flag_{contact}"
|
| 187 |
+
next_idx+=1
|
| 188 |
+
if self._env_opts["control_flength"]:
|
| 189 |
+
self._actions_map["flight_len_start"]=next_idx
|
| 190 |
+
for i in range(len(self._contact_names)):
|
| 191 |
+
contact=self._contact_names[i]
|
| 192 |
+
action_names[next_idx+i] = f"flight_len_{contact}"
|
| 193 |
+
next_idx+=len(self._contact_names)
|
| 194 |
+
if self._env_opts["control_fapex"]:
|
| 195 |
+
self._actions_map["flight_apex_start"]=next_idx
|
| 196 |
+
for i in range(len(self._contact_names)):
|
| 197 |
+
contact=self._contact_names[i]
|
| 198 |
+
action_names[next_idx+i] = f"flight_apex_{contact}"
|
| 199 |
+
next_idx+=len(self._contact_names)
|
| 200 |
+
if self._env_opts["control_fend"]:
|
| 201 |
+
self._actions_map["flight_end_start"]=next_idx
|
| 202 |
+
for i in range(len(self._contact_names)):
|
| 203 |
+
contact=self._contact_names[i]
|
| 204 |
+
action_names[next_idx+i] = f"flight_end_{contact}"
|
| 205 |
+
next_idx+=len(self._contact_names)
|
| 206 |
+
if self._env_opts["control_flanding"]:
|
| 207 |
+
self._actions_map["flight_land_dx_start"]=next_idx
|
| 208 |
+
for i in range(len(self._contact_names)):
|
| 209 |
+
contact=self._contact_names[i]
|
| 210 |
+
action_names[next_idx+i] = f"flight_land_dx_{contact}"
|
| 211 |
+
next_idx+=len(self._contact_names)
|
| 212 |
+
self._actions_map["flight_land_dy_start"]=next_idx
|
| 213 |
+
for i in range(len(self._contact_names)):
|
| 214 |
+
contact=self._contact_names[i]
|
| 215 |
+
action_names[next_idx+i] = f"flight_land_dy_{contact}"
|
| 216 |
+
next_idx+=len(self._contact_names)
|
| 217 |
+
|
| 218 |
+
return action_names
|
| 219 |
+
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/hybrid_quad_rhc.py
ADDED
|
@@ -0,0 +1,1243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from mpc_hive.controllers.rhc import RHController
|
| 2 |
+
# from perf_sleep.pyperfsleep import PerfSleep
|
| 3 |
+
# from mpc_hive.utilities.cpu_utils.core_utils import get_memory_usage
|
| 4 |
+
|
| 5 |
+
from aug_mpc.controllers.rhc.horizon_based.horizon_imports import *
|
| 6 |
+
|
| 7 |
+
from aug_mpc.controllers.rhc.horizon_based.hybrid_quad_rhc_refs import HybridQuadRhcRefs
|
| 8 |
+
from aug_mpc.controllers.rhc.horizon_based.gait_manager import GaitManager
|
| 9 |
+
|
| 10 |
+
from EigenIPC.PyEigenIPC import VLevel
|
| 11 |
+
from EigenIPC.PyEigenIPC import Journal, LogType
|
| 12 |
+
|
| 13 |
+
import numpy as np
|
| 14 |
+
|
| 15 |
+
import os
|
| 16 |
+
# import shutil
|
| 17 |
+
|
| 18 |
+
import time
|
| 19 |
+
from abc import ABC, abstractmethod
|
| 20 |
+
|
| 21 |
+
from typing import Dict, List
|
| 22 |
+
import re
|
| 23 |
+
|
| 24 |
+
class HybridQuadRhc(RHController):
|
| 25 |
+
|
| 26 |
+
def __init__(self,
|
| 27 |
+
srdf_path: str,
|
| 28 |
+
urdf_path: str,
|
| 29 |
+
config_path: str,
|
| 30 |
+
robot_name: str, # used for shared memory namespaces
|
| 31 |
+
codegen_dir: str,
|
| 32 |
+
n_nodes:float = 25,
|
| 33 |
+
injection_node:int = 10,
|
| 34 |
+
dt: float = 0.02,
|
| 35 |
+
max_solver_iter = 1, # defaults to rt-iteration
|
| 36 |
+
open_loop: bool = True,
|
| 37 |
+
close_loop_all: bool = False,
|
| 38 |
+
dtype = np.float32,
|
| 39 |
+
verbose = False,
|
| 40 |
+
debug = False,
|
| 41 |
+
refs_in_hor_frame = True,
|
| 42 |
+
timeout_ms: int = 60000,
|
| 43 |
+
custom_opts: Dict = {}):
|
| 44 |
+
|
| 45 |
+
self._refs_in_hor_frame = refs_in_hor_frame
|
| 46 |
+
|
| 47 |
+
self._injection_node = injection_node
|
| 48 |
+
|
| 49 |
+
self._open_loop = open_loop
|
| 50 |
+
self._close_loop_all = close_loop_all
|
| 51 |
+
|
| 52 |
+
self._codegen_dir = codegen_dir
|
| 53 |
+
if not os.path.exists(self._codegen_dir):
|
| 54 |
+
os.makedirs(self._codegen_dir)
|
| 55 |
+
# else:
|
| 56 |
+
# # Directory already exists, delete it and recreate
|
| 57 |
+
# shutil.rmtree(self._codegen_dir)
|
| 58 |
+
# os.makedirs(self._codegen_dir)
|
| 59 |
+
|
| 60 |
+
self.step_counter = 0
|
| 61 |
+
self.sol_counter = 0
|
| 62 |
+
|
| 63 |
+
self.max_solver_iter = max_solver_iter
|
| 64 |
+
|
| 65 |
+
self._timer_start = time.perf_counter()
|
| 66 |
+
self._prb_update_time = time.perf_counter()
|
| 67 |
+
self._phase_shift_time = time.perf_counter()
|
| 68 |
+
self._task_ref_update_time = time.perf_counter()
|
| 69 |
+
self._rti_time = time.perf_counter()
|
| 70 |
+
|
| 71 |
+
self.robot_name = robot_name
|
| 72 |
+
|
| 73 |
+
self.config_path = config_path
|
| 74 |
+
|
| 75 |
+
self.urdf_path = urdf_path
|
| 76 |
+
# read urdf and srdf files
|
| 77 |
+
with open(self.urdf_path, 'r') as file:
|
| 78 |
+
self.urdf = file.read()
|
| 79 |
+
self._base_init = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0])
|
| 80 |
+
|
| 81 |
+
self._c_timelines = dict()
|
| 82 |
+
self._f_reg_timelines = dict()
|
| 83 |
+
|
| 84 |
+
self._custom_opts={"replace_continuous_joints": False,
|
| 85 |
+
"use_force_feedback": False,
|
| 86 |
+
"lin_a_feedback": False,
|
| 87 |
+
"is_open_loop": self._open_loop, # fully open (just for db)
|
| 88 |
+
"fully_closed": False, # closed loop with full feedback (just for db)
|
| 89 |
+
"closed_partial": False, # closed loop with partial feedback
|
| 90 |
+
"adaptive_is": True, # closed loop with adaptation
|
| 91 |
+
"estimate_v_root": False, # when adaptive_is or closed_partial, estimate vbase
|
| 92 |
+
"alpha_from_outside": False, # alpha set ext. from shared memory
|
| 93 |
+
"alpha_half": 1.0,
|
| 94 |
+
"only_vel_wheels": True, # whether wheels (if present) are just vel controlled
|
| 95 |
+
"use_jnt_v_feedback": False
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
self._custom_opts.update(custom_opts)
|
| 99 |
+
|
| 100 |
+
self._alpha_half=self._custom_opts["alpha_half"]
|
| 101 |
+
|
| 102 |
+
if self._open_loop:
|
| 103 |
+
self._custom_opts["fully_closed"]=False
|
| 104 |
+
self._custom_opts["adaptive_is"]=False
|
| 105 |
+
self._custom_opts["closed_partial"]=False
|
| 106 |
+
else:
|
| 107 |
+
self._custom_opts["is_open_loop"]=False
|
| 108 |
+
if self._custom_opts["fully_closed"]:
|
| 109 |
+
self._custom_opts["adaptive_is"]=False
|
| 110 |
+
self._custom_opts["closed_partial"]=False
|
| 111 |
+
self._custom_opts["lin_a_feedback"]=False
|
| 112 |
+
if self._custom_opts["closed_partial"]:
|
| 113 |
+
self._custom_opts["adaptive_is"]=False
|
| 114 |
+
self._custom_opts["fully_closed"]=False
|
| 115 |
+
self._custom_opts["lin_a_feedback"]=False
|
| 116 |
+
if self._custom_opts["adaptive_is"]:
|
| 117 |
+
self._custom_opts["closed_partial"]=False
|
| 118 |
+
self._custom_opts["fully_closed"]=False
|
| 119 |
+
|
| 120 |
+
super().__init__(srdf_path=srdf_path,
|
| 121 |
+
n_nodes=n_nodes,
|
| 122 |
+
dt=dt,
|
| 123 |
+
namespace=self.robot_name,
|
| 124 |
+
dtype=dtype,
|
| 125 |
+
verbose=verbose,
|
| 126 |
+
debug=debug,
|
| 127 |
+
timeout_ms=timeout_ms)
|
| 128 |
+
|
| 129 |
+
self._rhc_fpaths.append(self.config_path)
|
| 130 |
+
|
| 131 |
+
def _config_override(self):
|
| 132 |
+
pass
|
| 133 |
+
|
| 134 |
+
def _post_problem_init(self):
|
| 135 |
+
|
| 136 |
+
self.rhc_costs={}
|
| 137 |
+
self.rhc_constr={}
|
| 138 |
+
|
| 139 |
+
self._fail_idx_scale=0.0
|
| 140 |
+
self._expl_idx_window_size=int(1*self._n_nodes)
|
| 141 |
+
self._explosion_idx_buffer=np.zeros((1,self._expl_idx_window_size))
|
| 142 |
+
self._expl_idx_counter=0
|
| 143 |
+
self._expl_idx_buffer_counter=0
|
| 144 |
+
|
| 145 |
+
self._pred_node_idx=self._n_nodes-1
|
| 146 |
+
|
| 147 |
+
self._nq=self.nq()
|
| 148 |
+
self._nq_jnts=self._nq-7# assuming floating base
|
| 149 |
+
self._nv=self.nv()
|
| 150 |
+
self._nv_jnts=self._nv-6
|
| 151 |
+
|
| 152 |
+
self._alphas_q_root=np.zeros((7, 1), dtype=self._dtype)
|
| 153 |
+
self._alphas_q_jnts=np.zeros((self._nq_jnts, 1), dtype=self._dtype)
|
| 154 |
+
self._alphas_twist_root=np.zeros((6, 1), dtype=self._dtype)
|
| 155 |
+
self._alphas_v_jnts=np.zeros((self._nv_jnts, 1), dtype=self._dtype)
|
| 156 |
+
self._alphas_a=np.zeros((self._nv, 1), dtype=self._dtype)
|
| 157 |
+
self._alphas_q_root[:, :]=1.0 # default to all open
|
| 158 |
+
self._alphas_q_jnts[:, :]=1.0
|
| 159 |
+
self._alphas_twist_root[:, :]=1.0
|
| 160 |
+
self._alphas_v_jnts[:, :]=1.0
|
| 161 |
+
self._alphas_a[:, :]=1.0
|
| 162 |
+
|
| 163 |
+
def _init_problem(self,
|
| 164 |
+
fixed_jnt_patterns: List[str] = None,
|
| 165 |
+
wheels_patterns: List[str] = None,
|
| 166 |
+
foot_linkname: str = None,
|
| 167 |
+
flight_duration: int = 10,
|
| 168 |
+
post_flight_stance: int = 3,
|
| 169 |
+
step_height: float = 0.12,
|
| 170 |
+
keep_yaw_vert: bool = False,
|
| 171 |
+
yaw_vertical_weight: float = 2.0,
|
| 172 |
+
vertical_landing: bool = False,
|
| 173 |
+
vertical_land_weight: float = 1.0,
|
| 174 |
+
phase_force_reg: float = 1e-2,
|
| 175 |
+
vel_bounds_weight: float = 1.0):
|
| 176 |
+
|
| 177 |
+
self._fixed_jnt_patterns=fixed_jnt_patterns
|
| 178 |
+
|
| 179 |
+
self._config_override()
|
| 180 |
+
|
| 181 |
+
Journal.log(self.__class__.__name__,
|
| 182 |
+
"_init_problem",
|
| 183 |
+
f" Will use horizon config file at {self.config_path}",
|
| 184 |
+
LogType.INFO,
|
| 185 |
+
throw_when_excep=True)
|
| 186 |
+
|
| 187 |
+
self._vel_bounds_weight=vel_bounds_weight
|
| 188 |
+
self._phase_force_reg=phase_force_reg
|
| 189 |
+
self._yaw_vertical_weight=yaw_vertical_weight
|
| 190 |
+
self._vertical_land_weight=vertical_land_weight
|
| 191 |
+
# overrides parent
|
| 192 |
+
self._prb = Problem(self._n_intervals,
|
| 193 |
+
receding=True,
|
| 194 |
+
casadi_type=cs.SX)
|
| 195 |
+
self._prb.setDt(self._dt)
|
| 196 |
+
|
| 197 |
+
if "replace_continuous_joints" in self._custom_opts:
|
| 198 |
+
# continous joints are parametrized in So2
|
| 199 |
+
if self._custom_opts["replace_continuous_joints"]:
|
| 200 |
+
self.urdf = self.urdf.replace('continuous', 'revolute')
|
| 201 |
+
else:
|
| 202 |
+
self.urdf = self.urdf.replace('continuous', 'revolute')
|
| 203 |
+
|
| 204 |
+
self._kin_dyn = casadi_kin_dyn.CasadiKinDyn(self.urdf) # used for getting joint names
|
| 205 |
+
self._assign_controller_side_jnt_names(jnt_names=self._get_robot_jnt_names())
|
| 206 |
+
|
| 207 |
+
self._init_robot_homer()
|
| 208 |
+
|
| 209 |
+
# handle fixed joints
|
| 210 |
+
fixed_joint_map={}
|
| 211 |
+
if self._fixed_jnt_patterns is not None:
|
| 212 |
+
for jnt_name in self._get_robot_jnt_names():
|
| 213 |
+
for fixed_jnt_pattern in self._fixed_jnt_patterns:
|
| 214 |
+
if fixed_jnt_pattern in jnt_name:
|
| 215 |
+
fixed_joint_map.update({f"{jnt_name}":
|
| 216 |
+
self._homer.get_homing_val(jnt_name=jnt_name)})
|
| 217 |
+
break # do not search for other pattern matches
|
| 218 |
+
|
| 219 |
+
if not len(fixed_joint_map)==0: # we need to recreate kin dyn and homers
|
| 220 |
+
Journal.log(self.__class__.__name__,
|
| 221 |
+
"_init_problem",
|
| 222 |
+
f"Will fix following joints: \n{str(fixed_joint_map)}",
|
| 223 |
+
LogType.INFO,
|
| 224 |
+
throw_when_excep=True)
|
| 225 |
+
# with the fixed joint map
|
| 226 |
+
self._kin_dyn = casadi_kin_dyn.CasadiKinDyn(self.urdf,fixed_joints=fixed_joint_map)
|
| 227 |
+
# assign again controlled joints names
|
| 228 |
+
self._assign_controller_side_jnt_names(jnt_names=self._get_robot_jnt_names())
|
| 229 |
+
# updated robot homer for controlled joints
|
| 230 |
+
self._init_robot_homer()
|
| 231 |
+
|
| 232 |
+
# handle continuous joints (need to change homing and retrieve
|
| 233 |
+
# cont jnts indexes) and homing
|
| 234 |
+
self._continuous_joints=self._get_continuous_jnt_names()
|
| 235 |
+
# reduced
|
| 236 |
+
self._continuous_joints_idxs=[]
|
| 237 |
+
self._continuous_joints_idxs_cos=[]
|
| 238 |
+
self._continuous_joints_idxs_sin=[]
|
| 239 |
+
self._continuous_joints_idxs_red=[]
|
| 240 |
+
self._rev_joints_idxs=[]
|
| 241 |
+
self._rev_joints_idxs_red=[]
|
| 242 |
+
# qfull
|
| 243 |
+
self._continuous_joints_idxs_qfull=[]
|
| 244 |
+
self._continuous_joints_idxs_cos_qfull=[]
|
| 245 |
+
self._continuous_joints_idxs_sin_qfull=[]
|
| 246 |
+
self._continuous_joints_idxs_red_qfull=[]
|
| 247 |
+
self._rev_joints_idxs_qfull=[]
|
| 248 |
+
self._rev_joints_idxs_red_qfull=[]
|
| 249 |
+
jnt_homing=[""]*(len(self._homer.get_homing())+len(self._continuous_joints))
|
| 250 |
+
jnt_names=self._get_robot_jnt_names()
|
| 251 |
+
for i in range(len(jnt_names)):
|
| 252 |
+
jnt=jnt_names[i]
|
| 253 |
+
index=self._get_jnt_id(jnt)# accounting for floating joint
|
| 254 |
+
homing_idx=index-7 # homing is only for actuated joints
|
| 255 |
+
homing_value=self._homer.get_homing_val(jnt)
|
| 256 |
+
if jnt in self._continuous_joints:
|
| 257 |
+
jnt_homing[homing_idx]=np.cos(homing_value).item()
|
| 258 |
+
jnt_homing[homing_idx+1]=np.sin(homing_value).item()
|
| 259 |
+
# just actuated joints
|
| 260 |
+
self._continuous_joints_idxs.append(homing_idx) # cos
|
| 261 |
+
self._continuous_joints_idxs.append(homing_idx+1) # sin
|
| 262 |
+
self._continuous_joints_idxs_cos.append(homing_idx)
|
| 263 |
+
self._continuous_joints_idxs_sin.append(homing_idx+1)
|
| 264 |
+
self._continuous_joints_idxs_red.append(i)
|
| 265 |
+
# q full
|
| 266 |
+
self._continuous_joints_idxs_qfull.append(index) # cos
|
| 267 |
+
self._continuous_joints_idxs_qfull.append(index+1) # sin
|
| 268 |
+
self._continuous_joints_idxs_cos_qfull.append(index)
|
| 269 |
+
self._continuous_joints_idxs_sin_qfull.append(index+1)
|
| 270 |
+
self._continuous_joints_idxs_red_qfull.append(i+7)
|
| 271 |
+
else:
|
| 272 |
+
jnt_homing[homing_idx]=homing_value
|
| 273 |
+
# just actuated joints
|
| 274 |
+
self._rev_joints_idxs.append(homing_idx)
|
| 275 |
+
self._rev_joints_idxs_red.append(i)
|
| 276 |
+
# q full
|
| 277 |
+
self._rev_joints_idxs_qfull.append(index)
|
| 278 |
+
self._rev_joints_idxs_red_qfull.append(i+7)
|
| 279 |
+
|
| 280 |
+
self._jnts_q_reduced=None
|
| 281 |
+
if not len(self._continuous_joints)==0:
|
| 282 |
+
cont_joints=", ".join(self._continuous_joints)
|
| 283 |
+
|
| 284 |
+
Journal.log(self.__class__.__name__,
|
| 285 |
+
"_init_problem",
|
| 286 |
+
f"The following continuous joints were found: \n{cont_joints}",
|
| 287 |
+
LogType.INFO,
|
| 288 |
+
throw_when_excep=True)
|
| 289 |
+
# preallocating data
|
| 290 |
+
self._jnts_q_reduced=np.zeros((1,self.nv()-6),dtype=self._dtype)
|
| 291 |
+
self._jnts_q_expanded=np.zeros((self.nq()-7,1),dtype=self._dtype)
|
| 292 |
+
self._full_q_reduced=np.zeros((7+len(jnt_names), self._n_nodes),dtype=self._dtype)
|
| 293 |
+
self._jnts_q_delta_expanded=np.zeros((self.nq()-7,1),dtype=self._dtype)
|
| 294 |
+
else:
|
| 295 |
+
self._custom_opts["replace_continuous_joints"]=True
|
| 296 |
+
Journal.log(self.__class__.__name__,
|
| 297 |
+
"_init_problem",
|
| 298 |
+
f"No continuous joints were found.",
|
| 299 |
+
LogType.INFO,
|
| 300 |
+
throw_when_excep=True)
|
| 301 |
+
|
| 302 |
+
# retrieve wheels indexes (not considering continuous joints,
|
| 303 |
+
# ok just for v, eff, etc..)
|
| 304 |
+
self._wheel_patterns=wheels_patterns
|
| 305 |
+
self._wheels_idxs_v=self._get_wheels_jnt_v_idxs(wheel_patterns=self._wheel_patterns)
|
| 306 |
+
self._f0 = [0, 0, self._kin_dyn.mass()/4*9.81]
|
| 307 |
+
|
| 308 |
+
# we can create an init for the base
|
| 309 |
+
init = self._base_init.tolist() + jnt_homing
|
| 310 |
+
|
| 311 |
+
if foot_linkname is not None:
|
| 312 |
+
FK = self._kin_dyn.fk(foot_linkname) # just to get robot reference height
|
| 313 |
+
ground_level = FK(q=init)['ee_pos']
|
| 314 |
+
self._base_init[2] = -ground_level[2] # override init
|
| 315 |
+
|
| 316 |
+
self._model = FullModelInverseDynamics(problem=self._prb,
|
| 317 |
+
kd=self._kin_dyn,
|
| 318 |
+
q_init=self._homer.get_homing_map(),
|
| 319 |
+
base_init=self._base_init)
|
| 320 |
+
|
| 321 |
+
self._ti = TaskInterface(prb=self._prb,
|
| 322 |
+
model=self._model,
|
| 323 |
+
max_solver_iter=self.max_solver_iter,
|
| 324 |
+
debug = self._debug,
|
| 325 |
+
verbose = self._verbose,
|
| 326 |
+
codegen_workdir = self._codegen_dir)
|
| 327 |
+
self._ti.setTaskFromYaml(self.config_path)
|
| 328 |
+
|
| 329 |
+
# setting initial base pos ref if exists
|
| 330 |
+
base_pos = self._ti.getTask('base_height')
|
| 331 |
+
if base_pos is not None:
|
| 332 |
+
base_pos.setRef(np.atleast_2d(self._base_init).T)
|
| 333 |
+
|
| 334 |
+
self._pm = pymanager.PhaseManager(self._n_nodes, debug=False) # intervals or nodes?????
|
| 335 |
+
|
| 336 |
+
self._gm = GaitManager(self._ti,
|
| 337 |
+
self._pm,
|
| 338 |
+
self._injection_node,
|
| 339 |
+
keep_yaw_vert=keep_yaw_vert,
|
| 340 |
+
yaw_vertical_weight=self._yaw_vertical_weight,
|
| 341 |
+
vertical_landing=vertical_landing,
|
| 342 |
+
landing_vert_weight=self._vertical_land_weight,
|
| 343 |
+
phase_force_reg=self._phase_force_reg,
|
| 344 |
+
custom_opts=self._custom_opts,
|
| 345 |
+
flight_duration=flight_duration,
|
| 346 |
+
post_flight_stance=post_flight_stance,
|
| 347 |
+
step_height=step_height,
|
| 348 |
+
dh=0.0)
|
| 349 |
+
|
| 350 |
+
self._ti.model.q.setBounds(self._ti.model.q0, self._ti.model.q0, nodes=0)
|
| 351 |
+
self._ti.model.v.setBounds(self._ti.model.v0, self._ti.model.v0, nodes=0)
|
| 352 |
+
self._ti.model.q.setInitialGuess(self._ti.model.q0)
|
| 353 |
+
self._ti.model.v.setInitialGuess(self._ti.model.v0)
|
| 354 |
+
for _, cforces in self._ti.model.cmap.items():
|
| 355 |
+
n_contact_f=len(cforces)
|
| 356 |
+
for c in cforces:
|
| 357 |
+
c.setInitialGuess(np.array(self._f0)/n_contact_f)
|
| 358 |
+
|
| 359 |
+
vel_lims = self._model.kd.velocityLimits()
|
| 360 |
+
import horizon.utils as utils
|
| 361 |
+
self._prb.createResidual('vel_lb_barrier', self._vel_bounds_weight*utils.utils.barrier(vel_lims[7:] - self._model.v[7:]))
|
| 362 |
+
self._prb.createResidual('vel_ub_barrier', self._vel_bounds_weight*utils.utils.barrier1(-1 * vel_lims[7:] - self._model.v[7:]))
|
| 363 |
+
|
| 364 |
+
self._meas_lin_a_par=None
|
| 365 |
+
# if self._custom_opts["lin_a_feedback"]:
|
| 366 |
+
# # acceleration feedback on first node
|
| 367 |
+
# self._meas_lin_a_par=self._prb.createParameter(name="lin_a_feedback",
|
| 368 |
+
# dim=3, nodes=0)
|
| 369 |
+
# base_lin_a_prb=self._prb.getInput().getVars()[0:3]
|
| 370 |
+
# self._prb.createConstraint('lin_acceleration_feedback', base_lin_a_prb - self._meas_lin_a_par,
|
| 371 |
+
# nodes=[0])
|
| 372 |
+
|
| 373 |
+
# if not self._open_loop:
|
| 374 |
+
# # we create a residual cost to be used as an attractor to the measured state on the first node
|
| 375 |
+
# # hard constraints injecting meas. states are pure EVIL!
|
| 376 |
+
# prb_state=self._prb.getState()
|
| 377 |
+
# full_state=prb_state.getVars()
|
| 378 |
+
# state_dim=prb_state.getBounds()[0].shape[0]
|
| 379 |
+
# meas_state=self._prb.createParameter(name="measured_state",
|
| 380 |
+
# dim=state_dim, nodes=0)
|
| 381 |
+
# self._prb.createResidual('meas_state_attractor', meas_state_attractor_weight * (full_state - meas_state),
|
| 382 |
+
# nodes=[0])
|
| 383 |
+
|
| 384 |
+
self._ti.finalize()
|
| 385 |
+
self._ti.bootstrap()
|
| 386 |
+
|
| 387 |
+
self._ti.init_inv_dyn_for_res() # we initialize some objects for sol. postprocessing purposes
|
| 388 |
+
self._ti.load_initial_guess()
|
| 389 |
+
|
| 390 |
+
self.n_dofs = self._get_ndofs() # after loading the URDF and creating the controller we
|
| 391 |
+
# know n_dofs -> we assign it (by default = None)
|
| 392 |
+
|
| 393 |
+
self.n_contacts = len(self._model.cmap.keys())
|
| 394 |
+
|
| 395 |
+
# remove variables bounds (before they were necessary to have a good
|
| 396 |
+
# quality bootstrap solution)
|
| 397 |
+
self._q_inf=np.zeros((self.nq(), 1))
|
| 398 |
+
self._q_inf[:, :]=np.inf
|
| 399 |
+
self._v_inf=np.zeros((self.nv(), 1))
|
| 400 |
+
self._v_inf[:, :]=np.inf
|
| 401 |
+
self._ti.model.q.setBounds(-self._q_inf, self._q_inf, nodes=0)
|
| 402 |
+
self._ti.model.v.setBounds(-self._v_inf, self._v_inf, nodes=0)
|
| 403 |
+
|
| 404 |
+
# self.horizon_anal = analyzer.ProblemAnalyzer(self._prb)
|
| 405 |
+
|
| 406 |
+
def get_file_paths(self):
|
| 407 |
+
# can be overriden by child
|
| 408 |
+
paths = super().get_file_paths()
|
| 409 |
+
return paths
|
| 410 |
+
|
| 411 |
+
def _get_quat_remap(self):
|
| 412 |
+
# overrides parent
|
| 413 |
+
return [1, 2, 3, 0] # mapping from robot quat. to Horizon's quaternion convention
|
| 414 |
+
|
| 415 |
+
def _zmp(self, model):
|
| 416 |
+
|
| 417 |
+
num = cs.SX([0, 0])
|
| 418 |
+
den = cs.SX([0])
|
| 419 |
+
pos_contact = dict()
|
| 420 |
+
force_val = dict()
|
| 421 |
+
|
| 422 |
+
q = cs.SX.sym('q', model.nq)
|
| 423 |
+
v = cs.SX.sym('v', model.nv)
|
| 424 |
+
a = cs.SX.sym('a', model.nv)
|
| 425 |
+
|
| 426 |
+
com = model.kd.centerOfMass()(q=q, v=v, a=a)['com']
|
| 427 |
+
|
| 428 |
+
n = cs.SX([0, 0, 1])
|
| 429 |
+
for c in model.fmap.keys():
|
| 430 |
+
pos_contact[c] = model.kd.fk(c)(q=q)['ee_pos']
|
| 431 |
+
force_val[c] = cs.SX.sym('force_val', 3)
|
| 432 |
+
num += (pos_contact[c][0:2] - com[0:2]) * cs.dot(force_val[c], n)
|
| 433 |
+
den += cs.dot(force_val[c], n)
|
| 434 |
+
|
| 435 |
+
zmp = com[0:2] + (num / den)
|
| 436 |
+
input_list = []
|
| 437 |
+
input_list.append(q)
|
| 438 |
+
input_list.append(v)
|
| 439 |
+
input_list.append(a)
|
| 440 |
+
|
| 441 |
+
for elem in force_val.values():
|
| 442 |
+
input_list.append(elem)
|
| 443 |
+
|
| 444 |
+
f = cs.Function('zmp', input_list, [zmp])
|
| 445 |
+
return f
|
| 446 |
+
|
| 447 |
+
def _add_zmp(self):
|
| 448 |
+
|
| 449 |
+
input_zmp = []
|
| 450 |
+
|
| 451 |
+
input_zmp.append(self._model.q)
|
| 452 |
+
input_zmp.append(self._model.v)
|
| 453 |
+
input_zmp.append(self._model.a)
|
| 454 |
+
|
| 455 |
+
for f_var in self._model.fmap.values():
|
| 456 |
+
input_zmp.append(f_var)
|
| 457 |
+
|
| 458 |
+
c_mean = cs.SX([0, 0, 0])
|
| 459 |
+
for c_name, f_var in self._model.fmap.items():
|
| 460 |
+
fk_c_pos = self._kin_dyn.fk(c_name)(q=self._model.q)['ee_pos']
|
| 461 |
+
c_mean += fk_c_pos
|
| 462 |
+
|
| 463 |
+
c_mean /= len(self._model.cmap.keys())
|
| 464 |
+
|
| 465 |
+
zmp_nominal_weight = 10.
|
| 466 |
+
zmp_fun = self._zmp(self._model)(*input_zmp)
|
| 467 |
+
|
| 468 |
+
if 'wheel_joint_1' in self._model.kd.joint_names():
|
| 469 |
+
zmp_residual = self._prb.createIntermediateResidual('zmp', zmp_nominal_weight * (zmp_fun[0:2] - c_mean[0:2]))
|
| 470 |
+
|
| 471 |
+
def _quaternion_multiply(self,
|
| 472 |
+
q1, q2):
|
| 473 |
+
x1, y1, z1, w1 = q1
|
| 474 |
+
x2, y2, z2, w2 = q2
|
| 475 |
+
w = w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2
|
| 476 |
+
x = w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2
|
| 477 |
+
y = w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2
|
| 478 |
+
z = w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2
|
| 479 |
+
return np.array([x, y, z, w])
|
| 480 |
+
|
| 481 |
+
def _get_continuous_jnt_names(self):
|
| 482 |
+
import xml.etree.ElementTree as ET
|
| 483 |
+
root = ET.fromstring(self.urdf)
|
| 484 |
+
continuous_joints = []
|
| 485 |
+
for joint in root.findall('joint'):
|
| 486 |
+
joint_type = joint.get('type')
|
| 487 |
+
if joint_type == 'continuous':
|
| 488 |
+
joint_name = joint.get('name')
|
| 489 |
+
continuous_joints.append(joint_name)
|
| 490 |
+
return continuous_joints
|
| 491 |
+
|
| 492 |
+
def _get_wheels_jnt_v_idxs(self, wheel_patterns: List[str]):
|
| 493 |
+
jnt_names=self._get_robot_jnt_names()
|
| 494 |
+
wheels_idxs=[]
|
| 495 |
+
for i in range(len(jnt_names)):
|
| 496 |
+
jnt_name=jnt_names[i]
|
| 497 |
+
for wheel_pattern in wheel_patterns:
|
| 498 |
+
if wheel_pattern in jnt_name:
|
| 499 |
+
wheels_idxs.append(i)
|
| 500 |
+
break
|
| 501 |
+
return wheels_idxs
|
| 502 |
+
|
| 503 |
+
def _get_jnt_id(self, jnt_name):
|
| 504 |
+
return self._kin_dyn.joint_iq(jnt_name)
|
| 505 |
+
|
| 506 |
+
def _init_rhc_task_cmds(self):
|
| 507 |
+
|
| 508 |
+
rhc_refs = HybridQuadRhcRefs(gait_manager=self._gm,
|
| 509 |
+
robot_index_shm=self.controller_index,
|
| 510 |
+
robot_index_view=0, # when using optimize_mem the view if always of shape 1x...
|
| 511 |
+
namespace=self.namespace,
|
| 512 |
+
safe=False,
|
| 513 |
+
verbose=self._verbose,
|
| 514 |
+
vlevel=VLevel.V2,
|
| 515 |
+
use_force_feedback=self._custom_opts["use_force_feedback"],
|
| 516 |
+
optimize_mem=True)
|
| 517 |
+
|
| 518 |
+
rhc_refs.run()
|
| 519 |
+
|
| 520 |
+
rhc_refs.rob_refs.set_jnts_remapping(jnts_remapping=self._to_controller)
|
| 521 |
+
rhc_refs.rob_refs.set_q_remapping(q_remapping=self._get_quat_remap())
|
| 522 |
+
|
| 523 |
+
rhc_refs.set_default_refs(p_ref=np.atleast_2d(self._base_init)[:, 0:3],
|
| 524 |
+
q_ref=np.atleast_2d(self._base_init)[:, 3:7])
|
| 525 |
+
|
| 526 |
+
return rhc_refs
|
| 527 |
+
|
| 528 |
+
def get_vertex_fnames_from_ti(self):
|
| 529 |
+
tasks=self._ti.task_list
|
| 530 |
+
contact_f_names=[]
|
| 531 |
+
for task in tasks:
|
| 532 |
+
if isinstance(task, ContactTask):
|
| 533 |
+
interaction_task=task.dynamics_tasks[0]
|
| 534 |
+
contact_f_names.append(interaction_task.vertex_frames[0])
|
| 535 |
+
return contact_f_names
|
| 536 |
+
|
| 537 |
+
def _get_contact_names(self):
|
| 538 |
+
# should get contact names from vertex frames
|
| 539 |
+
# list(self._ti.model.cmap.keys())
|
| 540 |
+
return self.get_vertex_fnames_from_ti()
|
| 541 |
+
|
| 542 |
+
def _get_robot_jnt_names(self):
|
| 543 |
+
|
| 544 |
+
joints_names = self._kin_dyn.joint_names()
|
| 545 |
+
to_be_removed = ["universe",
|
| 546 |
+
"reference",
|
| 547 |
+
"world",
|
| 548 |
+
"floating",
|
| 549 |
+
"floating_base"]
|
| 550 |
+
for name in to_be_removed:
|
| 551 |
+
if name in joints_names:
|
| 552 |
+
joints_names.remove(name)
|
| 553 |
+
|
| 554 |
+
return joints_names
|
| 555 |
+
|
| 556 |
+
def _get_ndofs(self):
|
| 557 |
+
return len(self._model.joint_names)
|
| 558 |
+
|
| 559 |
+
def nq(self):
|
| 560 |
+
return self._kin_dyn.nq()
|
| 561 |
+
|
| 562 |
+
def nv(self):
|
| 563 |
+
return self._kin_dyn.nv()
|
| 564 |
+
|
| 565 |
+
def _get_robot_mass(self):
|
| 566 |
+
|
| 567 |
+
return self._kin_dyn.mass()
|
| 568 |
+
|
| 569 |
+
def _get_root_full_q_from_sol(self, node_idx=1):
|
| 570 |
+
|
| 571 |
+
root_q_full=self._ti.solution['q'][0:7, node_idx].reshape(1, 7).astype(self._dtype)
|
| 572 |
+
|
| 573 |
+
np.nan_to_num(root_q_full, nan=1e3, posinf=1e3, neginf=-1e3, copy=False)
|
| 574 |
+
np.clip(a=root_q_full, a_min=-1e3, a_max=1e3, out=root_q_full)
|
| 575 |
+
|
| 576 |
+
return root_q_full
|
| 577 |
+
|
| 578 |
+
def _get_full_q_from_sol(self, node_idx=1):
|
| 579 |
+
|
| 580 |
+
return self._ti.solution['q'][:, node_idx].reshape(1, -1).astype(self._dtype)
|
| 581 |
+
|
| 582 |
+
def _get_root_twist_from_sol(self, node_idx=1):
|
| 583 |
+
# provided in world frame
|
| 584 |
+
twist_base_local=self._get_v_from_sol()[0:6, node_idx].reshape(1, 6)
|
| 585 |
+
# if world_aligned:
|
| 586 |
+
# q_root_rhc = self._get_root_full_q_from_sol(node_idx=node_idx)[:, 0:4]
|
| 587 |
+
# r_base_rhc=Rotation.from_quat(q_root_rhc.flatten()).as_matrix()
|
| 588 |
+
# twist_base_local[:, 0:3] = r_base_rhc @ twist_base_local[0, 0:3]
|
| 589 |
+
# twist_base_local[:, 3:6] = r_base_rhc @ twist_base_local[0, 3:6]
|
| 590 |
+
return twist_base_local
|
| 591 |
+
|
| 592 |
+
def _get_root_a_from_sol(self, node_idx=0):
|
| 593 |
+
# provided in world frame
|
| 594 |
+
a_base_local=self._get_a_from_sol()[0:6, node_idx].reshape(1, 6)
|
| 595 |
+
# if world_aligned:
|
| 596 |
+
# q_root_rhc = self._get_root_full_q_from_sol(node_idx=node_idx)[:, 0:4]
|
| 597 |
+
# r_base_rhc=Rotation.from_quat(q_root_rhc.flatten()).as_matrix()
|
| 598 |
+
# a_base_local[:, 0:3] = r_base_rhc @ a_base_local[0, 0:3]
|
| 599 |
+
# a_base_local[:, 3:6] = r_base_rhc @ v[0, 3:6]
|
| 600 |
+
return a_base_local
|
| 601 |
+
|
| 602 |
+
def _get_jnt_q_from_sol(self, node_idx=0,
|
| 603 |
+
reduce: bool = True,
|
| 604 |
+
clamp: bool = True):
|
| 605 |
+
|
| 606 |
+
full_jnts_q=self._ti.solution['q'][7:, node_idx:node_idx+1].reshape(1,-1).astype(self._dtype)
|
| 607 |
+
|
| 608 |
+
np.nan_to_num(full_jnts_q, nan=1e3, posinf=1e3, neginf=-1e3, copy=False) # in place
|
| 609 |
+
np.clip(a=full_jnts_q, a_max=1e3, a_min=-1e3, out=full_jnts_q) # in place
|
| 610 |
+
|
| 611 |
+
if self._custom_opts["replace_continuous_joints"] or (not reduce):
|
| 612 |
+
if clamp:
|
| 613 |
+
return np.fmod(full_jnts_q, 2*np.pi)
|
| 614 |
+
else:
|
| 615 |
+
return full_jnts_q
|
| 616 |
+
else:
|
| 617 |
+
cos_sin=full_jnts_q[:,self._continuous_joints_idxs].reshape(-1,2)
|
| 618 |
+
# copy rev joint vals
|
| 619 |
+
self._jnts_q_reduced[:, self._rev_joints_idxs_red]=np.fmod(full_jnts_q[:, self._rev_joints_idxs], 2*np.pi).reshape(1, -1)
|
| 620 |
+
# and continuous
|
| 621 |
+
self._jnts_q_reduced[:, self._continuous_joints_idxs_red]=np.arctan2(cos_sin[:, 1], cos_sin[:, 0]).reshape(1,-1)
|
| 622 |
+
return self._jnts_q_reduced
|
| 623 |
+
|
| 624 |
+
def _get_jnt_v_from_sol(self, node_idx=1):
|
| 625 |
+
|
| 626 |
+
jnt_v_sol=self._get_v_from_sol()[6:, node_idx].reshape(1,
|
| 627 |
+
self._nv_jnts)
|
| 628 |
+
np.nan_to_num(jnt_v_sol, nan=1e5, posinf=1e5, neginf=-1e5, copy=False) # in place
|
| 629 |
+
# np.clip(a=jnt_v_sol, a_max=1e5, a_min=-1e5, out=jnt_v_sol) # in place
|
| 630 |
+
|
| 631 |
+
return jnt_v_sol
|
| 632 |
+
|
| 633 |
+
def _get_jnt_a_from_sol(self, node_idx=1):
|
| 634 |
+
|
| 635 |
+
return self._get_a_from_sol()[6:, node_idx].reshape(1,
|
| 636 |
+
self._nv_jnts)
|
| 637 |
+
|
| 638 |
+
def _get_jnt_eff_from_sol(self, node_idx=0):
|
| 639 |
+
|
| 640 |
+
efforts_on_node = self._ti.eval_efforts_on_node(node_idx=node_idx)
|
| 641 |
+
|
| 642 |
+
# if self._custom_opts["only_vel_wheels"]:
|
| 643 |
+
|
| 644 |
+
jnt_efforts=efforts_on_node[6:, 0]
|
| 645 |
+
|
| 646 |
+
if self._custom_opts["only_vel_wheels"] and self._wheels_idxs_v:
|
| 647 |
+
jnt_efforts[self._wheels_idxs_v]=0.0
|
| 648 |
+
|
| 649 |
+
return jnt_efforts.reshape(1,
|
| 650 |
+
self._nv_jnts).astype(self._dtype)
|
| 651 |
+
|
| 652 |
+
def _get_rhc_cost(self):
|
| 653 |
+
|
| 654 |
+
return self._ti.solution["opt_cost"]
|
| 655 |
+
|
| 656 |
+
def _get_rhc_constr_viol(self):
|
| 657 |
+
|
| 658 |
+
return self._ti.solution["residual_norm"]
|
| 659 |
+
|
| 660 |
+
def _get_rhc_nodes_cost(self):
|
| 661 |
+
|
| 662 |
+
cost = self._ti.solver_rti.getCostValOnNodes()
|
| 663 |
+
return cost.reshape((1, -1))
|
| 664 |
+
|
| 665 |
+
def _get_rhc_nodes_constr_viol(self):
|
| 666 |
+
|
| 667 |
+
constr_viol = self._ti.solver_rti.getConstrValOnNodes()
|
| 668 |
+
return constr_viol.reshape((1, -1))
|
| 669 |
+
|
| 670 |
+
def _get_rhc_niter_to_sol(self):
|
| 671 |
+
|
| 672 |
+
return self._ti.solution["n_iter2sol"]
|
| 673 |
+
|
| 674 |
+
def _set_ig(self):
|
| 675 |
+
|
| 676 |
+
shift_num = -1 # shift data by one node
|
| 677 |
+
|
| 678 |
+
x_opt = self._ti.solution['x_opt']
|
| 679 |
+
u_opt = self._ti.solution['u_opt']
|
| 680 |
+
|
| 681 |
+
# building ig for state
|
| 682 |
+
xig = np.roll(x_opt,
|
| 683 |
+
shift_num, axis=1) # rolling state sol.
|
| 684 |
+
for i in range(abs(shift_num)):
|
| 685 |
+
# state on last node is copied to the elements
|
| 686 |
+
# which are "lost" during the shift operation
|
| 687 |
+
xig[:, -1 - i] = x_opt[:, -1]
|
| 688 |
+
# building ig for inputs
|
| 689 |
+
uig = np.roll(u_opt,
|
| 690 |
+
shift_num, axis=1) # rolling state sol.
|
| 691 |
+
for i in range(abs(shift_num)):
|
| 692 |
+
# state on last node is copied to the elements
|
| 693 |
+
# which are "lost" during the shift operation
|
| 694 |
+
uig[:, -1 - i] = u_opt[:, -1]
|
| 695 |
+
|
| 696 |
+
# assigning ig
|
| 697 |
+
self._prb.getState().setInitialGuess(xig)
|
| 698 |
+
self._prb.getInput().setInitialGuess(uig)
|
| 699 |
+
|
| 700 |
+
return xig, uig
|
| 701 |
+
|
| 702 |
+
def _update_open_loop(self):
|
| 703 |
+
|
| 704 |
+
xig, _ = self._set_ig()
|
| 705 |
+
|
| 706 |
+
q_state, v_state, a_state=self._set_is_open()
|
| 707 |
+
|
| 708 |
+
# robot_state=xig[:, 0]
|
| 709 |
+
# # open loop update:
|
| 710 |
+
# self._prb.setInitialState(x0=robot_state) # (xig has been shifted, so node 0
|
| 711 |
+
# # is node 1 in the last opt solution)
|
| 712 |
+
|
| 713 |
+
return q_state, v_state, a_state
|
| 714 |
+
|
| 715 |
+
def _update_closed_loop(self):
|
| 716 |
+
|
| 717 |
+
# set initial guess for controller
|
| 718 |
+
xig, _ = self._set_ig()
|
| 719 |
+
# set initial state
|
| 720 |
+
q_state=None
|
| 721 |
+
v_state=None
|
| 722 |
+
a_state=None
|
| 723 |
+
if self._custom_opts["adaptive_is"]:
|
| 724 |
+
# adaptive closed loop
|
| 725 |
+
q_state, v_state, a_state=self._set_is_adaptive()
|
| 726 |
+
elif self._custom_opts["fully_closed"]:
|
| 727 |
+
q_state, v_state, a_state=self._set_is_full()
|
| 728 |
+
elif self._custom_opts["closed_partial"]:
|
| 729 |
+
q_state, v_state, a_state=self._set_is_partial()
|
| 730 |
+
else:
|
| 731 |
+
Journal.log(self.__class__.__name__,
|
| 732 |
+
"_update_closed_loop",
|
| 733 |
+
"Neither adaptive_is, fully_closed, or closed_partial.",
|
| 734 |
+
LogType.EXCEP,
|
| 735 |
+
throw_when_excep = False)
|
| 736 |
+
q_state, v_state, a_state=self._set_is()
|
| 737 |
+
|
| 738 |
+
return q_state, v_state, a_state
|
| 739 |
+
|
| 740 |
+
def _set_is_open(self):
|
| 741 |
+
|
| 742 |
+
# overriding states with rhc data
|
| 743 |
+
q_full_root=self._get_root_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 744 |
+
q_jnts=self._get_jnt_q_from_sol(node_idx=1, reduce=False).reshape(-1, 1)
|
| 745 |
+
|
| 746 |
+
twist_root=self._get_root_twist_from_sol(node_idx=1).reshape(-1, 1)
|
| 747 |
+
v_jnts=self._get_jnt_v_from_sol(node_idx=1).reshape(-1, 1)
|
| 748 |
+
|
| 749 |
+
# rhc variables to be set
|
| 750 |
+
q=self._prb.getVariables("q") # .setBounds()
|
| 751 |
+
root_q_full_rhc=q[0:7] # root full q
|
| 752 |
+
jnts_q_rhc=q[7:] # jnts q
|
| 753 |
+
vel=self._prb.getVariables("v")
|
| 754 |
+
root_twist_rhc=vel[0:6] # lin v.
|
| 755 |
+
jnts_v_rhc=vel[6:] # jnts v
|
| 756 |
+
|
| 757 |
+
self.rhc_refs.set_alpha(alpha=1.0) # fully open
|
| 758 |
+
|
| 759 |
+
# close state on known quantities
|
| 760 |
+
root_q_full_rhc.setBounds(lb=q_full_root,
|
| 761 |
+
ub=q_full_root, nodes=0)
|
| 762 |
+
jnts_q_rhc.setBounds(lb=q_jnts,
|
| 763 |
+
ub=q_jnts, nodes=0)
|
| 764 |
+
root_twist_rhc.setBounds(lb=twist_root,
|
| 765 |
+
ub=twist_root, nodes=0)
|
| 766 |
+
jnts_v_rhc.setBounds(lb=v_jnts,
|
| 767 |
+
ub=v_jnts, nodes=0)
|
| 768 |
+
|
| 769 |
+
# return state used for feedback
|
| 770 |
+
q_state=np.concatenate((q_full_root, q_jnts),
|
| 771 |
+
axis=0)
|
| 772 |
+
v_state=np.concatenate((twist_root, v_jnts),
|
| 773 |
+
axis=0)
|
| 774 |
+
|
| 775 |
+
return (q_state, v_state, None)
|
| 776 |
+
|
| 777 |
+
def _set_is_full(self):
|
| 778 |
+
|
| 779 |
+
# measurements
|
| 780 |
+
q_full_root = self.robot_state.root_state.get(data_type="q_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 781 |
+
v_root = self.robot_state.root_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 782 |
+
omega = self.robot_state.root_state.get(data_type="omega", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 783 |
+
a_root = self.robot_state.root_state.get(data_type="a_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 784 |
+
|
| 785 |
+
q_jnts = self.robot_state.jnts_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 786 |
+
v_jnts = self.robot_state.jnts_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 787 |
+
a_jnts = self.robot_state.jnts_state.get(data_type="a", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 788 |
+
|
| 789 |
+
if (not len(self._continuous_joints)==0): # we need do expand some meas. rev jnts to So2
|
| 790 |
+
self._jnts_q_expanded[self._rev_joints_idxs, :]=q_jnts[self._rev_joints_idxs_red ,:]
|
| 791 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_cos, :]=np.cos(q_jnts[self._continuous_joints_idxs_red, :]) # cos
|
| 792 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_sin, :]=np.sin(q_jnts[self._continuous_joints_idxs_red, :]) # sin
|
| 793 |
+
q_jnts=self._jnts_q_expanded.reshape(-1,1)
|
| 794 |
+
|
| 795 |
+
# rhc variables to be set
|
| 796 |
+
q=self._prb.getVariables("q") # .setBounds()
|
| 797 |
+
root_full_q_rhc=q[0:7] # root p
|
| 798 |
+
jnts_q_rhc=q[7:] # jnts q
|
| 799 |
+
vel=self._prb.getVariables("v")
|
| 800 |
+
root_v_rhc=vel[0:3] # lin v.
|
| 801 |
+
root_omega_rhc=vel[3:6] # omega
|
| 802 |
+
jnts_v_rhc=vel[6:] # jnts v
|
| 803 |
+
acc=self._prb.getVariables("a")
|
| 804 |
+
lin_a_prb=acc[0:3] # lin acc
|
| 805 |
+
|
| 806 |
+
self.rhc_refs.set_alpha(alpha=0.0) # non-adaptive
|
| 807 |
+
|
| 808 |
+
root_full_q_rhc.setBounds(lb=q_full_root,
|
| 809 |
+
ub=q_full_root, nodes=0)
|
| 810 |
+
jnts_q_rhc.setBounds(lb=q_jnts,
|
| 811 |
+
ub=q_jnts, nodes=0)
|
| 812 |
+
root_v_rhc.setBounds(lb=v_root,
|
| 813 |
+
ub=v_root, nodes=0) # leaving lin v of the base free (estimated from constraints)
|
| 814 |
+
root_omega_rhc.setBounds(lb=omega,
|
| 815 |
+
ub=omega, nodes=0)
|
| 816 |
+
jnts_v_rhc.setBounds(lb=v_jnts,
|
| 817 |
+
ub=v_jnts, nodes=0)
|
| 818 |
+
if self._custom_opts["lin_a_feedback"]:
|
| 819 |
+
# write base lin 13793197 from meas
|
| 820 |
+
lin_a_prb.setBounds(lb=a_root[0:3, :],
|
| 821 |
+
ub=a_root[0:3, :],
|
| 822 |
+
nodes=0)
|
| 823 |
+
|
| 824 |
+
# return state used for feedback
|
| 825 |
+
q_state=np.concatenate((q_full_root, q_jnts),
|
| 826 |
+
axis=0)
|
| 827 |
+
v_state=np.concatenate((v_root, omega, v_jnts),
|
| 828 |
+
axis=0)
|
| 829 |
+
a_state=np.concatenate((a_root, a_jnts),
|
| 830 |
+
axis=0)
|
| 831 |
+
|
| 832 |
+
return (q_state, v_state, a_state)
|
| 833 |
+
|
| 834 |
+
def _set_is_partial(self):
|
| 835 |
+
|
| 836 |
+
# measurements
|
| 837 |
+
p_root = self.robot_state.root_state.get(data_type="p", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 838 |
+
q_root = self.robot_state.root_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 839 |
+
v_root = self.robot_state.root_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 840 |
+
omega = self.robot_state.root_state.get(data_type="omega", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 841 |
+
a_root = self.robot_state.root_state.get(data_type="a_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 842 |
+
|
| 843 |
+
q_jnts = self.robot_state.jnts_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 844 |
+
v_jnts = self.robot_state.jnts_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 845 |
+
a_jnts = self.robot_state.jnts_state.get(data_type="a", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 846 |
+
|
| 847 |
+
if (not len(self._continuous_joints)==0): # we need do expand some meas. rev jnts to So2
|
| 848 |
+
self._jnts_q_expanded[self._rev_joints_idxs, :]=q_jnts[self._rev_joints_idxs_red ,:]
|
| 849 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_cos, :]=np.cos(q_jnts[self._continuous_joints_idxs_red, :]) # cos
|
| 850 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_sin, :]=np.sin(q_jnts[self._continuous_joints_idxs_red, :]) # sin
|
| 851 |
+
q_jnts=self._jnts_q_expanded.reshape(-1,1)
|
| 852 |
+
|
| 853 |
+
# overriding states with rhc data (-> all overridden state are open looop)
|
| 854 |
+
root_q_full_from_rhc=self._get_root_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 855 |
+
root_p_from_rhc=root_q_full_from_rhc[0:3, :]
|
| 856 |
+
p_root[:, :]=root_p_from_rhc # position is always open loop
|
| 857 |
+
if not self._custom_opts["estimate_v_root"]:
|
| 858 |
+
v_root[:, :]=self._get_root_twist_from_sol(node_idx=1)[:, 0:3].reshape(-1, 1)
|
| 859 |
+
# override v jnts with the ones from controller
|
| 860 |
+
if not self._custom_opts["use_jnt_v_feedback"]:
|
| 861 |
+
v_jnts[:, :]=self._get_jnt_v_from_sol(node_idx=1).reshape(-1, 1)
|
| 862 |
+
# v_jnts[:, :]=self._get_jnt_v_from_sol(node_idx=1).reshape(-1, 1)
|
| 863 |
+
# root_twist_from_rhc=self._get_root_twist_from_sol(node_idx=1)
|
| 864 |
+
# root_v_from_rhc=root_twist_from_rhc[:, 0:3].reshape(-1, 1)
|
| 865 |
+
# root_omega_from_rhc=root_twist_from_rhc[:, 3:6].reshape(-1, 1)
|
| 866 |
+
# jnt_q_from_rhc=self._get_jnt_q_from_sol(node_idx=1,reduce=False,clamp=False).reshape(-1, 1)
|
| 867 |
+
# jnt_v_from_rhc=self._get_jnt_v_from_sol(node_idx=1).reshape(-1, 1)
|
| 868 |
+
|
| 869 |
+
# rhc variables to be set
|
| 870 |
+
q=self._prb.getVariables("q") # .setBounds()
|
| 871 |
+
root_p_rhc=q[0:3] # root p
|
| 872 |
+
root_q_rhc=q[3:7] # root orientation
|
| 873 |
+
jnts_q_rhc=q[7:] # jnts q
|
| 874 |
+
vel=self._prb.getVariables("v")
|
| 875 |
+
root_v_rhc=vel[0:3] # lin v.
|
| 876 |
+
root_omega_rhc=vel[3:6] # omega
|
| 877 |
+
jnts_v_rhc=vel[6:] # jnts v
|
| 878 |
+
acc=self._prb.getVariables("a")
|
| 879 |
+
lin_a_prb=acc[0:3] # lin acc
|
| 880 |
+
|
| 881 |
+
self.rhc_refs.set_alpha(alpha=0.0) # non-adaptive
|
| 882 |
+
|
| 883 |
+
root_p_rhc.setBounds(lb=p_root,
|
| 884 |
+
ub=p_root, nodes=0)
|
| 885 |
+
root_q_rhc.setBounds(lb=q_root,
|
| 886 |
+
ub=q_root, nodes=0)
|
| 887 |
+
jnts_q_rhc.setBounds(lb=q_jnts,
|
| 888 |
+
ub=q_jnts, nodes=0)
|
| 889 |
+
if self._custom_opts["estimate_v_root"]:
|
| 890 |
+
root_v_rhc.setBounds(lb=-self._v_inf[0:3],
|
| 891 |
+
ub=self._v_inf[0:3], nodes=0) # leaving lin v of the base free (estimated from constraints)
|
| 892 |
+
else: # get it from controller
|
| 893 |
+
root_v_rhc.setBounds(lb=v_root,
|
| 894 |
+
ub=v_root, nodes=0)
|
| 895 |
+
root_omega_rhc.setBounds(lb=omega,
|
| 896 |
+
ub=omega, nodes=0)
|
| 897 |
+
jnts_v_rhc.setBounds(lb=v_jnts,
|
| 898 |
+
ub=v_jnts, nodes=0)
|
| 899 |
+
if self._custom_opts["lin_a_feedback"]:
|
| 900 |
+
# write base lin 13793197 from meas
|
| 901 |
+
lin_a_prb.setBounds(lb=a_root[0:3, :],
|
| 902 |
+
ub=a_root[0:3, :],
|
| 903 |
+
nodes=0)
|
| 904 |
+
|
| 905 |
+
# return state used for feedback
|
| 906 |
+
q_state=np.concatenate((p_root, q_root, q_jnts),
|
| 907 |
+
axis=0)
|
| 908 |
+
v_state=np.concatenate((v_root, omega, v_jnts),
|
| 909 |
+
axis=0)
|
| 910 |
+
a_state=np.concatenate((a_root, a_jnts),
|
| 911 |
+
axis=0)
|
| 912 |
+
|
| 913 |
+
return (q_state, v_state, a_state)
|
| 914 |
+
|
| 915 |
+
def _set_is_adaptive(self):
|
| 916 |
+
|
| 917 |
+
# measurements
|
| 918 |
+
p_root = self.robot_state.root_state.get(data_type="p", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 919 |
+
q_root = self.robot_state.root_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 920 |
+
v_root = self.robot_state.root_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 921 |
+
omega = self.robot_state.root_state.get(data_type="omega", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 922 |
+
a_root = self.robot_state.root_state.get(data_type="a_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 923 |
+
|
| 924 |
+
q_jnts = self.robot_state.jnts_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 925 |
+
v_jnts = self.robot_state.jnts_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 926 |
+
a_jnts = self.robot_state.jnts_state.get(data_type="a", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 927 |
+
|
| 928 |
+
# rhc variables to be set
|
| 929 |
+
q=self._prb.getVariables("q") # .setBounds()
|
| 930 |
+
root_p_rhc=q[0:3] # root p
|
| 931 |
+
root_q_rhc=q[3:7] # root orientation
|
| 932 |
+
jnts_q_rhc=q[7:] # jnts q
|
| 933 |
+
vel=self._prb.getVariables("v")
|
| 934 |
+
root_v_rhc=vel[0:3] # lin v.
|
| 935 |
+
root_omega_rhc=vel[3:6] # omega
|
| 936 |
+
jnts_v_rhc=vel[6:] # jnts v
|
| 937 |
+
acc=self._prb.getVariables("a")
|
| 938 |
+
lin_a_prb=acc[0:3] # lin acc
|
| 939 |
+
|
| 940 |
+
# getting prediction defects
|
| 941 |
+
root_q_delta=self.rhc_pred_delta.root_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 942 |
+
jnt_q_delta=self.rhc_pred_delta.jnts_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 943 |
+
jnt_v_delta=self.rhc_pred_delta.jnts_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 944 |
+
v_root_delta = self.rhc_pred_delta.root_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 945 |
+
omega_root_delta = self.rhc_pred_delta.root_state.get(data_type="omega", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 946 |
+
a_root_delta = self.rhc_pred_delta.root_state.get(data_type="a_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 947 |
+
|
| 948 |
+
# close state on known quantities, estimate some (e.g. lin vel) and
|
| 949 |
+
# open loop if thing start to explode
|
| 950 |
+
alpha_now=1.0
|
| 951 |
+
delta=0.0
|
| 952 |
+
if self._custom_opts["alpha_from_outside"]:
|
| 953 |
+
alpha_now=self.rhc_refs.get_alpha()
|
| 954 |
+
else: # "autotuned" alpha
|
| 955 |
+
if self._custom_opts["estimate_v_root"]: # we copmute delta based on jnt v (since we use meas.)
|
| 956 |
+
delta=np.max(np.abs(jnt_v_delta))
|
| 957 |
+
else:
|
| 958 |
+
delta=np.max(np.abs(omega_root_delta))
|
| 959 |
+
# fail_idx=self._get_failure_index()
|
| 960 |
+
# fail_idx=self._get_explosion_idx()/self._fail_idx_thresh
|
| 961 |
+
alpha_now=(np.tanh(2*self._alpha_half*(delta-self._alpha_half))+1)/2.0
|
| 962 |
+
|
| 963 |
+
bound_relaxation=-np.log(1-alpha_now+1e-16) # [~0, ~inf] if alpha_now [0, 1]
|
| 964 |
+
self.rhc_refs.set_alpha(alpha=alpha_now) # also writes on shared mem for db
|
| 965 |
+
self.rhc_refs.set_bound_relax(bound_relax=bound_relaxation) # also writes on shared mem for db
|
| 966 |
+
|
| 967 |
+
self._alphas_q_root[:]=alpha_now # for now single alpha for everything
|
| 968 |
+
self._alphas_q_jnts[:]=alpha_now
|
| 969 |
+
self._alphas_twist_root[:]=alpha_now
|
| 970 |
+
self._alphas_v_jnts[:]=alpha_now
|
| 971 |
+
self._alphas_a[:]=alpha_now
|
| 972 |
+
if not self._custom_opts["estimate_v_root"]:
|
| 973 |
+
self._alphas_twist_root[0:3]=1.0 # open
|
| 974 |
+
self._alphas_v_jnts[:]=1.0 # open
|
| 975 |
+
|
| 976 |
+
# position is always open loop
|
| 977 |
+
root_q_full_from_rhc=self._get_root_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 978 |
+
root_p_from_rhc=root_q_full_from_rhc[0:3, :]
|
| 979 |
+
p_root[:, :]=root_p_from_rhc
|
| 980 |
+
|
| 981 |
+
# expaning meas q if continuous joints
|
| 982 |
+
if (not len(self._continuous_joints)==0): # we need do expand some meas. rev jnts to So2
|
| 983 |
+
self._jnts_q_expanded[self._rev_joints_idxs, :]=q_jnts[self._rev_joints_idxs_red ,:]
|
| 984 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_cos, :]=np.cos(q_jnts[self._continuous_joints_idxs_red, :]) # cos
|
| 985 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_sin, :]=np.sin(q_jnts[self._continuous_joints_idxs_red, :]) # sin
|
| 986 |
+
|
| 987 |
+
# continous joints position is always open loop, but we need a delta vector of matching dimension
|
| 988 |
+
q_jnts_from_rhc=self._get_jnt_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 989 |
+
|
| 990 |
+
self._jnts_q_delta_expanded[self._rev_joints_idxs, :]=jnt_q_delta[self._rev_joints_idxs_red ,:]
|
| 991 |
+
|
| 992 |
+
self._jnts_q_delta_expanded[self._continuous_joints_idxs_cos, :]=\
|
| 993 |
+
np.cos(q_jnts_from_rhc[self._continuous_joints_idxs_red, :]) - \
|
| 994 |
+
np.cos(q_jnts[self._continuous_joints_idxs_red, :])
|
| 995 |
+
self._jnts_q_delta_expanded[self._continuous_joints_idxs_sin, :]=\
|
| 996 |
+
np.sin(q_jnts_from_rhc[self._continuous_joints_idxs_red, :]) - \
|
| 997 |
+
np.sin(q_jnts[self._continuous_joints_idxs_red, :])
|
| 998 |
+
|
| 999 |
+
q_jnts=self._jnts_q_expanded.reshape(-1,1) # overriting with expanded jnts
|
| 1000 |
+
jnt_q_delta=self._jnts_q_delta_expanded.reshape(-1, 1) # overriting with expanded jnts
|
| 1001 |
+
|
| 1002 |
+
self._alphas_q_jnts[self._continuous_joints_idxs_cos, :]=1.0 # open loop
|
| 1003 |
+
self._alphas_q_jnts[self._continuous_joints_idxs_sin, :]=1.0 # open loop
|
| 1004 |
+
|
| 1005 |
+
# self._alphas_v_jnts[self._continuous_joints_idxs_red, :]=0.0 # open loop
|
| 1006 |
+
|
| 1007 |
+
root_p_rhc.setBounds(lb=p_root,
|
| 1008 |
+
ub=p_root, nodes=0)
|
| 1009 |
+
root_q_rhc.setBounds(lb=q_root+self._alphas_q_root[3:7]*root_q_delta,
|
| 1010 |
+
ub=q_root+self._alphas_q_root[3:7]*root_q_delta, nodes=0)
|
| 1011 |
+
jnts_q_rhc.setBounds(lb=q_jnts+self._alphas_q_jnts*jnt_q_delta,
|
| 1012 |
+
ub=q_jnts+self._alphas_q_jnts*jnt_q_delta, nodes=0)
|
| 1013 |
+
if self._custom_opts["estimate_v_root"]:
|
| 1014 |
+
root_v_rhc.setBounds(lb=-self._v_inf[0:3],
|
| 1015 |
+
ub=self._v_inf[0:3], nodes=0)
|
| 1016 |
+
else:
|
| 1017 |
+
root_v_rhc.setBounds(lb=v_root+self._alphas_twist_root[0:3, :]*v_root_delta,
|
| 1018 |
+
ub=v_root+self._alphas_twist_root[0:3, :]*v_root_delta, nodes=0)
|
| 1019 |
+
root_omega_rhc.setBounds(lb=omega+self._alphas_twist_root[3:6, :]*omega_root_delta,
|
| 1020 |
+
ub=omega+self._alphas_twist_root[3:6, :]*omega_root_delta, nodes=0)
|
| 1021 |
+
jnts_v_rhc.setBounds(lb=v_jnts+self._alphas_v_jnts*jnt_v_delta,
|
| 1022 |
+
ub=v_jnts+self._alphas_v_jnts*jnt_v_delta, nodes=0)
|
| 1023 |
+
if self._custom_opts["lin_a_feedback"]:
|
| 1024 |
+
lin_a_prb.setBounds(lb=a_root[0:3, :]+self._alphas_a[0:3]*a_root_delta[0:3, :],
|
| 1025 |
+
ub=a_root[0:3, :]+self._alphas_a[0:3]*a_root_delta[0:3, :],
|
| 1026 |
+
nodes=0)
|
| 1027 |
+
|
| 1028 |
+
# return state used for feedback
|
| 1029 |
+
q_state=np.concatenate((p_root, q_root, q_jnts),
|
| 1030 |
+
axis=0)
|
| 1031 |
+
v_state=np.concatenate((v_root, omega, v_jnts),
|
| 1032 |
+
axis=0)
|
| 1033 |
+
a_state=np.concatenate((a_root, a_jnts),
|
| 1034 |
+
axis=0)
|
| 1035 |
+
|
| 1036 |
+
return (q_state, v_state, a_state)
|
| 1037 |
+
|
| 1038 |
+
def _solve(self):
|
| 1039 |
+
|
| 1040 |
+
if self._debug:
|
| 1041 |
+
return self._db_solve()
|
| 1042 |
+
else:
|
| 1043 |
+
return self._min_solve()
|
| 1044 |
+
|
| 1045 |
+
def _min_solve(self):
|
| 1046 |
+
# minimal solve version -> no debug
|
| 1047 |
+
robot_qstate=None
|
| 1048 |
+
robot_vstate=None
|
| 1049 |
+
robot_astate=None
|
| 1050 |
+
if self._open_loop:
|
| 1051 |
+
robot_qstate, robot_vstate, robot_astate = self._update_open_loop() # updates the TO ig and
|
| 1052 |
+
# initial conditions using data from the solution itself
|
| 1053 |
+
else:
|
| 1054 |
+
robot_qstate, robot_vstate, robot_astate = self._update_closed_loop() # updates the TO ig and
|
| 1055 |
+
# initial conditions using robot measurements
|
| 1056 |
+
|
| 1057 |
+
self._pm.shift() # shifts phases of one dt
|
| 1058 |
+
if self._refs_in_hor_frame:
|
| 1059 |
+
# q_base=self.robot_state.root_state.get(data_type="q",
|
| 1060 |
+
# robot_idxs=self.controller_index).reshape(-1, 1)
|
| 1061 |
+
# q_full=self._get_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 1062 |
+
# using internal base pose from rhc. in case of closed loop, it will be the meas state
|
| 1063 |
+
force_norm=None
|
| 1064 |
+
if self._custom_opts["use_force_feedback"]:
|
| 1065 |
+
contact_forces=self.robot_state.contact_wrenches.get(data_type="f",
|
| 1066 |
+
robot_idxs=self.controller_index_np,
|
| 1067 |
+
contact_name=None).reshape(self.n_contacts,3)
|
| 1068 |
+
force_norm=np.linalg.norm(contact_forces, axis=1)
|
| 1069 |
+
self.rhc_refs.step(qstate=robot_qstate, vstate=robot_vstate,
|
| 1070 |
+
force_norm=force_norm)
|
| 1071 |
+
else:
|
| 1072 |
+
self.rhc_refs.step()
|
| 1073 |
+
|
| 1074 |
+
try:
|
| 1075 |
+
converged = self._ti.rti() # solves the problem
|
| 1076 |
+
self.sol_counter = self.sol_counter + 1
|
| 1077 |
+
return not self._check_rhc_failure()
|
| 1078 |
+
except Exception as e: # fail in case of exceptions
|
| 1079 |
+
return False
|
| 1080 |
+
|
| 1081 |
+
def _db_solve(self):
|
| 1082 |
+
|
| 1083 |
+
self._timer_start = time.perf_counter()
|
| 1084 |
+
|
| 1085 |
+
robot_qstate=None
|
| 1086 |
+
robot_vstate=None
|
| 1087 |
+
robot_astate=None
|
| 1088 |
+
if self._open_loop:
|
| 1089 |
+
robot_qstate, robot_vstate, robot_astate = self._update_open_loop() # updates the TO ig and
|
| 1090 |
+
# initial conditions using data from the solution itself
|
| 1091 |
+
else:
|
| 1092 |
+
robot_qstate, robot_vstate, robot_astate = self._update_closed_loop() # updates the TO ig and
|
| 1093 |
+
# initial conditions using robot measurements
|
| 1094 |
+
|
| 1095 |
+
self._prb_update_time = time.perf_counter()
|
| 1096 |
+
self._pm.shift() # shifts phases of one dt
|
| 1097 |
+
self._phase_shift_time = time.perf_counter()
|
| 1098 |
+
|
| 1099 |
+
if self._refs_in_hor_frame:
|
| 1100 |
+
# q_base=self.robot_state.root_state.get(data_type="q",
|
| 1101 |
+
# robot_idxs=self.controller_index).reshape(-1, 1)
|
| 1102 |
+
# q_full=self._get_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 1103 |
+
# using internal base pose from rhc. in case of closed loop, it will be the meas state
|
| 1104 |
+
force_norm=None
|
| 1105 |
+
if self._custom_opts["use_force_feedback"]:
|
| 1106 |
+
contact_forces=self.robot_state.contact_wrenches.get(data_type="f",
|
| 1107 |
+
robot_idxs=self.controller_index_np,
|
| 1108 |
+
contact_name=None).reshape(self.n_contacts,3)
|
| 1109 |
+
force_norm=np.linalg.norm(contact_forces, axis=1)
|
| 1110 |
+
self.rhc_refs.step(qstate=robot_qstate, vstate=robot_vstate,
|
| 1111 |
+
force_norm=force_norm)
|
| 1112 |
+
else:
|
| 1113 |
+
self.rhc_refs.step()
|
| 1114 |
+
|
| 1115 |
+
self._task_ref_update_time = time.perf_counter()
|
| 1116 |
+
|
| 1117 |
+
try:
|
| 1118 |
+
converged = self._ti.rti() # solves the problem
|
| 1119 |
+
self._rti_time = time.perf_counter()
|
| 1120 |
+
self.sol_counter = self.sol_counter + 1
|
| 1121 |
+
self._update_db_data()
|
| 1122 |
+
return not self._check_rhc_failure()
|
| 1123 |
+
except Exception as e: # fail in case of exceptions
|
| 1124 |
+
if self._verbose:
|
| 1125 |
+
exception = f"Rti() for controller {self.controller_index} failed" + \
|
| 1126 |
+
f" with exception{type(e).__name__}"
|
| 1127 |
+
Journal.log(self.__class__.__name__,
|
| 1128 |
+
"solve",
|
| 1129 |
+
exception,
|
| 1130 |
+
LogType.EXCEP,
|
| 1131 |
+
throw_when_excep = False)
|
| 1132 |
+
self._update_db_data()
|
| 1133 |
+
return False
|
| 1134 |
+
|
| 1135 |
+
def _get_fail_idx(self):
|
| 1136 |
+
|
| 1137 |
+
self._explosion_idx_buffer[:, self._expl_idx_buffer_counter]=self._get_explosion_idx()
|
| 1138 |
+
self._expl_idx_buffer_counter+=1
|
| 1139 |
+
self._expl_idx_counter+=1
|
| 1140 |
+
if self._expl_idx_counter%self._expl_idx_window_size==0:
|
| 1141 |
+
self._expl_idx_buffer_counter=0 # restart from 0
|
| 1142 |
+
|
| 1143 |
+
running_avrg=np.mean(self._explosion_idx_buffer).item()
|
| 1144 |
+
|
| 1145 |
+
return running_avrg
|
| 1146 |
+
|
| 1147 |
+
def _get_explosion_idx(self):
|
| 1148 |
+
explosion_index = self._get_rhc_constr_viol() + self._get_rhc_cost()*self._fail_idx_scale
|
| 1149 |
+
return explosion_index
|
| 1150 |
+
|
| 1151 |
+
def _update_db_data(self):
|
| 1152 |
+
|
| 1153 |
+
self._profiling_data_dict["problem_update_dt"] = self._prb_update_time - self._timer_start
|
| 1154 |
+
self._profiling_data_dict["phases_shift_dt"] = self._phase_shift_time - self._prb_update_time
|
| 1155 |
+
self._profiling_data_dict["task_ref_update"] = self._task_ref_update_time - self._phase_shift_time
|
| 1156 |
+
self._profiling_data_dict["rti_solve_dt"] = self._rti_time - self._task_ref_update_time
|
| 1157 |
+
self.rhc_costs.update(self._ti.solver_rti.getCostsValues())
|
| 1158 |
+
self.rhc_constr.update(self._ti.solver_rti.getConstraintsValues())
|
| 1159 |
+
|
| 1160 |
+
def _reset(self):
|
| 1161 |
+
|
| 1162 |
+
# reset task interface (ig, solvers, etc..) +
|
| 1163 |
+
# phase manager and sets bootstap as solution
|
| 1164 |
+
self._gm.reset()
|
| 1165 |
+
self._explosion_idx_buffer[:, :]=self._get_explosion_idx() # reset with data from reset solution
|
| 1166 |
+
self._expl_idx_counter=0.0
|
| 1167 |
+
self._expl_idx_buffer_counter=0
|
| 1168 |
+
|
| 1169 |
+
def _get_cost_data(self):
|
| 1170 |
+
|
| 1171 |
+
cost_dict = self._ti.solver_rti.getCostsValues()
|
| 1172 |
+
cost_names = list(cost_dict.keys())
|
| 1173 |
+
cost_dims = [1] * len(cost_names) # costs are always scalar
|
| 1174 |
+
return cost_names, cost_dims
|
| 1175 |
+
|
| 1176 |
+
def _get_constr_data(self):
|
| 1177 |
+
|
| 1178 |
+
constr_dict = self._ti.solver_rti.getConstraintsValues()
|
| 1179 |
+
constr_names = list(constr_dict.keys())
|
| 1180 |
+
constr_dims = [-1] * len(constr_names)
|
| 1181 |
+
i = 0
|
| 1182 |
+
for constr in constr_dict:
|
| 1183 |
+
constr_val = constr_dict[constr]
|
| 1184 |
+
constr_shape = constr_val.shape
|
| 1185 |
+
constr_dims[i] = constr_shape[0]
|
| 1186 |
+
i+=1
|
| 1187 |
+
return constr_names, constr_dims
|
| 1188 |
+
|
| 1189 |
+
def _get_q_from_sol(self):
|
| 1190 |
+
full_q=self._ti.solution['q'].astype(self._dtype)
|
| 1191 |
+
if self._custom_opts["replace_continuous_joints"]:
|
| 1192 |
+
return full_q
|
| 1193 |
+
else:
|
| 1194 |
+
cont_jnts=full_q[self._continuous_joints_idxs_qfull, :]
|
| 1195 |
+
cos=cont_jnts[::2, :]
|
| 1196 |
+
sin=cont_jnts[1::2, :]
|
| 1197 |
+
# copy root
|
| 1198 |
+
self._full_q_reduced[0:7, :]=full_q[0:7, :]
|
| 1199 |
+
# copy rev joint vals
|
| 1200 |
+
self._full_q_reduced[self._rev_joints_idxs_red_qfull, :]=full_q[self._rev_joints_idxs_qfull, :]
|
| 1201 |
+
# and continuous
|
| 1202 |
+
angle=np.arctan2(sin, cos)
|
| 1203 |
+
self._full_q_reduced[self._continuous_joints_idxs_red_qfull, :]=angle
|
| 1204 |
+
return self._full_q_reduced
|
| 1205 |
+
|
| 1206 |
+
def _get_v_from_sol(self):
|
| 1207 |
+
return self._ti.solution['v'].astype(self._dtype)
|
| 1208 |
+
|
| 1209 |
+
def _get_a_from_sol(self):
|
| 1210 |
+
return self._ti.solution['a'].astype(self._dtype)
|
| 1211 |
+
|
| 1212 |
+
def _get_a_dot_from_sol(self):
|
| 1213 |
+
return None
|
| 1214 |
+
|
| 1215 |
+
def _get_f_from_sol(self):
|
| 1216 |
+
# to be overridden by child class
|
| 1217 |
+
contact_names =self._get_contacts() # we use controller-side names
|
| 1218 |
+
try:
|
| 1219 |
+
data=[]
|
| 1220 |
+
for key in contact_names:
|
| 1221 |
+
contact_f=self._ti.solution["f_" + key].astype(self._dtype)
|
| 1222 |
+
np.nan_to_num(contact_f, nan=1e6, posinf=1e6, neginf=-1e6, copy=False)
|
| 1223 |
+
np.clip(a=contact_f, a_max=1e6, a_min=-1e6, out=contact_f)
|
| 1224 |
+
data.append(contact_f)
|
| 1225 |
+
return np.concatenate(data, axis=0)
|
| 1226 |
+
except:
|
| 1227 |
+
return None
|
| 1228 |
+
|
| 1229 |
+
def _get_f_dot_from_sol(self):
|
| 1230 |
+
# to be overridden by child class
|
| 1231 |
+
return None
|
| 1232 |
+
|
| 1233 |
+
def _get_eff_from_sol(self):
|
| 1234 |
+
# to be overridden by child class
|
| 1235 |
+
return None
|
| 1236 |
+
|
| 1237 |
+
def _get_cost_from_sol(self,
|
| 1238 |
+
cost_name: str):
|
| 1239 |
+
return self.rhc_costs[cost_name]
|
| 1240 |
+
|
| 1241 |
+
def _get_constr_from_sol(self,
|
| 1242 |
+
constr_name: str):
|
| 1243 |
+
return self.rhc_constr[constr_name]
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/isaac_world_interface.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/jnt_imp_config.yaml
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
XBotInterface: # just used for retrieving homing in sim with xbot_mujoco
|
| 2 |
+
urdf_path: $PWD/xmj_env_files/centauro.urdf
|
| 3 |
+
srdf_path: $PWD/xmj_env_files/centauro.srdf
|
| 4 |
+
|
| 5 |
+
# defaults
|
| 6 |
+
motor_pd:
|
| 7 |
+
"j_arm*_1": [500, 10]
|
| 8 |
+
"j_arm*_2": [500, 10]
|
| 9 |
+
"j_arm*_3": [500, 10]
|
| 10 |
+
"j_arm*_4": [500, 10]
|
| 11 |
+
"j_arm*_5": [100, 5]
|
| 12 |
+
"j_arm*_6": [100, 5]
|
| 13 |
+
"j_arm*_7": [100, 5]
|
| 14 |
+
"hip_yaw_*": [3000, 30]
|
| 15 |
+
"hip_pitch_*": [3000, 30]
|
| 16 |
+
"knee_pitch_*": [3000, 30]
|
| 17 |
+
"ankle_pitch_*": [1000, 10]
|
| 18 |
+
"ankle_yaw_*": [300, 10]
|
| 19 |
+
"neck_pitch": [10, 1]
|
| 20 |
+
"neck_yaw": [10, 1]
|
| 21 |
+
"torso_yaw": [1000, 30]
|
| 22 |
+
"j_wheel_*": [0, 30]
|
| 23 |
+
"velodyne_*": [10, 1]
|
| 24 |
+
"d435_*": [10, 1]
|
| 25 |
+
|
| 26 |
+
startup_motor_pd: # iannis combo
|
| 27 |
+
"j_arm*_1": [500, 30]
|
| 28 |
+
"j_arm*_2": [500, 30]
|
| 29 |
+
"j_arm*_3": [500, 30]
|
| 30 |
+
"j_arm*_4": [500, 30]
|
| 31 |
+
"j_arm*_5": [100, 5]
|
| 32 |
+
"j_arm*_6": [100, 5]
|
| 33 |
+
"j_arm*_7": [100, 5]
|
| 34 |
+
"hip_yaw_*": [200, 60]
|
| 35 |
+
"hip_pitch_*": [200, 60]
|
| 36 |
+
"knee_pitch_*": [200, 60]
|
| 37 |
+
"ankle_pitch_*": [200, 60]
|
| 38 |
+
"ankle_yaw_*": [120, 30]
|
| 39 |
+
"neck_pitch": [10, 1]
|
| 40 |
+
"neck_yaw": [10, 1]
|
| 41 |
+
"torso_yaw": [1000, 30]
|
| 42 |
+
"j_wheel_*": [0, 30]
|
| 43 |
+
"velodyne_*": [10, 1]
|
| 44 |
+
"d435_*": [10, 1]
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/jnt_imp_config_no_yaw.yaml
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
XBotInterface: # just used for retrieving homing in sim with xbot_mujoco
|
| 2 |
+
urdf_path: $PWD/xmj_env_files/centauro.urdf
|
| 3 |
+
srdf_path: $PWD/xmj_env_files/centauro.srdf
|
| 4 |
+
|
| 5 |
+
# defaults
|
| 6 |
+
motor_pd:
|
| 7 |
+
"j_arm*_1": [500, 10]
|
| 8 |
+
"j_arm*_2": [500, 10]
|
| 9 |
+
"j_arm*_3": [500, 10]
|
| 10 |
+
"j_arm*_4": [500, 10]
|
| 11 |
+
"j_arm*_5": [100, 5]
|
| 12 |
+
"j_arm*_6": [100, 5]
|
| 13 |
+
"j_arm*_7": [100, 5]
|
| 14 |
+
"hip_yaw_*": [3000, 30]
|
| 15 |
+
"hip_pitch_*": [3000, 30]
|
| 16 |
+
"knee_pitch_*": [3000, 30]
|
| 17 |
+
"ankle_pitch_*": [1000, 10]
|
| 18 |
+
"ankle_yaw_*": [300, 10]
|
| 19 |
+
"neck_pitch": [10, 1]
|
| 20 |
+
"neck_yaw": [10, 1]
|
| 21 |
+
"torso_yaw": [1000, 30]
|
| 22 |
+
"j_wheel_*": [0, 30]
|
| 23 |
+
"velodyne_*": [10, 1]
|
| 24 |
+
"d435_*": [10, 1]
|
| 25 |
+
|
| 26 |
+
startup_motor_pd: # iannis combo
|
| 27 |
+
"j_arm*_1": [500, 30]
|
| 28 |
+
"j_arm*_2": [500, 30]
|
| 29 |
+
"j_arm*_3": [500, 30]
|
| 30 |
+
"j_arm*_4": [500, 30]
|
| 31 |
+
"j_arm*_5": [100, 5]
|
| 32 |
+
"j_arm*_6": [100, 5]
|
| 33 |
+
"j_arm*_7": [100, 5]
|
| 34 |
+
"hip_yaw_*": [200, 60]
|
| 35 |
+
"hip_pitch_*": [200, 60]
|
| 36 |
+
"knee_pitch_*": [200, 60]
|
| 37 |
+
"ankle_pitch_*": [200, 60]
|
| 38 |
+
"ankle_yaw_*": [600, 10]
|
| 39 |
+
"neck_pitch": [10, 1]
|
| 40 |
+
"neck_yaw": [10, 1]
|
| 41 |
+
"torso_yaw": [1000, 30]
|
| 42 |
+
"j_wheel_*": [0, 30]
|
| 43 |
+
"velodyne_*": [10, 1]
|
| 44 |
+
"d435_*": [10, 1]
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/launch_control_cluster.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import argparse
|
| 3 |
+
import multiprocessing as mp
|
| 4 |
+
import importlib.util
|
| 5 |
+
import inspect
|
| 6 |
+
|
| 7 |
+
from aug_mpc.utils.custom_arg_parsing import generate_custom_arg_dict
|
| 8 |
+
|
| 9 |
+
from EigenIPC.PyEigenIPC import Journal, LogType
|
| 10 |
+
|
| 11 |
+
this_script_name = os.path.splitext(os.path.basename(os.path.abspath(__file__)))[0]
|
| 12 |
+
|
| 13 |
+
# Function to dynamically import a module from a specific file path
|
| 14 |
+
def import_env_module(env_path):
|
| 15 |
+
spec = importlib.util.spec_from_file_location("env_module", env_path)
|
| 16 |
+
env_module = importlib.util.module_from_spec(spec)
|
| 17 |
+
spec.loader.exec_module(env_module)
|
| 18 |
+
return env_module
|
| 19 |
+
|
| 20 |
+
if __name__ == "__main__":
|
| 21 |
+
|
| 22 |
+
# Parse command line arguments for CPU affinity
|
| 23 |
+
parser = argparse.ArgumentParser(description="Set CPU affinity for the script.")
|
| 24 |
+
parser.add_argument('--ns', type=str, help='Namespace to be used for cluster shared memory')
|
| 25 |
+
parser.add_argument('--urdf_path', type=str, help='Robot description package path for URDF ')
|
| 26 |
+
parser.add_argument('--srdf_path', type=str, help='Robot description package path for SRDF ')
|
| 27 |
+
parser.add_argument('--size', type=int, help='cluster size', default=1)
|
| 28 |
+
|
| 29 |
+
# Replacing argparse.BooleanOptionalAction with 'store_true' and 'store_false' for compatibility with Python 3.8
|
| 30 |
+
parser.add_argument('--cloop',action='store_true', help='whether to use RHC controllers in closed loop mode')
|
| 31 |
+
parser.add_argument('--cluster_dt', type=float, default=0.05, help='dt used by MPC controllers for discretization')
|
| 32 |
+
parser.add_argument('--n_nodes', type=int, default=31, help='n nodes used by MPC controllers')
|
| 33 |
+
|
| 34 |
+
parser.add_argument('--verbose',action='store_true', help='run in verbose mode')
|
| 35 |
+
|
| 36 |
+
parser.add_argument('--enable_debug',action='store_true', help='enable debug mode for cluster client and all controllers')
|
| 37 |
+
|
| 38 |
+
parser.add_argument('--dmpdir', type=str, help='directory where data is dumped', default="/root/aux_data")
|
| 39 |
+
|
| 40 |
+
parser.add_argument('--no_mp_fork',action='store_true', help='whether to multiprocess with forkserver context')
|
| 41 |
+
|
| 42 |
+
parser.add_argument('--set_affinity',action='store_true', help='set affinity to a core for each controller')
|
| 43 |
+
|
| 44 |
+
parser.add_argument('--comment', type=str, help='Any useful comment associated with this run', default="")
|
| 45 |
+
parser.add_argument('--timeout_ms', type=int, help='connection timeout after which the script self-terminates', default=60000)
|
| 46 |
+
parser.add_argument('--codegen_override_dir', type=str, help='Path to base dir where codegen is to be loaded', default="")
|
| 47 |
+
|
| 48 |
+
parser.add_argument('--custom_args_names', nargs='+', default=None,
|
| 49 |
+
help='list of custom arguments names')
|
| 50 |
+
parser.add_argument('--custom_args_vals', nargs='+', default=None,
|
| 51 |
+
help='list of custom arguments values')
|
| 52 |
+
parser.add_argument('--custom_args_dtype', nargs='+', default=None,
|
| 53 |
+
help='list of custom arguments data types')
|
| 54 |
+
|
| 55 |
+
parser.add_argument('--cluster_client_fname', type=str,
|
| 56 |
+
default="aug_mpc.controllers.rhc.hybrid_quad_client",
|
| 57 |
+
help="cluster client file import pattern (without extension)")
|
| 58 |
+
|
| 59 |
+
args = parser.parse_args()
|
| 60 |
+
|
| 61 |
+
# Ensure custom_args_names and custom_args_vals have the same length
|
| 62 |
+
custom_opts = generate_custom_arg_dict(args=args)
|
| 63 |
+
custom_opts.update({"cloop": args.cloop,
|
| 64 |
+
"cluster_dt": args.cluster_dt,
|
| 65 |
+
"n_nodes": args.n_nodes,
|
| 66 |
+
"codegen_override_dir": args.codegen_override_dir})
|
| 67 |
+
if args.no_mp_fork: # this needs to be in the main
|
| 68 |
+
mp.set_start_method('spawn')
|
| 69 |
+
else:
|
| 70 |
+
# mp.set_start_method('forkserver')
|
| 71 |
+
mp.set_start_method('fork')
|
| 72 |
+
|
| 73 |
+
cluster_module=importlib.import_module(args.cluster_client_fname)
|
| 74 |
+
# Get all classes defined in the module
|
| 75 |
+
classes_in_module = [name for name, obj in inspect.getmembers(cluster_module, inspect.isclass)
|
| 76 |
+
if obj.__module__ == cluster_module.__name__]
|
| 77 |
+
if len(classes_in_module) == 1:
|
| 78 |
+
cluster_classname=classes_in_module[0]
|
| 79 |
+
ClusterClient = getattr(cluster_module, cluster_classname)
|
| 80 |
+
cluster_client = ClusterClient(namespace=args.ns,
|
| 81 |
+
cluster_size=args.size,
|
| 82 |
+
urdf_xacro_path=args.urdf_path,
|
| 83 |
+
srdf_xacro_path=args.srdf_path,
|
| 84 |
+
open_loop=not args.cloop,
|
| 85 |
+
use_mp_fork = not args.no_mp_fork,
|
| 86 |
+
verbose=args.verbose,
|
| 87 |
+
debug=args.enable_debug,
|
| 88 |
+
base_dump_dir=args.dmpdir,
|
| 89 |
+
timeout_ms=args.timeout_ms,
|
| 90 |
+
custom_opts=custom_opts,
|
| 91 |
+
codegen_override=args.codegen_override_dir,
|
| 92 |
+
set_affinity=args.set_affinity)
|
| 93 |
+
cluster_client.run()
|
| 94 |
+
|
| 95 |
+
else:
|
| 96 |
+
class_list_str = ", ".join(classes_in_module)
|
| 97 |
+
Journal.log("launch_control_cluster.py",
|
| 98 |
+
"",
|
| 99 |
+
f"Found more than one class in cluster client file {args.cluster_client_fname}. Found: {class_list_str}",
|
| 100 |
+
LogType.EXCEP,
|
| 101 |
+
throw_when_excep = False)
|
| 102 |
+
exit()
|
| 103 |
+
|
| 104 |
+
# control_cluster_client =
|
| 105 |
+
# control_cluster_client.run() # spawns the controllers on separate processes (blocking)
|
| 106 |
+
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/launch_train_env.py
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from aug_mpc.utils.determinism import deterministic_run
|
| 2 |
+
|
| 3 |
+
from mpc_hive.utilities.shared_data.sim_data import SharedEnvInfo
|
| 4 |
+
from mpc_hive.utilities.shared_data.cluster_data import SharedClusterInfo
|
| 5 |
+
|
| 6 |
+
from EigenIPC.PyEigenIPC import VLevel, Journal, LogType
|
| 7 |
+
from EigenIPC.PyEigenIPC import StringTensorServer
|
| 8 |
+
|
| 9 |
+
import os, argparse, sys, types, inspect
|
| 10 |
+
|
| 11 |
+
from perf_sleep.pyperfsleep import PerfSleep
|
| 12 |
+
|
| 13 |
+
import importlib.util
|
| 14 |
+
import torch
|
| 15 |
+
import signal
|
| 16 |
+
|
| 17 |
+
algo = None # global to make it accessible by signal handler
|
| 18 |
+
exit_request=False
|
| 19 |
+
dummy_step_exit_req=False
|
| 20 |
+
|
| 21 |
+
def handle_sigint(signum, frame):
|
| 22 |
+
global exit_request, dummy_step_exit_req
|
| 23 |
+
Journal.log("launch_train_env.py",
|
| 24 |
+
"",
|
| 25 |
+
f"Received sigint. Will stop training.",
|
| 26 |
+
LogType.WARN)
|
| 27 |
+
exit_request=True
|
| 28 |
+
dummy_step_exit_req=True # in case dummy_step_loop was used
|
| 29 |
+
|
| 30 |
+
# Function to dynamically import a module from a specific file path
|
| 31 |
+
# def import_env_module(env_path):
|
| 32 |
+
# spec = importlib.util.spec_from_file_location("env_module", env_path)
|
| 33 |
+
# env_module = importlib.util.module_from_spec(spec)
|
| 34 |
+
# spec.loader.exec_module(env_module)
|
| 35 |
+
# return env_module
|
| 36 |
+
|
| 37 |
+
def import_env_module(env_path, local_env_root: str = None):
|
| 38 |
+
"""
|
| 39 |
+
env_path: full path to the child env .py file to exec
|
| 40 |
+
local_env_root: directory where local copies of aug_mpc_envs.training_envs modules live
|
| 41 |
+
"""
|
| 42 |
+
if local_env_root is not None:
|
| 43 |
+
local_env_root = os.path.abspath(local_env_root)
|
| 44 |
+
# override aug_mpc_envs.training_envs package to point to the local_env_root
|
| 45 |
+
pkg_name = "aug_mpc_envs.training_envs"
|
| 46 |
+
if pkg_name not in sys.modules:
|
| 47 |
+
mod = types.ModuleType(pkg_name)
|
| 48 |
+
mod.__path__ = [local_env_root] # tell Python to look here first
|
| 49 |
+
sys.modules[pkg_name] = mod
|
| 50 |
+
else:
|
| 51 |
+
existing = getattr(sys.modules[pkg_name], "__path__", None)
|
| 52 |
+
if existing is None:
|
| 53 |
+
sys.modules[pkg_name].__path__ = [local_env_root]
|
| 54 |
+
elif local_env_root not in existing:
|
| 55 |
+
existing.insert(0, local_env_root)
|
| 56 |
+
|
| 57 |
+
# load the module as usual
|
| 58 |
+
spec = importlib.util.spec_from_file_location("env_module", env_path)
|
| 59 |
+
env_module = importlib.util.module_from_spec(spec)
|
| 60 |
+
spec.loader.exec_module(env_module)
|
| 61 |
+
return env_module
|
| 62 |
+
|
| 63 |
+
def log_env_hierarchy(env_class, env_path, env_type="training"):
|
| 64 |
+
"""
|
| 65 |
+
Logs the env class, its file, and full inheritance hierarchy with file paths.
|
| 66 |
+
env_class: the child env class
|
| 67 |
+
env_path: file path where the child class was loaded from
|
| 68 |
+
env_type: string label, e.g., "training", "evaluation", "resumed_training"
|
| 69 |
+
"""
|
| 70 |
+
def get_bases_recursive(cls):
|
| 71 |
+
"""Recursively get all base classes with their file paths."""
|
| 72 |
+
info = []
|
| 73 |
+
for base in cls.__bases__:
|
| 74 |
+
try:
|
| 75 |
+
file = inspect.getfile(base)
|
| 76 |
+
except TypeError:
|
| 77 |
+
file = "built-in or unknown"
|
| 78 |
+
info.append(f"{base.__name__} (from {file})")
|
| 79 |
+
# Recurse unless it's object
|
| 80 |
+
if base is not object:
|
| 81 |
+
info.extend(get_bases_recursive(base))
|
| 82 |
+
return info
|
| 83 |
+
|
| 84 |
+
hierarchy_info = get_bases_recursive(env_class)
|
| 85 |
+
hierarchy_str = " -> ".join(hierarchy_info) if hierarchy_info else "No parents"
|
| 86 |
+
|
| 87 |
+
Journal.log(
|
| 88 |
+
"launch_train_env.py",
|
| 89 |
+
"",
|
| 90 |
+
f"loading {env_type} env {env_class.__name__} (from {env_path}) "
|
| 91 |
+
f"with hierarchy: {hierarchy_str}",
|
| 92 |
+
LogType.INFO,
|
| 93 |
+
throw_when_excep=True
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
def dummy_step_loop(env):
|
| 97 |
+
global dummy_step_exit_req
|
| 98 |
+
while True:
|
| 99 |
+
if dummy_step_exit_req:
|
| 100 |
+
return True
|
| 101 |
+
step_ok=env.step(action=env.safe_action) # not a busy loop because of MPC in the step
|
| 102 |
+
if not step_ok:
|
| 103 |
+
return False
|
| 104 |
+
|
| 105 |
+
if __name__ == "__main__":
|
| 106 |
+
|
| 107 |
+
signal.signal(signal.SIGINT, handle_sigint)
|
| 108 |
+
|
| 109 |
+
# Parse command line arguments for CPU affinity
|
| 110 |
+
parser = argparse.ArgumentParser(description="Set CPU affinity for the script.")
|
| 111 |
+
|
| 112 |
+
parser.add_argument('--run_name', type=str, default=None, help='Name of training run')
|
| 113 |
+
parser.add_argument('--ns', type=str, help='Namespace to be used for shared memory')
|
| 114 |
+
parser.add_argument('--timeout_ms', type=int, help='Connection timeout after which the script self-terminates', default=60000)
|
| 115 |
+
parser.add_argument('--drop_dir', type=str, help='Directory root where all run data will be dumped')
|
| 116 |
+
parser.add_argument('--comment', type=str, help='Any useful comment associated with this run', default="")
|
| 117 |
+
parser.add_argument('--seed', type=int, help='Seed', default=1)
|
| 118 |
+
parser.add_argument('--use_cpu',action='store_true', help='If set, all the training (data included) will be performed on CPU')
|
| 119 |
+
|
| 120 |
+
parser.add_argument('--db',action='store_true', help='Whether to enable local data logging for the algorithm (reward metrics, etc.)')
|
| 121 |
+
parser.add_argument('--env_db',action='store_true', help='Whether to enable env db data logging on shared mem (e.g. reward metrics are not available for reading anymore)')
|
| 122 |
+
parser.add_argument('--full_env_db',action='store_true', help='Whether to enable detailed episodic data storage (data over single transitions)')
|
| 123 |
+
parser.add_argument('--rmdb',action='store_true', help='Whether to enable remote debug (e.g. data logging on remote servers)')
|
| 124 |
+
|
| 125 |
+
parser.add_argument('--tot_tsteps', type=int, help='Total number of timesteps to be collected', default=int(30e6))
|
| 126 |
+
parser.add_argument('--action_repeat', type=int, help='Frame skipping (1-> no skip)', default=1)
|
| 127 |
+
parser.add_argument('--discount_factor', type=float, help='', default=0.99)
|
| 128 |
+
parser.add_argument('--obs_norm',action='store_true', help='Whether to enable the use of running normalizer in agent')
|
| 129 |
+
parser.add_argument('--obs_rescale',action='store_true', help='Whether to rescale observation depending on their expected range')
|
| 130 |
+
parser.add_argument('--add_weight_norm',action='store_true', help='Whether to add weight normalization to agent interal llayers')
|
| 131 |
+
parser.add_argument('--add_layer_norm',action='store_true', help='Whether to add layer normalization to agent internal llayers')
|
| 132 |
+
parser.add_argument('--add_batch_norm',action='store_true', help='Whether to add batch normalization to agent internal llayers')
|
| 133 |
+
|
| 134 |
+
parser.add_argument('--act_rescale_critic',action='store_true', help='Whether to rescale actions provided to critic (if SAC) to be in range [-1, 1]')
|
| 135 |
+
parser.add_argument('--use_period_resets',action='store_true', help='')
|
| 136 |
+
|
| 137 |
+
parser.add_argument('--sac',action='store_true', help='Use SAC, otherwise PPO, unless dummy is set')
|
| 138 |
+
parser.add_argument('--dummy',action='store_true', help='Use dummy agent (useful for testing and debugging environments)')
|
| 139 |
+
|
| 140 |
+
parser.add_argument('--dump_checkpoints',action='store_true', help='Whether to dump model checkpoints during training')
|
| 141 |
+
|
| 142 |
+
parser.add_argument('--demo_envs_perc', type=float, help='[0, 1]', default=0.0)
|
| 143 |
+
parser.add_argument('--demo_stop_thresh', type=float, default=None,
|
| 144 |
+
help='Performance hreshold above which demonstration envs should be deactivated.')
|
| 145 |
+
|
| 146 |
+
parser.add_argument('--expl_envs_perc', type=float, help='[0, 1]', default=0)
|
| 147 |
+
|
| 148 |
+
parser.add_argument('--use_rnd',action='store_true', help='Whether to use RND for exploration')
|
| 149 |
+
|
| 150 |
+
parser.add_argument('--eval',action='store_true', help='Whether to perform an evaluation run')
|
| 151 |
+
parser.add_argument('--n_eval_timesteps', type=int, help='Total number of timesteps to be evaluated', default=int(1e6))
|
| 152 |
+
parser.add_argument('--det_eval',action='store_true', help='Whether to perform a deterministic eval (only action mean is used). Only valid if --eval.')
|
| 153 |
+
parser.add_argument('--allow_expl_during_eval',action='store_true', help='Whether to allow expl envs during evaluation (useful to tune exploration)')
|
| 154 |
+
|
| 155 |
+
parser.add_argument('--resume',action='store_true', help='Resume a previous training using a checkpoint')
|
| 156 |
+
parser.add_argument('--mpath', type=str, help='Model path to be used for policy evaluation', default=None)
|
| 157 |
+
parser.add_argument('--mname', type=str, help='Model name', default=None)
|
| 158 |
+
parser.add_argument('--override_env',action='store_true', help='Whether to override env when running evaluation')
|
| 159 |
+
|
| 160 |
+
parser.add_argument('--anomaly_detect',action='store_true', help='Whether to enable anomaly detection (useful for debug)')
|
| 161 |
+
|
| 162 |
+
parser.add_argument('--compression_ratio', type=float,
|
| 163 |
+
help='If e.g. 0.8, the fist layer will be of dimension [input_features_size x (input_features_size*compression_ratio)]', default=-1.0)
|
| 164 |
+
parser.add_argument('--actor_lwidth', type=int, help='Actor network layer width', default=128)
|
| 165 |
+
parser.add_argument('--critic_lwidth', type=int, help='Critic network layer width', default=256)
|
| 166 |
+
parser.add_argument('--actor_n_hlayers', type=int, help='Actor network size', default=3)
|
| 167 |
+
parser.add_argument('--critic_n_hlayers', type=int, help='Critic network size', default=4)
|
| 168 |
+
|
| 169 |
+
parser.add_argument('--env_fname', type=str, default="twist_tracking_env", help='Training env file name (without extension)')
|
| 170 |
+
parser.add_argument('--env_classname', type=str, default="TwistTrackingEnv", help='Training env class name')
|
| 171 |
+
parser.add_argument('--override_agent_actions',action='store_true', help='Whether to override agent actions with custom ones from shared mem (useful for db)')
|
| 172 |
+
parser.add_argument('--override_agent_refs',action='store_true', help='Whether to override automatically generated agent refs (useful for debug)')
|
| 173 |
+
|
| 174 |
+
parser.add_argument('--step_while_setup',action='store_true', help='Continue stepping env with default actions while setting up agent, etc..')
|
| 175 |
+
|
| 176 |
+
args = parser.parse_args()
|
| 177 |
+
args_dict = vars(args)
|
| 178 |
+
|
| 179 |
+
if args.eval and args.resume:
|
| 180 |
+
Journal.log("launch_train_env.py",
|
| 181 |
+
"",
|
| 182 |
+
f"Cannot set both --eval and --resume flags. Exiting.",
|
| 183 |
+
LogType.EXCEP,
|
| 184 |
+
throw_when_excep = True)
|
| 185 |
+
|
| 186 |
+
deterministic_run(seed=args.seed, torch_det_algos=False)
|
| 187 |
+
|
| 188 |
+
anomaly_detect=False
|
| 189 |
+
if args.anomaly_detect:
|
| 190 |
+
torch.autograd.set_detect_anomaly(True)
|
| 191 |
+
|
| 192 |
+
if (not args.mpath is None) and (not args.mname is None):
|
| 193 |
+
mpath_full = os.path.join(args.mpath, args.mname)
|
| 194 |
+
else:
|
| 195 |
+
mpath_full=None
|
| 196 |
+
|
| 197 |
+
env_fname=args.env_fname
|
| 198 |
+
env_classname = args.env_classname
|
| 199 |
+
env_path=""
|
| 200 |
+
env_module=None
|
| 201 |
+
if (not args.eval and not args.resume) or (args.override_env):
|
| 202 |
+
# if starting a fresh traning or overriding env, load from a fresh env from aug_mpc
|
| 203 |
+
env_path = f"aug_mpc_envs.training_envs.{env_fname}"
|
| 204 |
+
env_module = importlib.import_module(env_path)
|
| 205 |
+
else:
|
| 206 |
+
if args.mpath is None:
|
| 207 |
+
Journal.log("launch_train_env.py",
|
| 208 |
+
"",
|
| 209 |
+
f"no mpath provided! Cannot load env. Either provide a mpath or run with --override_env",
|
| 210 |
+
LogType.EXCEP,
|
| 211 |
+
throw_when_excep = True)
|
| 212 |
+
|
| 213 |
+
env_path = os.path.join(args.mpath, env_fname + ".py")
|
| 214 |
+
env_module = import_env_module(env_path, local_env_root=args.mpath)
|
| 215 |
+
|
| 216 |
+
EnvClass = getattr(env_module, env_classname)
|
| 217 |
+
env_type = "training" if not args.eval else "evaluation"
|
| 218 |
+
if args.resume:
|
| 219 |
+
env_type = "resumed_training"
|
| 220 |
+
log_env_hierarchy(EnvClass, env_path, env_type) # db print of env class
|
| 221 |
+
|
| 222 |
+
env = EnvClass(namespace=args.ns,
|
| 223 |
+
verbose=True,
|
| 224 |
+
vlevel=VLevel.V2,
|
| 225 |
+
use_gpu=not args.use_cpu,
|
| 226 |
+
debug=args.env_db,
|
| 227 |
+
override_agent_refs=args.override_agent_refs,
|
| 228 |
+
timeout_ms=args.timeout_ms,
|
| 229 |
+
env_opts=args_dict)
|
| 230 |
+
if not env.is_ready(): # something went wrong
|
| 231 |
+
exit()
|
| 232 |
+
|
| 233 |
+
dummy_step_thread = None
|
| 234 |
+
if args.step_while_setup:
|
| 235 |
+
import threading
|
| 236 |
+
# spawn step thread (we don't true parallelization, thread is fine)
|
| 237 |
+
# start the dummy stepping in a separate thread so setup can continue concurrently
|
| 238 |
+
dummy_step_thread = threading.Thread(target=dummy_step_loop, args=(env,), daemon=True)
|
| 239 |
+
dummy_step_thread.start()
|
| 240 |
+
|
| 241 |
+
# getting some sim info for debugging
|
| 242 |
+
sim_data = {}
|
| 243 |
+
sim_info_shared = SharedEnvInfo(namespace=args.ns,
|
| 244 |
+
is_server=False,
|
| 245 |
+
safe=False)
|
| 246 |
+
sim_info_shared.run()
|
| 247 |
+
sim_info_keys = sim_info_shared.param_keys
|
| 248 |
+
sim_info_data = sim_info_shared.get().flatten()
|
| 249 |
+
for i in range(len(sim_info_keys)):
|
| 250 |
+
sim_data[sim_info_keys[i]] = sim_info_data[i]
|
| 251 |
+
|
| 252 |
+
# getting come cluster info for debugging
|
| 253 |
+
cluster_data={}
|
| 254 |
+
cluste_info_shared = SharedClusterInfo(namespace=args.ns,
|
| 255 |
+
is_server=False,
|
| 256 |
+
safe=False)
|
| 257 |
+
cluste_info_shared.run()
|
| 258 |
+
cluster_info_keys = cluste_info_shared.param_keys
|
| 259 |
+
cluster_info_data = cluste_info_shared.get().flatten()
|
| 260 |
+
for i in range(len(cluster_info_keys)):
|
| 261 |
+
cluster_data[cluster_info_keys[i]] = cluster_info_data[i]
|
| 262 |
+
|
| 263 |
+
custom_args={}
|
| 264 |
+
custom_args["uname_host"]="user_host"
|
| 265 |
+
try:
|
| 266 |
+
username = os.getlogin() # add machine info to db data
|
| 267 |
+
hostname = os.uname().nodename
|
| 268 |
+
user_host = f"{username}@{hostname}"
|
| 269 |
+
custom_args["uname_host"]=user_host
|
| 270 |
+
except:
|
| 271 |
+
pass
|
| 272 |
+
|
| 273 |
+
algo=None
|
| 274 |
+
if not args.dummy:
|
| 275 |
+
if args.sac:
|
| 276 |
+
from aug_mpc.training_algs.sac.sac import SAC
|
| 277 |
+
|
| 278 |
+
algo = SAC(env=env,
|
| 279 |
+
debug=args.db,
|
| 280 |
+
remote_db=args.rmdb,
|
| 281 |
+
seed=args.seed)
|
| 282 |
+
else:
|
| 283 |
+
from aug_mpc.training_algs.ppo.ppo import PPO
|
| 284 |
+
|
| 285 |
+
algo = PPO(env=env,
|
| 286 |
+
debug=args.db,
|
| 287 |
+
remote_db=args.rmdb,
|
| 288 |
+
seed=args.seed)
|
| 289 |
+
else:
|
| 290 |
+
from aug_mpc.training_algs.dummy.dummy import Dummy
|
| 291 |
+
|
| 292 |
+
algo=Dummy(env=env,
|
| 293 |
+
debug=args.db,
|
| 294 |
+
remote_db=args.rmdb,
|
| 295 |
+
seed=args.seed)
|
| 296 |
+
|
| 297 |
+
custom_args.update(args_dict)
|
| 298 |
+
custom_args.update(cluster_data)
|
| 299 |
+
custom_args.update(sim_data)
|
| 300 |
+
|
| 301 |
+
run_name=env_classname if args.run_name is None else args.run_name
|
| 302 |
+
algo.setup(run_name=run_name,
|
| 303 |
+
ns=args.ns,
|
| 304 |
+
verbose=True,
|
| 305 |
+
drop_dir_name=args.drop_dir,
|
| 306 |
+
custom_args=custom_args,
|
| 307 |
+
comment=args.comment,
|
| 308 |
+
eval=args.eval,
|
| 309 |
+
resume=args.resume,
|
| 310 |
+
model_path=mpath_full,
|
| 311 |
+
n_eval_timesteps=args.n_eval_timesteps,
|
| 312 |
+
dump_checkpoints=args.dump_checkpoints,
|
| 313 |
+
norm_obs=args.obs_norm,
|
| 314 |
+
rescale_obs=args.obs_rescale)
|
| 315 |
+
|
| 316 |
+
full_drop_dir=algo.drop_dir()
|
| 317 |
+
shared_drop_dir = StringTensorServer(length=1,
|
| 318 |
+
basename="SharedTrainingDropDir",
|
| 319 |
+
name_space=args.ns,
|
| 320 |
+
verbose=True,
|
| 321 |
+
vlevel=VLevel.V2,
|
| 322 |
+
force_reconnection=True)
|
| 323 |
+
shared_drop_dir.run()
|
| 324 |
+
|
| 325 |
+
while True:
|
| 326 |
+
if not shared_drop_dir.write_vec([full_drop_dir], 0):
|
| 327 |
+
ns=1000000000
|
| 328 |
+
PerfSleep.thread_sleep(ns)
|
| 329 |
+
continue
|
| 330 |
+
else:
|
| 331 |
+
break
|
| 332 |
+
|
| 333 |
+
if args.step_while_setup:
|
| 334 |
+
# stop dummy step thread and give algo authority on step
|
| 335 |
+
dummy_step_exit_req=True
|
| 336 |
+
# wait for thread to join
|
| 337 |
+
if dummy_step_thread is not None:
|
| 338 |
+
dummy_step_thread.join()
|
| 339 |
+
Journal.log("launch_train_env.py",
|
| 340 |
+
"",
|
| 341 |
+
f"Dummy env step thread joined. Moving step authority to algo.",
|
| 342 |
+
LogType.INFO)
|
| 343 |
+
|
| 344 |
+
eval=args.eval
|
| 345 |
+
if args.override_agent_actions:
|
| 346 |
+
eval=True
|
| 347 |
+
if not eval:
|
| 348 |
+
while not exit_request:
|
| 349 |
+
if not algo.learn():
|
| 350 |
+
break
|
| 351 |
+
else: # eval phase
|
| 352 |
+
with torch.no_grad(): # no need for grad computation
|
| 353 |
+
while not exit_request:
|
| 354 |
+
if not algo.eval():
|
| 355 |
+
break
|
| 356 |
+
|
| 357 |
+
algo.done() # make sure to terminate training properly
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/launch_world_interface.py
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import argparse
|
| 3 |
+
import importlib.util
|
| 4 |
+
import inspect
|
| 5 |
+
|
| 6 |
+
from aug_mpc.utils.rt_factor import RtFactor
|
| 7 |
+
from aug_mpc.utils.custom_arg_parsing import generate_custom_arg_dict
|
| 8 |
+
from aug_mpc.utils.determinism import deterministic_run
|
| 9 |
+
|
| 10 |
+
from mpc_hive.utilities.shared_data.sim_data import SharedEnvInfo
|
| 11 |
+
|
| 12 |
+
from EigenIPC.PyEigenIPC import VLevel
|
| 13 |
+
from EigenIPC.PyEigenIPC import Journal, LogType
|
| 14 |
+
|
| 15 |
+
script_name = os.path.splitext(os.path.basename(os.path.abspath(__file__)))[0]
|
| 16 |
+
|
| 17 |
+
# Function to dynamically import a module from a specific file path
|
| 18 |
+
def import_env_module(env_path):
|
| 19 |
+
spec = importlib.util.spec_from_file_location("env_module", env_path)
|
| 20 |
+
env_module = importlib.util.module_from_spec(spec)
|
| 21 |
+
spec.loader.exec_module(env_module)
|
| 22 |
+
return env_module
|
| 23 |
+
|
| 24 |
+
if __name__ == '__main__':
|
| 25 |
+
|
| 26 |
+
parser = argparse.ArgumentParser(description="Sim. env launcher")
|
| 27 |
+
# Add arguments
|
| 28 |
+
parser.add_argument('--robot_name', type=str, help='Alias to be used for the robot and also shared memory')
|
| 29 |
+
parser.add_argument('--urdf_path', type=str, help='path to the URDF file description for each robot')
|
| 30 |
+
parser.add_argument('--srdf_path', type=str, help='path to the SRDF file description for each robot (used for homing)')
|
| 31 |
+
parser.add_argument('--jnt_imp_config_path', type=str, help='path to a valid YAML file containing information on jnt impedance gains')
|
| 32 |
+
parser.add_argument('--num_envs', type=int, default=1)
|
| 33 |
+
parser.add_argument('--n_contacts', type=int, default=4)
|
| 34 |
+
parser.add_argument('--cluster_dt', type=float, default=0.03, help='dt at which the control cluster runs')
|
| 35 |
+
parser.add_argument('--dmpdir', type=str, help='directory where data is dumped', default="/root/aux_data")
|
| 36 |
+
parser.add_argument('--remote_stepping',action='store_true',
|
| 37 |
+
help='Whether to use remote stepping for cluster triggering (to be set during training)')
|
| 38 |
+
|
| 39 |
+
# Replacing argparse.BooleanOptionalAction with 'store_true' and 'store_false' for compatibility with Python 3.8
|
| 40 |
+
parser.add_argument('--use_gpu',action='store_true', help='Whether to use gpu simulation')
|
| 41 |
+
|
| 42 |
+
parser.add_argument('--enable_debug',action='store_true', help='Whether to enable debug mode (may introduce significant overhead)')
|
| 43 |
+
|
| 44 |
+
parser.add_argument('--headless',action='store_true', help='Whether to run simulation in headless mode')
|
| 45 |
+
|
| 46 |
+
parser.add_argument('--verbose',action='store_true', help='Enable verbose mode')
|
| 47 |
+
|
| 48 |
+
parser.add_argument('--comment', type=str, help='Any useful comment associated with this run', default="")
|
| 49 |
+
parser.add_argument('--timeout_ms', type=int, help='connection timeout after which the script self-terminates', default=60000)
|
| 50 |
+
parser.add_argument('--physics_dt', type=float, default=5e-4, help='')
|
| 51 |
+
|
| 52 |
+
parser.add_argument('--use_custom_jnt_imp',action='store_true',
|
| 53 |
+
help='Whether to override the default PD controller with a custom one')
|
| 54 |
+
|
| 55 |
+
parser.add_argument('--diff_vels',action='store_true',
|
| 56 |
+
help='Whether to obtain velocities by differentiation or not')
|
| 57 |
+
|
| 58 |
+
parser.add_argument('--init_timesteps', type=int, help='initialization timesteps', default=None)
|
| 59 |
+
parser.add_argument('--seed', type=int, help='seed', default=0)
|
| 60 |
+
|
| 61 |
+
parser.add_argument('--custom_args_names', nargs='+', default=None,
|
| 62 |
+
help='list of custom arguments names')
|
| 63 |
+
parser.add_argument('--custom_args_vals', nargs='+', default=None,
|
| 64 |
+
help='list of custom arguments values')
|
| 65 |
+
parser.add_argument('--custom_args_dtype', nargs='+', default=None,
|
| 66 |
+
help='list of custom arguments data types')
|
| 67 |
+
|
| 68 |
+
parser.add_argument('--env_fname', type=str,
|
| 69 |
+
default="aug_mpc_envs.world_interfaces.isaac_world_interface",
|
| 70 |
+
help="env file import pattern (without extension)")
|
| 71 |
+
|
| 72 |
+
args = parser.parse_args()
|
| 73 |
+
|
| 74 |
+
deterministic_run(seed=args.seed, torch_det_algos=False)
|
| 75 |
+
|
| 76 |
+
default_init_duration=3.0 # [s]
|
| 77 |
+
default_init_tsteps=int(default_init_duration/args.physics_dt)
|
| 78 |
+
init_tsteps=args.init_timesteps
|
| 79 |
+
if init_tsteps is None:
|
| 80 |
+
init_tsteps=default_init_tsteps
|
| 81 |
+
# Ensure custom_args_names, custom_args_vals, and custom_args_dtype have the same length
|
| 82 |
+
custom_opt = generate_custom_arg_dict(args=args)
|
| 83 |
+
|
| 84 |
+
Journal.log("launch_world_interface.py",
|
| 85 |
+
"",
|
| 86 |
+
f"Will warmup world interface for {default_init_duration}s ({default_init_tsteps} physics steps)",
|
| 87 |
+
LogType.STAT)
|
| 88 |
+
|
| 89 |
+
robot_names = [args.robot_name]
|
| 90 |
+
robot_urdf_paths = [args.urdf_path]
|
| 91 |
+
robot_srdf_paths = [args.srdf_path]
|
| 92 |
+
control_clust_dts = [float(args.cluster_dt)]
|
| 93 |
+
use_remote_stepping = [args.remote_stepping]
|
| 94 |
+
n_contacts = [args.n_contacts]
|
| 95 |
+
jnt_imp_config_paths = [args.jnt_imp_config_path]
|
| 96 |
+
num_envs = args.num_envs
|
| 97 |
+
control_clust_dt = args.cluster_dt # [s]. Dt at which RHC controllers run
|
| 98 |
+
headless = args.headless
|
| 99 |
+
|
| 100 |
+
# simulation parameters
|
| 101 |
+
remote_env_params = {}
|
| 102 |
+
remote_env_params["physics_dt"] = args.physics_dt # physics_dt?
|
| 103 |
+
remote_env_params["n_envs"] = num_envs
|
| 104 |
+
remote_env_params["use_gpu"] = args.use_gpu
|
| 105 |
+
remote_env_params["substepping_dt"] = control_clust_dts[0]
|
| 106 |
+
remote_env_params["headless"] = headless
|
| 107 |
+
remote_env_params["debug_enabled"] = args.enable_debug
|
| 108 |
+
remote_env_params["seed"] = args.seed
|
| 109 |
+
remote_env_params.update(custom_opt)
|
| 110 |
+
# sim info to be broadcasted on shared memory
|
| 111 |
+
# adding some data to dict for debugging
|
| 112 |
+
|
| 113 |
+
shared_sim_infos = []
|
| 114 |
+
for i in range(len(robot_names)):
|
| 115 |
+
shared_sim_infos.append(SharedEnvInfo(
|
| 116 |
+
namespace=robot_names[i],
|
| 117 |
+
is_server=True,
|
| 118 |
+
env_params_dict=remote_env_params,
|
| 119 |
+
verbose=True,
|
| 120 |
+
vlevel=VLevel.V2,
|
| 121 |
+
force_reconnection=True))
|
| 122 |
+
shared_sim_infos[i].run()
|
| 123 |
+
|
| 124 |
+
env_module=importlib.import_module(args.env_fname)
|
| 125 |
+
classes_in_module = [name for name, obj in inspect.getmembers(env_module, inspect.isclass)
|
| 126 |
+
if obj.__module__ == env_module.__name__]
|
| 127 |
+
if len(classes_in_module) == 1:
|
| 128 |
+
cluster_classname=classes_in_module[0]
|
| 129 |
+
Env = getattr(env_module, cluster_classname)
|
| 130 |
+
else:
|
| 131 |
+
class_list_str = ", ".join(classes_in_module)
|
| 132 |
+
Journal.log("launch_world_interface.py",
|
| 133 |
+
"",
|
| 134 |
+
f"Found more than one class in env file {args.env_fname}. Found: {class_list_str}",
|
| 135 |
+
LogType.EXCEP,
|
| 136 |
+
throw_when_excep = False)
|
| 137 |
+
exit()
|
| 138 |
+
|
| 139 |
+
env = Env(robot_names=robot_names,
|
| 140 |
+
robot_urdf_paths=robot_urdf_paths,
|
| 141 |
+
robot_srdf_paths=robot_srdf_paths,
|
| 142 |
+
cluster_dt=control_clust_dts,
|
| 143 |
+
jnt_imp_config_paths=jnt_imp_config_paths,
|
| 144 |
+
n_contacts=n_contacts,
|
| 145 |
+
use_remote_stepping=use_remote_stepping,
|
| 146 |
+
name=classes_in_module[0],
|
| 147 |
+
num_envs=num_envs,
|
| 148 |
+
debug=args.enable_debug,
|
| 149 |
+
verbose=args.verbose,
|
| 150 |
+
vlevel=VLevel.V2,
|
| 151 |
+
n_init_step=init_tsteps,
|
| 152 |
+
timeout_ms=args.timeout_ms,
|
| 153 |
+
env_opts=remote_env_params,
|
| 154 |
+
use_gpu=args.use_gpu,
|
| 155 |
+
override_low_lev_controller=args.use_custom_jnt_imp) # create environment
|
| 156 |
+
env.reset(reset_sim=True)
|
| 157 |
+
|
| 158 |
+
rt_factor = RtFactor(dt_nom=env.physics_dt(),
|
| 159 |
+
window_size=100)
|
| 160 |
+
|
| 161 |
+
while True:
|
| 162 |
+
|
| 163 |
+
if rt_factor.reset_due():
|
| 164 |
+
rt_factor.reset()
|
| 165 |
+
|
| 166 |
+
step_ok=env.step()
|
| 167 |
+
|
| 168 |
+
if not step_ok:
|
| 169 |
+
break
|
| 170 |
+
|
| 171 |
+
rt_factor.update()
|
| 172 |
+
|
| 173 |
+
for i in range(len(robot_names)):
|
| 174 |
+
robot_name=robot_names[i]
|
| 175 |
+
n_steps = env.cluster_sim_step_counters[robot_name]
|
| 176 |
+
sol_counter = env.cluster_servers[robot_name].solution_counter()
|
| 177 |
+
trigger_counter = env.cluster_servers[robot_name].trigger_counter()
|
| 178 |
+
shared_sim_infos[i].write(dyn_info_name=["sim_rt_factor",
|
| 179 |
+
"total_rt_factor",
|
| 180 |
+
"env_stepping_dt",
|
| 181 |
+
"world_stepping_dt",
|
| 182 |
+
"time_to_get_states_from_env",
|
| 183 |
+
"cluster_state_update_dt",
|
| 184 |
+
"cluster_sol_time",
|
| 185 |
+
"n_sim_steps",
|
| 186 |
+
"n_cluster_trigger_steps",
|
| 187 |
+
"n_cluster_sol_steps",
|
| 188 |
+
"sim_time",
|
| 189 |
+
"cluster_time"],
|
| 190 |
+
val=[rt_factor.get(),
|
| 191 |
+
rt_factor.get() * num_envs,
|
| 192 |
+
rt_factor.get_avrg_step_time(),
|
| 193 |
+
env.debug_data["time_to_step_world"],
|
| 194 |
+
env.debug_data["time_to_get_states_from_env"],
|
| 195 |
+
env.debug_data["cluster_state_update_dt"][robot_name],
|
| 196 |
+
env.debug_data["cluster_sol_time"][robot_name],
|
| 197 |
+
n_steps,
|
| 198 |
+
trigger_counter,
|
| 199 |
+
sol_counter,
|
| 200 |
+
env.debug_data["sim_time"][robot_name],
|
| 201 |
+
sol_counter*env.cluster_servers[robot_name].cluster_dt()
|
| 202 |
+
])
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/__init__.py
ADDED
|
File without changes
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/augmpc_cluster_client.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from mpc_hive.cluster_client.control_cluster_client import ControlClusterClient
|
| 2 |
+
from aug_mpc.utils.xrdf_gen import generate_srdf, generate_urdf
|
| 3 |
+
from aug_mpc.utils.hybrid_quad_xrdf_gen import get_xrdf_cmds
|
| 4 |
+
from aug_mpc.utils.custom_arg_parsing import extract_custom_xacro_args, merge_xacro_cmds
|
| 5 |
+
|
| 6 |
+
from EigenIPC.PyEigenIPC import Journal, LogType
|
| 7 |
+
|
| 8 |
+
from typing import List, Dict
|
| 9 |
+
|
| 10 |
+
import os
|
| 11 |
+
|
| 12 |
+
from abc import abstractmethod
|
| 13 |
+
|
| 14 |
+
class AugMpcClusterClient(ControlClusterClient):
|
| 15 |
+
|
| 16 |
+
def _import_aux_libs(self):
|
| 17 |
+
super()._import_aux_libs()
|
| 18 |
+
|
| 19 |
+
def __init__(self,
|
| 20 |
+
namespace: str,
|
| 21 |
+
urdf_xacro_path: str,
|
| 22 |
+
srdf_xacro_path: str,
|
| 23 |
+
cluster_size: int,
|
| 24 |
+
set_affinity: bool = False,
|
| 25 |
+
use_mp_fork: bool = False,
|
| 26 |
+
isolated_cores_only: bool = False,
|
| 27 |
+
core_ids_override_list: List[int] = None,
|
| 28 |
+
verbose: bool = False,
|
| 29 |
+
debug: bool = False,
|
| 30 |
+
codegen_base_dirname: str = "CodeGen",
|
| 31 |
+
base_dump_dir: str = "/tmp",
|
| 32 |
+
codegen_override: str = None,
|
| 33 |
+
custom_opts: Dict = {}):
|
| 34 |
+
|
| 35 |
+
self._base_dump_dir = base_dump_dir
|
| 36 |
+
|
| 37 |
+
self._temp_path = base_dump_dir + "/" + f"{self.__class__.__name__}" + f"_{namespace}"
|
| 38 |
+
|
| 39 |
+
self._codegen_base_dirname = codegen_base_dirname
|
| 40 |
+
self._codegen_basedir = self._temp_path + "/" + self._codegen_base_dirname
|
| 41 |
+
|
| 42 |
+
self._codegen_override = codegen_override # can be used to manually override
|
| 43 |
+
# the default codegen dir
|
| 44 |
+
|
| 45 |
+
if not os.path.exists(self._temp_path):
|
| 46 |
+
os.makedirs(self._temp_path)
|
| 47 |
+
if not os.path.exists(self._codegen_basedir):
|
| 48 |
+
os.makedirs(self._codegen_basedir)
|
| 49 |
+
|
| 50 |
+
self._urdf_xacro_path = urdf_xacro_path
|
| 51 |
+
self._srdf_xacro_path = srdf_xacro_path
|
| 52 |
+
self._urdf_path=""
|
| 53 |
+
self._srdf_path=""
|
| 54 |
+
|
| 55 |
+
super().__init__(namespace = namespace,
|
| 56 |
+
cluster_size=cluster_size,
|
| 57 |
+
isolated_cores_only = isolated_cores_only,
|
| 58 |
+
set_affinity = set_affinity,
|
| 59 |
+
use_mp_fork = use_mp_fork,
|
| 60 |
+
core_ids_override_list = core_ids_override_list,
|
| 61 |
+
verbose = verbose,
|
| 62 |
+
debug = debug,
|
| 63 |
+
custom_opts=custom_opts)
|
| 64 |
+
self._generate_srdf(namespace=namespace)
|
| 65 |
+
|
| 66 |
+
self._generate_urdf(namespace=namespace)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def codegen_dir(self):
|
| 70 |
+
|
| 71 |
+
return self._codegen_basedir
|
| 72 |
+
|
| 73 |
+
def codegen_dir_override(self):
|
| 74 |
+
|
| 75 |
+
return self._codegen_override
|
| 76 |
+
|
| 77 |
+
def _generate_srdf(self,namespace:str):
|
| 78 |
+
|
| 79 |
+
custom_xacro_args=extract_custom_xacro_args(self._custom_opts)
|
| 80 |
+
cmds=merge_xacro_cmds(prev_cmds=self._xrdf_cmds(),
|
| 81 |
+
new_cmds=custom_xacro_args)
|
| 82 |
+
|
| 83 |
+
self._urdf_path=generate_urdf(robot_name=namespace,
|
| 84 |
+
xacro_path=self._urdf_xacro_path,
|
| 85 |
+
dump_path=self._temp_path,
|
| 86 |
+
xrdf_cmds=cmds)
|
| 87 |
+
|
| 88 |
+
def _generate_urdf(self,namespace:str):
|
| 89 |
+
|
| 90 |
+
custom_xacro_args=extract_custom_xacro_args(self._custom_opts)
|
| 91 |
+
cmds=merge_xacro_cmds(prev_cmds=self._xrdf_cmds(),
|
| 92 |
+
new_cmds=custom_xacro_args)
|
| 93 |
+
|
| 94 |
+
self._srdf_path=generate_srdf(robot_name=namespace,
|
| 95 |
+
xacro_path=self._srdf_xacro_path,
|
| 96 |
+
dump_path=self._temp_path,
|
| 97 |
+
xrdf_cmds=cmds)
|
| 98 |
+
|
| 99 |
+
@abstractmethod
|
| 100 |
+
def _xrdf_cmds(self):
|
| 101 |
+
|
| 102 |
+
# to be implemented by parent class (
|
| 103 |
+
# for an example have a look at utils/centauro_xrdf_gen.py)
|
| 104 |
+
|
| 105 |
+
pass
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/augmpc_cluster_server.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from mpc_hive.cluster_server.control_cluster_server import ControlClusterServer
|
| 2 |
+
from typing import List
|
| 3 |
+
from EigenIPC.PyEigenIPC import VLevel
|
| 4 |
+
|
| 5 |
+
class AugMpcClusterServer(ControlClusterServer):
|
| 6 |
+
|
| 7 |
+
def __init__(self,
|
| 8 |
+
robot_name: str,
|
| 9 |
+
cluster_size: int,
|
| 10 |
+
cluster_dt: float,
|
| 11 |
+
control_dt: float,
|
| 12 |
+
jnt_names: List[str],
|
| 13 |
+
n_contacts: int,
|
| 14 |
+
contact_linknames: List[str] = None,
|
| 15 |
+
verbose: bool = False,
|
| 16 |
+
vlevel: VLevel = VLevel.V1,
|
| 17 |
+
debug: bool = False,
|
| 18 |
+
use_gpu: bool = True,
|
| 19 |
+
force_reconnection: bool = True,
|
| 20 |
+
timeout_ms: int = 60000,
|
| 21 |
+
enable_height_sensor: bool = False,
|
| 22 |
+
height_grid_size: int = None,
|
| 23 |
+
height_grid_resolution: float = None):
|
| 24 |
+
|
| 25 |
+
self.robot_name = robot_name
|
| 26 |
+
|
| 27 |
+
super().__init__(
|
| 28 |
+
namespace=self.robot_name,
|
| 29 |
+
cluster_size=cluster_size,
|
| 30 |
+
cluster_dt=cluster_dt,
|
| 31 |
+
control_dt=control_dt,
|
| 32 |
+
jnt_names=jnt_names,
|
| 33 |
+
n_contacts = n_contacts,
|
| 34 |
+
contact_linknames = contact_linknames,
|
| 35 |
+
verbose=verbose,
|
| 36 |
+
vlevel=vlevel,
|
| 37 |
+
debug=debug,
|
| 38 |
+
use_gpu=use_gpu,
|
| 39 |
+
force_reconnection=force_reconnection,
|
| 40 |
+
timeout_ms=timeout_ms,
|
| 41 |
+
enable_height_sensor=enable_height_sensor,
|
| 42 |
+
height_grid_size=height_grid_size,
|
| 43 |
+
height_grid_resolution=height_grid_resolution)
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/__init__.py
ADDED
|
File without changes
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/config/rhc_horizon_config.yaml
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# A dummy example of a rhc controller configuration built on top of horizon
|
| 2 |
+
# and iLQR
|
| 3 |
+
|
| 4 |
+
solver:
|
| 5 |
+
type: ilqr
|
| 6 |
+
ilqr.tol: 0.01
|
| 7 |
+
ilqr.constr_viol_tol: 0.01
|
| 8 |
+
ilqr.suppress_all_output: 'yes'
|
| 9 |
+
ilqr.codegen_enabled: true
|
| 10 |
+
# ilqr.codegen_workdir: /tmp/tyhio
|
| 11 |
+
ilqr.enable_gn: true
|
| 12 |
+
ilqr.hxx_reg_base: 0.0
|
| 13 |
+
ilqr.n_threads: 0
|
| 14 |
+
print_time: 0
|
| 15 |
+
|
| 16 |
+
constraints:
|
| 17 |
+
- ball_1_contact
|
| 18 |
+
- ball_2_contact
|
| 19 |
+
- ball_3_contact
|
| 20 |
+
- ball_4_contact
|
| 21 |
+
- z_ball_1
|
| 22 |
+
- z_ball_2
|
| 23 |
+
- z_ball_3
|
| 24 |
+
- z_ball_4
|
| 25 |
+
|
| 26 |
+
costs:
|
| 27 |
+
- joint_regularization
|
| 28 |
+
- joint_posture
|
| 29 |
+
- base_position
|
| 30 |
+
- base_orientation
|
| 31 |
+
|
| 32 |
+
.define:
|
| 33 |
+
- &w_base_pos 10
|
| 34 |
+
- &w_base_ori 1
|
| 35 |
+
- &w_ball_z 1
|
| 36 |
+
# - &w_postural 0.0001
|
| 37 |
+
- &w_jnt_v_reg 0.01
|
| 38 |
+
- &w_jnt_a_reg 0.001
|
| 39 |
+
- &w_jnt_f_reg 0.0001
|
| 40 |
+
- &wheel_radius 0.124
|
| 41 |
+
|
| 42 |
+
base_position:
|
| 43 |
+
type: Cartesian
|
| 44 |
+
distal_link: base_link
|
| 45 |
+
indices: [0, 1, 2]
|
| 46 |
+
nodes: ${N}
|
| 47 |
+
weight: *w_base_pos
|
| 48 |
+
|
| 49 |
+
base_orientation:
|
| 50 |
+
type: Cartesian
|
| 51 |
+
distal_link: base_link
|
| 52 |
+
indices: [3, 4, 5]
|
| 53 |
+
nodes: ${N}
|
| 54 |
+
weight: *w_base_ori
|
| 55 |
+
|
| 56 |
+
# ===============================
|
| 57 |
+
|
| 58 |
+
rolling_contact_1:
|
| 59 |
+
type: Rolling
|
| 60 |
+
frame: wheel_1
|
| 61 |
+
radius: *wheel_radius
|
| 62 |
+
|
| 63 |
+
rolling_contact_2:
|
| 64 |
+
type: Rolling
|
| 65 |
+
frame: wheel_2
|
| 66 |
+
radius: *wheel_radius
|
| 67 |
+
|
| 68 |
+
rolling_contact_3:
|
| 69 |
+
type: Rolling
|
| 70 |
+
frame: wheel_3
|
| 71 |
+
radius: *wheel_radius
|
| 72 |
+
|
| 73 |
+
rolling_contact_4:
|
| 74 |
+
type: Rolling
|
| 75 |
+
frame: wheel_4
|
| 76 |
+
radius: *wheel_radius
|
| 77 |
+
|
| 78 |
+
# contact_1:
|
| 79 |
+
# type: Cartesian
|
| 80 |
+
# distal_link: ball_1
|
| 81 |
+
# indices: [0, 1, 2]
|
| 82 |
+
# cartesian_type: velocity
|
| 83 |
+
|
| 84 |
+
# contact_2:
|
| 85 |
+
# type: Cartesian
|
| 86 |
+
# distal_link: ball_2
|
| 87 |
+
# indices: [0, 1, 2]
|
| 88 |
+
# cartesian_type: velocity
|
| 89 |
+
|
| 90 |
+
# contact_3:
|
| 91 |
+
# type: Cartesian
|
| 92 |
+
# distal_link: ball_3
|
| 93 |
+
# indices: [0, 1, 2]
|
| 94 |
+
# cartesian_type: velocity
|
| 95 |
+
|
| 96 |
+
# contact_4:
|
| 97 |
+
# type: Cartesian
|
| 98 |
+
# distal_link: ball_4
|
| 99 |
+
# indices: [0, 1, 2]
|
| 100 |
+
# cartesian_type: velocity
|
| 101 |
+
|
| 102 |
+
# ==================================
|
| 103 |
+
|
| 104 |
+
interaction_wheel_1:
|
| 105 |
+
type: VertexForce
|
| 106 |
+
frame: ball_1
|
| 107 |
+
fn_min: 10.0
|
| 108 |
+
enable_fc: true
|
| 109 |
+
friction_coeff: 0.5
|
| 110 |
+
vertex_frames:
|
| 111 |
+
- wheel_1
|
| 112 |
+
|
| 113 |
+
interaction_wheel_2:
|
| 114 |
+
type: VertexForce
|
| 115 |
+
frame: ball_2
|
| 116 |
+
fn_min: 10.0
|
| 117 |
+
enable_fc: true
|
| 118 |
+
friction_coeff: 0.5
|
| 119 |
+
vertex_frames:
|
| 120 |
+
- wheel_2
|
| 121 |
+
|
| 122 |
+
interaction_wheel_3:
|
| 123 |
+
type: VertexForce
|
| 124 |
+
frame: ball_3
|
| 125 |
+
fn_min: 10.0
|
| 126 |
+
enable_fc: true
|
| 127 |
+
friction_coeff: 0.5
|
| 128 |
+
vertex_frames:
|
| 129 |
+
- wheel_3
|
| 130 |
+
|
| 131 |
+
interaction_wheel_4:
|
| 132 |
+
type: VertexForce
|
| 133 |
+
frame: ball_4
|
| 134 |
+
fn_min: 10.0
|
| 135 |
+
enable_fc: true
|
| 136 |
+
friction_coeff: 0.5
|
| 137 |
+
vertex_frames:
|
| 138 |
+
- wheel_4
|
| 139 |
+
|
| 140 |
+
ball_1_contact:
|
| 141 |
+
type: Contact
|
| 142 |
+
subtask: [interaction_wheel_1, rolling_contact_1]
|
| 143 |
+
|
| 144 |
+
ball_2_contact:
|
| 145 |
+
type: Contact
|
| 146 |
+
subtask: [interaction_wheel_2, rolling_contact_2]
|
| 147 |
+
|
| 148 |
+
ball_3_contact:
|
| 149 |
+
type: Contact
|
| 150 |
+
subtask: [interaction_wheel_3, rolling_contact_3]
|
| 151 |
+
|
| 152 |
+
ball_4_contact:
|
| 153 |
+
type: Contact
|
| 154 |
+
subtask: [interaction_wheel_4, rolling_contact_4]
|
| 155 |
+
|
| 156 |
+
# joint_posture:
|
| 157 |
+
# type: Postural
|
| 158 |
+
# weight: *w_postural
|
| 159 |
+
# indices: [0, 1, 2,
|
| 160 |
+
# 4, 5, 6,
|
| 161 |
+
# 8, 9, 10,
|
| 162 |
+
# 12, 13, 14]
|
| 163 |
+
# nodes: ${range(N-8, N)}
|
| 164 |
+
|
| 165 |
+
# todo: wrong, as the order COUNTS. If I add the contacts after the joint regularization, they wont get considered.
|
| 166 |
+
joint_regularization:
|
| 167 |
+
type: Regularization
|
| 168 |
+
nodes: all # maybe not on first nodes??
|
| 169 |
+
weight:
|
| 170 |
+
velocity: *w_jnt_v_reg
|
| 171 |
+
acceleration: *w_jnt_a_reg
|
| 172 |
+
force: *w_jnt_f_reg
|
| 173 |
+
|
| 174 |
+
z_ball_1:
|
| 175 |
+
type: Cartesian
|
| 176 |
+
distal_link: ball_1
|
| 177 |
+
indices: [2]
|
| 178 |
+
cartesian_type: position
|
| 179 |
+
weight: *w_ball_z
|
| 180 |
+
|
| 181 |
+
z_ball_2:
|
| 182 |
+
type: Cartesian
|
| 183 |
+
distal_link: ball_2
|
| 184 |
+
indices: [2]
|
| 185 |
+
cartesian_type: position
|
| 186 |
+
weight: *w_ball_z
|
| 187 |
+
|
| 188 |
+
z_ball_3:
|
| 189 |
+
type: Cartesian
|
| 190 |
+
distal_link: ball_3
|
| 191 |
+
indices: [2]
|
| 192 |
+
cartesian_type: position
|
| 193 |
+
weight: *w_ball_z
|
| 194 |
+
|
| 195 |
+
z_ball_4:
|
| 196 |
+
type: Cartesian
|
| 197 |
+
distal_link: ball_4
|
| 198 |
+
indices: [2]
|
| 199 |
+
cartesian_type: position
|
| 200 |
+
weight: *w_ball_z
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/gait_manager.py
ADDED
|
@@ -0,0 +1,565 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
|
| 3 |
+
from aug_mpc.controllers.rhc.horizon_based.horizon_imports import *
|
| 4 |
+
|
| 5 |
+
from EigenIPC.PyEigenIPC import VLevel
|
| 6 |
+
from EigenIPC.PyEigenIPC import Journal, LogType
|
| 7 |
+
|
| 8 |
+
from typing import Dict
|
| 9 |
+
|
| 10 |
+
class GaitManager:
|
| 11 |
+
|
| 12 |
+
def __init__(self,
|
| 13 |
+
task_interface: TaskInterface,
|
| 14 |
+
phase_manager: pymanager.PhaseManager,
|
| 15 |
+
injection_node: int = None,
|
| 16 |
+
keep_yaw_vert: bool = False,
|
| 17 |
+
yaw_vertical_weight: float = None,
|
| 18 |
+
vertical_landing: bool = False,
|
| 19 |
+
landing_vert_weight: float = None,
|
| 20 |
+
phase_force_reg: float = None,
|
| 21 |
+
flight_duration: int = 15,
|
| 22 |
+
post_flight_stance: int = 3,
|
| 23 |
+
step_height: float = 0.1,
|
| 24 |
+
dh: float = 0.0,
|
| 25 |
+
custom_opts: Dict = {}):
|
| 26 |
+
|
| 27 |
+
self._custom_opts=custom_opts
|
| 28 |
+
|
| 29 |
+
self._is_open_loop=False
|
| 30 |
+
if "is_open_loop" in self._custom_opts:
|
| 31 |
+
self._is_open_loop=self._custom_opts["is_open_loop"]
|
| 32 |
+
|
| 33 |
+
self.task_interface = task_interface
|
| 34 |
+
self._n_nodes_prb=self.task_interface.prb.getNNodes()
|
| 35 |
+
|
| 36 |
+
self._phase_manager = phase_manager
|
| 37 |
+
self._model=self.task_interface.model
|
| 38 |
+
self._q0=self._model.q0
|
| 39 |
+
self._kin_dyn=self.task_interface.model.kd
|
| 40 |
+
|
| 41 |
+
# phase weights and regs
|
| 42 |
+
self._keep_yaw_vert=keep_yaw_vert
|
| 43 |
+
self._yaw_vertical_weight=yaw_vertical_weight
|
| 44 |
+
self._vertical_landing=vertical_landing
|
| 45 |
+
self._landing_vert_weight=landing_vert_weight
|
| 46 |
+
self._phase_force_reg=phase_force_reg
|
| 47 |
+
self._total_weight = np.atleast_2d(np.array([0, 0, self._kin_dyn.mass() * 9.81])).T
|
| 48 |
+
|
| 49 |
+
self._f_reg_ref={}
|
| 50 |
+
|
| 51 |
+
# flight parameters
|
| 52 |
+
self._post_flight_stance=post_flight_stance
|
| 53 |
+
self._flight_info_now=None
|
| 54 |
+
self._flight_duration_max=self._n_nodes_prb-(injection_node+1)
|
| 55 |
+
self._flight_duration_min=3
|
| 56 |
+
self._flight_duration_default=flight_duration
|
| 57 |
+
# apex bounds/defaults
|
| 58 |
+
self._step_height_default=step_height
|
| 59 |
+
self._step_height_min=0.0
|
| 60 |
+
self._step_height_max=0.5
|
| 61 |
+
# end height bounds/defaults
|
| 62 |
+
self._dh_default=dh
|
| 63 |
+
self._dh_min=0.0
|
| 64 |
+
self._dh_max=0.5
|
| 65 |
+
# landing dx, dy bounds/defaults
|
| 66 |
+
self._land_dx_default=0.0
|
| 67 |
+
self._land_dx_min=-0.5
|
| 68 |
+
self._land_dx_max=0.5
|
| 69 |
+
self._land_dy_default=0.0
|
| 70 |
+
self._land_dy_min=-0.5
|
| 71 |
+
self._land_dy_max=0.5
|
| 72 |
+
|
| 73 |
+
# timeline data
|
| 74 |
+
self._contact_timelines = dict()
|
| 75 |
+
self.timeline_names=[]
|
| 76 |
+
|
| 77 |
+
self._flight_phases = {}
|
| 78 |
+
self._touchdown_phases = {}
|
| 79 |
+
self._contact_phases = {}
|
| 80 |
+
self._fk_contacts = {}
|
| 81 |
+
self._fkd_contacts = {}
|
| 82 |
+
self._f_reg_ref = {}
|
| 83 |
+
|
| 84 |
+
# reference traj
|
| 85 |
+
self._tg = trajectoryGenerator.TrajectoryGenerator()
|
| 86 |
+
self._traj_der= [None, 0, 0]
|
| 87 |
+
self._traj_second_der=[None, 0, 0]
|
| 88 |
+
self._third_traj_der=[None, None, 0]
|
| 89 |
+
|
| 90 |
+
self._ref_trjs = {}
|
| 91 |
+
self._ref_vtrjs = {}
|
| 92 |
+
|
| 93 |
+
if injection_node is None:
|
| 94 |
+
self._injection_node = round(self.task_interface.prb.getNNodes()/2.0)
|
| 95 |
+
else:
|
| 96 |
+
self._injection_node = injection_node
|
| 97 |
+
|
| 98 |
+
self._init_contact_timelines()
|
| 99 |
+
|
| 100 |
+
self._reset_contact_timelines()
|
| 101 |
+
|
| 102 |
+
def _init_contact_timelines(self):
|
| 103 |
+
|
| 104 |
+
short_stance_duration=1
|
| 105 |
+
flight_phase_short_duration=1
|
| 106 |
+
|
| 107 |
+
self.n_contacts=len(self._model.cmap.keys())
|
| 108 |
+
self._dt=float(self.task_interface.prb.getDt())
|
| 109 |
+
|
| 110 |
+
self._name_to_idx_map={}
|
| 111 |
+
|
| 112 |
+
j=0
|
| 113 |
+
for contact in self._model.cmap.keys():
|
| 114 |
+
|
| 115 |
+
self._fk_contacts[contact]=self._kin_dyn.fk(contact)
|
| 116 |
+
self._fkd_contacts[contact]=self._kin_dyn.frameVelocity(contact, self._model.kd_frame)
|
| 117 |
+
self.timeline_names.append(contact)
|
| 118 |
+
self._contact_timelines[contact]=self._phase_manager.createTimeline(f'{contact}_timeline')
|
| 119 |
+
# stances
|
| 120 |
+
self._contact_phases[contact] = self._contact_timelines[contact].createPhase(short_stance_duration,
|
| 121 |
+
f'stance_{contact}_short')
|
| 122 |
+
|
| 123 |
+
if self.task_interface.getTask(f'{contact}') is not None:
|
| 124 |
+
self._contact_phases[contact].addItem(self.task_interface.getTask(f'{contact}'))
|
| 125 |
+
else:
|
| 126 |
+
Journal.log(self.__class__.__name__,
|
| 127 |
+
"_init_contact_timelines",
|
| 128 |
+
f"contact task {contact} not found",
|
| 129 |
+
LogType.EXCEP,
|
| 130 |
+
throw_when_excep=True)
|
| 131 |
+
i=0
|
| 132 |
+
self._f_reg_ref[contact]=[]
|
| 133 |
+
for force in self._model.cmap[contact]:
|
| 134 |
+
f_ref=self.task_interface.prb.createParameter(name=f"{contact}_force_reg_f{i}_ref",
|
| 135 |
+
dim=3)
|
| 136 |
+
force_reg=self.task_interface.prb.createResidual(f'{contact}_force_reg_f{i}', self._phase_force_reg * (force - f_ref),
|
| 137 |
+
nodes=[])
|
| 138 |
+
self._f_reg_ref[contact].append(f_ref)
|
| 139 |
+
self.set_f_reg(contact_name=contact, scale=4)
|
| 140 |
+
self._contact_phases[contact].addCost(force_reg, nodes=list(range(0, short_stance_duration)))
|
| 141 |
+
i+=1
|
| 142 |
+
|
| 143 |
+
# flights
|
| 144 |
+
self._flight_phases[contact]=self._contact_timelines[contact].createPhase(flight_phase_short_duration,
|
| 145 |
+
f'flight_{contact}_short')
|
| 146 |
+
|
| 147 |
+
# sanity checks (z trajectory)
|
| 148 |
+
self._zpos_task_found=True
|
| 149 |
+
self._zvel_task_found=True
|
| 150 |
+
self._xypos_task_found=True
|
| 151 |
+
self._xyvel_task_found=True
|
| 152 |
+
if self.task_interface.getTask(f'z_{contact}') is None:
|
| 153 |
+
self._zpos_task_found=False
|
| 154 |
+
if self.task_interface.getTask(f'vz_{contact}') is None:
|
| 155 |
+
self._zvel_task_found=False
|
| 156 |
+
if self.task_interface.getTask(f'xy_{contact}') is None:
|
| 157 |
+
self._xypos_task_found=False
|
| 158 |
+
if self.task_interface.getTask(f'vxy_{contact}') is None:
|
| 159 |
+
self._xyvel_task_found=False
|
| 160 |
+
if (not self._zpos_task_found) and (not self._zvel_task_found):
|
| 161 |
+
Journal.log(self.__class__.__name__,
|
| 162 |
+
"_init_contact_timelines",
|
| 163 |
+
f"neither pos or vel task for contacts were found! Aborting.",
|
| 164 |
+
LogType.EXCEP,
|
| 165 |
+
throw_when_excep=True)
|
| 166 |
+
if (not self._zpos_task_found) and self._is_open_loop:
|
| 167 |
+
Journal.log(self.__class__.__name__,
|
| 168 |
+
"_init_contact_timelines",
|
| 169 |
+
f"Running in open loop, but no contact pos task found. Aborting.",
|
| 170 |
+
LogType.EXCEP,
|
| 171 |
+
throw_when_excep=True)
|
| 172 |
+
if self._zpos_task_found and self._xyvel_task_found:
|
| 173 |
+
Journal.log(self.__class__.__name__,
|
| 174 |
+
"_init_contact_timelines",
|
| 175 |
+
f"Both pos and vel task for contact {contact} found! This is not allowed, aborting.",
|
| 176 |
+
LogType.EXCEP,
|
| 177 |
+
throw_when_excep=True)
|
| 178 |
+
if self._zvel_task_found and self._xypos_task_found:
|
| 179 |
+
Journal.log(self.__class__.__name__,
|
| 180 |
+
"_init_contact_timelines",
|
| 181 |
+
f"Both pos and vel task for contact {contact} found! This is not allowed, aborting.",
|
| 182 |
+
LogType.EXCEP,
|
| 183 |
+
throw_when_excep=True)
|
| 184 |
+
if (not self._xypos_task_found) and (not self._xyvel_task_found):
|
| 185 |
+
Journal.log(self.__class__.__name__,
|
| 186 |
+
"_init_contact_timelines",
|
| 187 |
+
f"neither pos or vel task for contact {contact} xy were found! Will proceed without xy landing constraints.",
|
| 188 |
+
LogType.WARN)
|
| 189 |
+
# if (not self._zvel_task_found) and (not self._is_open_loop):
|
| 190 |
+
# Journal.log(self.__class__.__name__,
|
| 191 |
+
# "_init_contact_timelines",
|
| 192 |
+
# f"Running in closed loop, but contact vel task not found. Aborting",
|
| 193 |
+
# LogType.EXCEP,
|
| 194 |
+
# throw_when_excep=True)
|
| 195 |
+
|
| 196 |
+
self._ref_trjs[contact]=None
|
| 197 |
+
self._ref_vtrjs[contact]=None
|
| 198 |
+
if self._zpos_task_found: # we use pos trajectory
|
| 199 |
+
self._ref_trjs[contact]=np.zeros(shape=[7, self.task_interface.prb.getNNodes()])
|
| 200 |
+
init_z_foot = self._fk_contacts[contact](q=self._q0)['ee_pos'].elements()[2]
|
| 201 |
+
if self._is_open_loop:
|
| 202 |
+
self._ref_trjs[contact][2, :] = np.atleast_2d(init_z_foot)
|
| 203 |
+
else:
|
| 204 |
+
self._ref_trjs[contact][2, :] = 0.0 # place foot at ground level initially ()
|
| 205 |
+
|
| 206 |
+
if self._xypos_task_found: # xy
|
| 207 |
+
self._flight_phases[contact].addItemReference(self.task_interface.getTask(f'xy_{contact}'),
|
| 208 |
+
self._ref_trjs[contact][0:2, 0:1],
|
| 209 |
+
nodes=list(range(0, flight_phase_short_duration)))
|
| 210 |
+
self._touchdown_phases[contact]=None
|
| 211 |
+
# z
|
| 212 |
+
self._flight_phases[contact].addItemReference(self.task_interface.getTask(f'z_{contact}'),
|
| 213 |
+
self._ref_trjs[contact][2, 0:1],
|
| 214 |
+
nodes=list(range(0, flight_phase_short_duration)))
|
| 215 |
+
|
| 216 |
+
self._touchdown_phases[contact]=None
|
| 217 |
+
|
| 218 |
+
else: # foot traj in velocity
|
| 219 |
+
# ref vel traj
|
| 220 |
+
self._ref_vtrjs[contact]=np.zeros(shape=[7, self.task_interface.prb.getNNodes()]) # allocate traj
|
| 221 |
+
# of max length eual to number of nodes
|
| 222 |
+
self._ref_vtrjs[contact][2, :] = np.atleast_2d(0)
|
| 223 |
+
|
| 224 |
+
if self._xyvel_task_found: # xy
|
| 225 |
+
self._flight_phases[contact].addItemReference(self.task_interface.getTask(f'vxy_{contact}'),
|
| 226 |
+
self._ref_vtrjs[contact][0:2, 0:1],
|
| 227 |
+
nodes=list(range(0, flight_phase_short_duration)))
|
| 228 |
+
# z
|
| 229 |
+
self._flight_phases[contact].addItemReference(self.task_interface.getTask(f'vz_{contact}'),
|
| 230 |
+
self._ref_vtrjs[contact][2, 0:1],
|
| 231 |
+
nodes=list(range(0, flight_phase_short_duration)))
|
| 232 |
+
self._touchdown_phases[contact]=self._contact_timelines[contact].createPhase(flight_phase_short_duration,
|
| 233 |
+
f'touchdown_{contact}_short')
|
| 234 |
+
# self._touchdown_phases[contact].addItemReference(self.task_interface.getTask(f'vz_{contact}'),
|
| 235 |
+
# self._ref_vtrjs[contact][2, 0:1],
|
| 236 |
+
# nodes=list(range(0, flight_phase_short_duration)))
|
| 237 |
+
|
| 238 |
+
# ee_vel=self._fkd_contacts[contact](q=self._model.q,
|
| 239 |
+
# qdot=self._model.v)['ee_vel_linear']
|
| 240 |
+
# cstr = self.task_interface.prb.createConstraint(f'{contact}_vert', ee_vel[0:2], [])
|
| 241 |
+
# self._flight_phases[contact].addConstraint(cstr, nodes=[0, flight_phase_short_duration-1])
|
| 242 |
+
if self._keep_yaw_vert:
|
| 243 |
+
# keep ankle vertical
|
| 244 |
+
c_ori = self._model.kd.fk(contact)(q=self._model.q)['ee_rot'][2, :]
|
| 245 |
+
cost_ori = self.task_interface.prb.createResidual(f'{contact}_ori', self._yaw_vertical_weight * (c_ori.T - np.array([0, 0, 1])))
|
| 246 |
+
# flight_phase.addCost(cost_ori, nodes=list(range(0, flight_duration+post_landing_stance)))
|
| 247 |
+
|
| 248 |
+
if self._vertical_landing and self._touchdown_phases[contact] is not None:
|
| 249 |
+
v_xy=self._fkd_contacts[contact](q=self._model.q, qdot=self._model.v)['ee_vel_linear'][0:2]
|
| 250 |
+
vertical_landing=self.task_interface.prb.createResidual(f'{contact}_only_vert_v',
|
| 251 |
+
self._landing_vert_weight * v_xy,
|
| 252 |
+
nodes=[])
|
| 253 |
+
self._touchdown_phases[contact].addCost(vertical_landing, nodes=list(range(0, short_stance_duration)))
|
| 254 |
+
|
| 255 |
+
self._name_to_idx_map[contact]=j
|
| 256 |
+
|
| 257 |
+
j+=1
|
| 258 |
+
|
| 259 |
+
# current pos [c0, c1, ....], current length, nominal length, nom. apex, no. landing height, landing dx, landing dy (local world aligned)
|
| 260 |
+
self._flight_info_now=np.zeros(shape=(7*self.n_contacts))
|
| 261 |
+
|
| 262 |
+
self.update()
|
| 263 |
+
|
| 264 |
+
def _reset_contact_timelines(self):
|
| 265 |
+
|
| 266 |
+
for contact in self._model.cmap.keys():
|
| 267 |
+
|
| 268 |
+
idx=self._name_to_idx_map[contact]
|
| 269 |
+
# we follow same order as in shm for more efficient writing
|
| 270 |
+
self._flight_info_now[idx]= -1.0 # pos [nodes]
|
| 271 |
+
self._flight_info_now[idx+1*self.n_contacts]= -1.0 # duration (remaining) [nodes]
|
| 272 |
+
self._flight_info_now[idx+2*self.n_contacts]=self._flight_duration_default # [nodes]
|
| 273 |
+
self._flight_info_now[idx+3*self.n_contacts]=self._step_height_default
|
| 274 |
+
self._flight_info_now[idx+4*self.n_contacts]=self._dh_default
|
| 275 |
+
self._flight_info_now[idx+5*self.n_contacts]=self._land_dx_default
|
| 276 |
+
self._flight_info_now[idx+6*self.n_contacts]=self._land_dy_default
|
| 277 |
+
# fill timeline with stances
|
| 278 |
+
contact_timeline=self._contact_timelines[contact]
|
| 279 |
+
contact_timeline.clear() # remove phases
|
| 280 |
+
short_stance_phase = contact_timeline.getRegisteredPhase(f'stance_{contact}_short')
|
| 281 |
+
while contact_timeline.getEmptyNodes() > 0:
|
| 282 |
+
contact_timeline.addPhase(short_stance_phase)
|
| 283 |
+
|
| 284 |
+
self.update()
|
| 285 |
+
|
| 286 |
+
def reset(self):
|
| 287 |
+
# self.phase_manager.clear()
|
| 288 |
+
self.task_interface.reset()
|
| 289 |
+
self._reset_contact_timelines()
|
| 290 |
+
|
| 291 |
+
def set_f_reg(self,
|
| 292 |
+
contact_name,
|
| 293 |
+
scale: float = 4.0):
|
| 294 |
+
f_refs=self._f_reg_ref[contact_name]
|
| 295 |
+
for force in f_refs:
|
| 296 |
+
ref=self._total_weight/(scale*len(f_refs))
|
| 297 |
+
force.assign(ref)
|
| 298 |
+
|
| 299 |
+
def set_flight_duration(self, contact_name, val: float):
|
| 300 |
+
self._flight_info_now[self._name_to_idx_map[contact_name]+2*self.n_contacts]=val
|
| 301 |
+
|
| 302 |
+
def get_flight_duration(self, contact_name):
|
| 303 |
+
return self._flight_info_now[self._name_to_idx_map[contact_name]+2*self.n_contacts]
|
| 304 |
+
|
| 305 |
+
def set_step_apexdh(self, contact_name, val: float):
|
| 306 |
+
self._flight_info_now[self._name_to_idx_map[contact_name]+3*self.n_contacts]=val
|
| 307 |
+
|
| 308 |
+
def get_step_apexdh(self, contact_name):
|
| 309 |
+
return self._flight_info_now[self._name_to_idx_map[contact_name]+3*self.n_contacts]
|
| 310 |
+
|
| 311 |
+
def set_step_enddh(self, contact_name, val: float):
|
| 312 |
+
self._flight_info_now[self._name_to_idx_map[contact_name]+4*self.n_contacts]=val
|
| 313 |
+
|
| 314 |
+
def get_step_enddh(self, contact_name):
|
| 315 |
+
return self._flight_info_now[self._name_to_idx_map[contact_name]+4*self.n_contacts]
|
| 316 |
+
|
| 317 |
+
def get_step_landing_dx(self, contact_name):
|
| 318 |
+
return self._flight_info_now[self._name_to_idx_map[contact_name]+5*self.n_contacts]
|
| 319 |
+
|
| 320 |
+
def set_step_landing_dx(self, contact_name, val: float):
|
| 321 |
+
self._flight_info_now[self._name_to_idx_map[contact_name]+5*self.n_contacts]=val
|
| 322 |
+
|
| 323 |
+
def get_step_landing_dy(self, contact_name):
|
| 324 |
+
return self._flight_info_now[self._name_to_idx_map[contact_name]+6*self.n_contacts]
|
| 325 |
+
|
| 326 |
+
def set_step_landing_dy(self, contact_name, val: float):
|
| 327 |
+
self._flight_info_now[self._name_to_idx_map[contact_name]+6*self.n_contacts]=val
|
| 328 |
+
|
| 329 |
+
def add_stand(self, contact_name):
|
| 330 |
+
# always add stand at the end of the horizon
|
| 331 |
+
timeline = self._contact_timelines[contact_name]
|
| 332 |
+
if timeline.getEmptyNodes() > 0:
|
| 333 |
+
timeline.addPhase(timeline.getRegisteredPhase(f'stance_{contact_name}_short'))
|
| 334 |
+
|
| 335 |
+
def add_flight(self, contact_name,
|
| 336 |
+
robot_q: np.ndarray):
|
| 337 |
+
|
| 338 |
+
timeline = self._contact_timelines[contact_name]
|
| 339 |
+
|
| 340 |
+
flights_on_horizon=self._contact_timelines[contact_name].getPhaseIdx(self._flight_phases[contact_name])
|
| 341 |
+
|
| 342 |
+
last_flight_idx=self._injection_node-1 # default to make things work
|
| 343 |
+
if not len(flights_on_horizon)==0: # some flight phases are there
|
| 344 |
+
last_flight_idx=flights_on_horizon[-1]+self._post_flight_stance
|
| 345 |
+
|
| 346 |
+
if last_flight_idx<self._injection_node: # allow injecting
|
| 347 |
+
|
| 348 |
+
flight_duration_req=int(self.get_flight_duration(contact_name=contact_name))
|
| 349 |
+
flight_apex_req=self.get_step_apexdh(contact_name=contact_name)
|
| 350 |
+
flight_enddh_req=self.get_step_enddh(contact_name=contact_name)
|
| 351 |
+
flight_land_dx_req=self.get_step_landing_dx(contact_name=contact_name)
|
| 352 |
+
flight_land_dy_req=self.get_step_landing_dy(contact_name=contact_name)
|
| 353 |
+
if not flight_duration_req>1:
|
| 354 |
+
Journal.log(self.__class__.__name__,
|
| 355 |
+
"add_flight",
|
| 356 |
+
f"Got flight duration {flight_duration_req} < 1!",
|
| 357 |
+
LogType.WARN,
|
| 358 |
+
throw_when_excep=True)
|
| 359 |
+
|
| 360 |
+
# process requests to ensure flight params are valid
|
| 361 |
+
# duration
|
| 362 |
+
if flight_duration_req<self._flight_duration_min:
|
| 363 |
+
flight_duration_req=self._flight_duration_min
|
| 364 |
+
if flight_duration_req>self._flight_duration_max:
|
| 365 |
+
flight_duration_req=self._flight_duration_max
|
| 366 |
+
# apex height
|
| 367 |
+
if flight_apex_req<self._step_height_min:
|
| 368 |
+
flight_apex_req=self._step_height_min
|
| 369 |
+
if flight_apex_req>self._step_height_max:
|
| 370 |
+
flight_apex_req=self._step_height_max
|
| 371 |
+
# landing height
|
| 372 |
+
if flight_enddh_req<self._dh_min:
|
| 373 |
+
flight_enddh_req=self._dh_min
|
| 374 |
+
if flight_enddh_req>self._dh_max:
|
| 375 |
+
flight_enddh_req=self._dh_max
|
| 376 |
+
# landing dx
|
| 377 |
+
if flight_land_dx_req<self._land_dx_min:
|
| 378 |
+
flight_land_dx_req=self._land_dx_min
|
| 379 |
+
if flight_land_dx_req>self._land_dx_max:
|
| 380 |
+
flight_land_dx_req=self._land_dx_max
|
| 381 |
+
# landing dy
|
| 382 |
+
if flight_land_dy_req<self._land_dy_min:
|
| 383 |
+
flight_land_dy_req=self._land_dy_min
|
| 384 |
+
if flight_land_dy_req>self._land_dy_max:
|
| 385 |
+
flight_land_dy_req=self._land_dy_max
|
| 386 |
+
|
| 387 |
+
land_dx_w = flight_land_dx_req
|
| 388 |
+
land_dy_w = flight_land_dy_req
|
| 389 |
+
if self._xypos_task_found or self._xyvel_task_found:
|
| 390 |
+
# landing dx/dy are specified in horizontal frame; rotate into world aligned frame
|
| 391 |
+
q_base = robot_q[3:7]
|
| 392 |
+
if q_base.ndim == 1:
|
| 393 |
+
q_base = q_base.reshape(-1, 1)
|
| 394 |
+
q_w = q_base[3, 0]
|
| 395 |
+
q_x = q_base[0, 0]
|
| 396 |
+
q_y = q_base[1, 0]
|
| 397 |
+
q_z = q_base[2, 0]
|
| 398 |
+
r11 = 1 - 2 * (q_y * q_y + q_z * q_z)
|
| 399 |
+
r21 = 2 * (q_x * q_y + q_z * q_w)
|
| 400 |
+
norm = np.hypot(r11, r21)
|
| 401 |
+
if norm > 0.0:
|
| 402 |
+
cos_yaw = r11 / norm
|
| 403 |
+
sin_yaw = r21 / norm
|
| 404 |
+
else:
|
| 405 |
+
cos_yaw = 1.0
|
| 406 |
+
sin_yaw = 0.
|
| 407 |
+
|
| 408 |
+
land_dx_w = flight_land_dx_req * cos_yaw - flight_land_dy_req * sin_yaw
|
| 409 |
+
land_dy_w = flight_land_dx_req * sin_yaw + flight_land_dy_req * cos_yaw
|
| 410 |
+
|
| 411 |
+
if self._ref_vtrjs[contact_name] is not None and \
|
| 412 |
+
self._ref_trjs[contact_name] is not None: # only allow one mode (pos/velocity traj)
|
| 413 |
+
Journal.log(self.__class__.__name__,
|
| 414 |
+
"add_flight",
|
| 415 |
+
f"Both pos and vel traj for contact {contact_name} are not None! This is not allowed, aborting.",
|
| 416 |
+
LogType.EXCEP,
|
| 417 |
+
throw_when_excep=True)
|
| 418 |
+
|
| 419 |
+
# inject pos traj if pos mode
|
| 420 |
+
if self._ref_trjs[contact_name] is not None:
|
| 421 |
+
# recompute trajectory online (just needed if using pos traj)
|
| 422 |
+
foot_pos=self._fk_contacts[contact_name](q=robot_q)['ee_pos'].elements()
|
| 423 |
+
starting_pos=foot_pos[2] # compute foot traj (local world aligned)
|
| 424 |
+
starting_x_pos=foot_pos[0]
|
| 425 |
+
starting_y_pos=foot_pos[1]
|
| 426 |
+
# starting_pos=0.0
|
| 427 |
+
self._ref_trjs[contact_name][2, 0:flight_duration_req]=np.atleast_2d(self._tg.from_derivatives(
|
| 428 |
+
flight_duration_req,
|
| 429 |
+
p_start=starting_pos,
|
| 430 |
+
p_goal=starting_pos+flight_enddh_req,
|
| 431 |
+
clearance=flight_apex_req,
|
| 432 |
+
derivatives=self._traj_der,
|
| 433 |
+
second_der=self._traj_second_der,
|
| 434 |
+
third_der=self._third_traj_der)
|
| 435 |
+
)
|
| 436 |
+
if self._xypos_task_found:
|
| 437 |
+
self._ref_trjs[contact_name][0, 0:flight_duration_req]=starting_x_pos+land_dx_w
|
| 438 |
+
self._ref_trjs[contact_name][1, 0:flight_duration_req]=starting_y_pos+land_dy_w
|
| 439 |
+
|
| 440 |
+
for i in range(flight_duration_req):
|
| 441 |
+
res, phase_token=timeline.addPhase(self._flight_phases[contact_name],
|
| 442 |
+
pos=self._injection_node+i,
|
| 443 |
+
absolute_position=True)
|
| 444 |
+
phase_token.setItemReference(f'z_{contact_name}',
|
| 445 |
+
self._ref_trjs[contact_name][:, i])
|
| 446 |
+
if self._xypos_task_found:
|
| 447 |
+
phase_token.setItemReference(f'xy_{contact_name}',
|
| 448 |
+
self._ref_trjs[contact_name][:, i])
|
| 449 |
+
if self._touchdown_phases[contact_name] is not None:
|
| 450 |
+
# add touchdown phase for forcing vertical landing
|
| 451 |
+
res, phase_token=timeline.addPhase(self._touchdown_phases[contact_name],
|
| 452 |
+
pos=self._injection_node+flight_duration_req,
|
| 453 |
+
absolute_position=True)
|
| 454 |
+
|
| 455 |
+
# inject vel traj if vel mode
|
| 456 |
+
if self._ref_vtrjs[contact_name] is not None:
|
| 457 |
+
self._ref_vtrjs[contact_name][2, 0:flight_duration_req]=np.atleast_2d(self._tg.derivative_of_trajectory(
|
| 458 |
+
flight_duration_req,
|
| 459 |
+
p_start=0.0,
|
| 460 |
+
p_goal=flight_enddh_req,
|
| 461 |
+
clearance=flight_apex_req,
|
| 462 |
+
derivatives=self._traj_der,
|
| 463 |
+
second_der=self._traj_second_der,
|
| 464 |
+
third_der=self._third_traj_der))
|
| 465 |
+
if self._xyvel_task_found: # compute vel reference using problem dt and flight length
|
| 466 |
+
flight_duration_sec=float(flight_duration_req)*self._dt
|
| 467 |
+
self._ref_vtrjs[contact_name][0, 0:flight_duration_req]=land_dx_w/flight_duration_sec
|
| 468 |
+
self._ref_vtrjs[contact_name][1, 0:flight_duration_req]=land_dy_w/flight_duration_sec
|
| 469 |
+
|
| 470 |
+
for i in range(flight_duration_req):
|
| 471 |
+
res, phase_token=timeline.addPhase(self._flight_phases[contact_name],
|
| 472 |
+
pos=self._injection_node+i,
|
| 473 |
+
absolute_position=True)
|
| 474 |
+
phase_token.setItemReference(f'vz_{contact_name}',
|
| 475 |
+
self._ref_vtrjs[contact_name][2:3, i:i+1])
|
| 476 |
+
if self._touchdown_phases[contact_name] is not None:
|
| 477 |
+
# add touchdown phase for forcing vertical landing
|
| 478 |
+
res, phase_token=timeline.addPhase(self._touchdown_phases[contact_name],
|
| 479 |
+
pos=self._injection_node+flight_duration_req,
|
| 480 |
+
absolute_position=True)
|
| 481 |
+
|
| 482 |
+
if timeline.getEmptyNodes() > 0: # fill empty nodes at the end of the horizon, if any, with stance
|
| 483 |
+
timeline.addPhase(timeline.getRegisteredPhase(f'stance_{contact_name}_short'))
|
| 484 |
+
|
| 485 |
+
def update(self):
|
| 486 |
+
self._phase_manager.update()
|
| 487 |
+
|
| 488 |
+
def update_flight_info(self, timeline_name):
|
| 489 |
+
|
| 490 |
+
# get current position and remaining duration of flight phases over the horizon for a single contact
|
| 491 |
+
|
| 492 |
+
# phase indexes over timeline
|
| 493 |
+
phase_idxs=self._contact_timelines[timeline_name].getPhaseIdx(self._flight_phases[timeline_name])
|
| 494 |
+
|
| 495 |
+
if not len(phase_idxs)==0: # at least one flight phase on horizon -> read info from timeline
|
| 496 |
+
|
| 497 |
+
# all active phases on timeline
|
| 498 |
+
active_phases=self._contact_timelines[timeline_name].getActivePhases()
|
| 499 |
+
|
| 500 |
+
phase_idx_start=phase_idxs[0]
|
| 501 |
+
# active_nodes_start=active_phases[phase_idx_start].getActiveNodes()
|
| 502 |
+
pos_start=active_phases[phase_idx_start].getPosition()
|
| 503 |
+
# n_nodes_start=active_phases[phase_idx_start].getNNodes()
|
| 504 |
+
|
| 505 |
+
phase_idx_last=phase_idxs[-1] # just get info for last phase on the horizon
|
| 506 |
+
# active_nodes_last=active_phases[phase_idx_last].getActiveNodes()
|
| 507 |
+
pos_last=active_phases[phase_idx_last].getPosition()
|
| 508 |
+
# n_nodes_last=active_phases[phase_idx_last].getNNodes()
|
| 509 |
+
|
| 510 |
+
# write to info
|
| 511 |
+
self._flight_info_now[self._name_to_idx_map[timeline_name]+0*self.n_contacts]=pos_last
|
| 512 |
+
self._flight_info_now[self._name_to_idx_map[timeline_name]+1*self.n_contacts]=pos_last - pos_start
|
| 513 |
+
|
| 514 |
+
return True
|
| 515 |
+
|
| 516 |
+
return False
|
| 517 |
+
|
| 518 |
+
def get_flight_info(self, timeline_name):
|
| 519 |
+
return (self._flight_info_now[self._name_to_idx_map[timeline_name]+0*self.n_contacts],
|
| 520 |
+
self._flight_info_now[self._name_to_idx_map[timeline_name]+1*self.n_contacts],
|
| 521 |
+
self._flight_info_now[self._name_to_idx_map[timeline_name]+2*self.n_contacts],
|
| 522 |
+
self._flight_info_now[self._name_to_idx_map[timeline_name]+3*self.n_contacts],
|
| 523 |
+
self._flight_info_now[self._name_to_idx_map[timeline_name]+4*self.n_contacts],
|
| 524 |
+
self._flight_info_now[self._name_to_idx_map[timeline_name]+5*self.n_contacts],
|
| 525 |
+
self._flight_info_now[self._name_to_idx_map[timeline_name]+6*self.n_contacts])
|
| 526 |
+
|
| 527 |
+
def get_flight_info_all(self):
|
| 528 |
+
return self._flight_info_now
|
| 529 |
+
|
| 530 |
+
def set_ref_pos(self,
|
| 531 |
+
timeline_name:str,
|
| 532 |
+
ref_height: np.array = None,
|
| 533 |
+
threshold: float = 0.05):
|
| 534 |
+
|
| 535 |
+
if ref_height is not None:
|
| 536 |
+
self._ref_trjs[timeline_name][2, :]=ref_height
|
| 537 |
+
if ref_height>threshold:
|
| 538 |
+
self.add_flight(timeline_name=timeline_name)
|
| 539 |
+
this_flight_token_idx=self._contact_timelines[timeline_name].getPhaseIdx(self._flight_phases[timeline_name])[-1]
|
| 540 |
+
active_phases=self._contact_timelines[timeline_name].getActivePhases()
|
| 541 |
+
active_phases[this_flight_token_idx].setItemReference(f'z_{timeline_name}',
|
| 542 |
+
self._ref_trjs[timeline_name])
|
| 543 |
+
else:
|
| 544 |
+
self.add_stand(timeline_name=timeline_name)
|
| 545 |
+
|
| 546 |
+
def set_force_feedback(self,
|
| 547 |
+
timeline_name: str,
|
| 548 |
+
force_norm: float):
|
| 549 |
+
|
| 550 |
+
flight_tokens=self._contact_timelines[timeline_name].getPhaseIdx(self._flight_phases[timeline_name])
|
| 551 |
+
contact_tokens=self._contact_phases[timeline_name].getPhaseIdx(self._contact_phases[timeline_name])
|
| 552 |
+
if not len(flight_tokens)==0:
|
| 553 |
+
first_flight=flight_tokens[0]
|
| 554 |
+
first_flight
|
| 555 |
+
|
| 556 |
+
def check_horizon_full(self,
|
| 557 |
+
timeline_name):
|
| 558 |
+
timeline = self._contact_timelines[timeline_name]
|
| 559 |
+
if timeline.getEmptyNodes() > 0:
|
| 560 |
+
error = f"Empty nodes detected over the horizon for timeline {timeline}! Make sure to fill the whole horizon with valid phases!!"
|
| 561 |
+
Journal.log(self.__class__.__name__,
|
| 562 |
+
"check_horizon_full",
|
| 563 |
+
error,
|
| 564 |
+
LogType.EXCEP,
|
| 565 |
+
throw_when_excep = True)
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/horizon_imports.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# robot modeling and automatic differentiation
|
| 2 |
+
import casadi_kin_dyn.py3casadi_kin_dyn as casadi_kin_dyn
|
| 3 |
+
import casadi as cs
|
| 4 |
+
|
| 5 |
+
# horizon stuff
|
| 6 |
+
import horizon.utils.kin_dyn as kd
|
| 7 |
+
from horizon.problem import Problem
|
| 8 |
+
from horizon.rhc.model_description import FullModelInverseDynamics
|
| 9 |
+
from horizon.rhc.taskInterface import TaskInterface
|
| 10 |
+
from horizon.rhc.tasks.interactionTask import VertexContact
|
| 11 |
+
from horizon.rhc.tasks.contactTask import ContactTask
|
| 12 |
+
from horizon.utils import trajectoryGenerator, utils
|
| 13 |
+
|
| 14 |
+
# phase managing
|
| 15 |
+
import phase_manager.pymanager as pymanager
|
| 16 |
+
import phase_manager.pyphase as pyphase
|
| 17 |
+
import phase_manager.pytimeline as pytimeline
|
| 18 |
+
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/horizon_imports_glob.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Dynamically import all necessary Horizon and related dependencies.
|
| 3 |
+
This function is intended to be used within the import_child_lib method
|
| 4 |
+
of a class, enabling the parent process to load all required libraries.
|
| 5 |
+
"""
|
| 6 |
+
def import_horizon_global():
|
| 7 |
+
# Global imports to make modules accessible in child processes
|
| 8 |
+
global casadi_kin_dyn, cs, kd, Problem, FullModelInverseDynamics
|
| 9 |
+
global TaskInterface, VertexContact, ContactTask, trajectoryGenerator, utils
|
| 10 |
+
global pymanager, pyphase, pytimeline
|
| 11 |
+
|
| 12 |
+
# robot modeling and automatic differentiation
|
| 13 |
+
import casadi_kin_dyn.py3casadi_kin_dyn as casadi_kin_dyn
|
| 14 |
+
import casadi as cs
|
| 15 |
+
|
| 16 |
+
# horizon stuff
|
| 17 |
+
import horizon.utils.kin_dyn as kd
|
| 18 |
+
from horizon.problem import Problem
|
| 19 |
+
from horizon.rhc.model_description import FullModelInverseDynamics
|
| 20 |
+
from horizon.rhc.taskInterface import TaskInterface
|
| 21 |
+
from horizon.rhc.tasks.interactionTask import VertexContact
|
| 22 |
+
from horizon.rhc.tasks.contactTask import ContactTask
|
| 23 |
+
from horizon.utils import trajectoryGenerator, utils
|
| 24 |
+
|
| 25 |
+
# phase managing
|
| 26 |
+
import phase_manager.pymanager as pymanager
|
| 27 |
+
import phase_manager.pyphase as pyphase
|
| 28 |
+
import phase_manager.pytimeline as pytimeline
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/hybrid_quad_rhc.py
ADDED
|
@@ -0,0 +1,1243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from mpc_hive.controllers.rhc import RHController
|
| 2 |
+
# from perf_sleep.pyperfsleep import PerfSleep
|
| 3 |
+
# from mpc_hive.utilities.cpu_utils.core_utils import get_memory_usage
|
| 4 |
+
|
| 5 |
+
from aug_mpc.controllers.rhc.horizon_based.horizon_imports import *
|
| 6 |
+
|
| 7 |
+
from aug_mpc.controllers.rhc.horizon_based.hybrid_quad_rhc_refs import HybridQuadRhcRefs
|
| 8 |
+
from aug_mpc.controllers.rhc.horizon_based.gait_manager import GaitManager
|
| 9 |
+
|
| 10 |
+
from EigenIPC.PyEigenIPC import VLevel
|
| 11 |
+
from EigenIPC.PyEigenIPC import Journal, LogType
|
| 12 |
+
|
| 13 |
+
import numpy as np
|
| 14 |
+
|
| 15 |
+
import os
|
| 16 |
+
# import shutil
|
| 17 |
+
|
| 18 |
+
import time
|
| 19 |
+
from abc import ABC, abstractmethod
|
| 20 |
+
|
| 21 |
+
from typing import Dict, List
|
| 22 |
+
import re
|
| 23 |
+
|
| 24 |
+
class HybridQuadRhc(RHController):
|
| 25 |
+
|
| 26 |
+
def __init__(self,
|
| 27 |
+
srdf_path: str,
|
| 28 |
+
urdf_path: str,
|
| 29 |
+
config_path: str,
|
| 30 |
+
robot_name: str, # used for shared memory namespaces
|
| 31 |
+
codegen_dir: str,
|
| 32 |
+
n_nodes:float = 25,
|
| 33 |
+
injection_node:int = 10,
|
| 34 |
+
dt: float = 0.02,
|
| 35 |
+
max_solver_iter = 1, # defaults to rt-iteration
|
| 36 |
+
open_loop: bool = True,
|
| 37 |
+
close_loop_all: bool = False,
|
| 38 |
+
dtype = np.float32,
|
| 39 |
+
verbose = False,
|
| 40 |
+
debug = False,
|
| 41 |
+
refs_in_hor_frame = True,
|
| 42 |
+
timeout_ms: int = 60000,
|
| 43 |
+
custom_opts: Dict = {}):
|
| 44 |
+
|
| 45 |
+
self._refs_in_hor_frame = refs_in_hor_frame
|
| 46 |
+
|
| 47 |
+
self._injection_node = injection_node
|
| 48 |
+
|
| 49 |
+
self._open_loop = open_loop
|
| 50 |
+
self._close_loop_all = close_loop_all
|
| 51 |
+
|
| 52 |
+
self._codegen_dir = codegen_dir
|
| 53 |
+
if not os.path.exists(self._codegen_dir):
|
| 54 |
+
os.makedirs(self._codegen_dir)
|
| 55 |
+
# else:
|
| 56 |
+
# # Directory already exists, delete it and recreate
|
| 57 |
+
# shutil.rmtree(self._codegen_dir)
|
| 58 |
+
# os.makedirs(self._codegen_dir)
|
| 59 |
+
|
| 60 |
+
self.step_counter = 0
|
| 61 |
+
self.sol_counter = 0
|
| 62 |
+
|
| 63 |
+
self.max_solver_iter = max_solver_iter
|
| 64 |
+
|
| 65 |
+
self._timer_start = time.perf_counter()
|
| 66 |
+
self._prb_update_time = time.perf_counter()
|
| 67 |
+
self._phase_shift_time = time.perf_counter()
|
| 68 |
+
self._task_ref_update_time = time.perf_counter()
|
| 69 |
+
self._rti_time = time.perf_counter()
|
| 70 |
+
|
| 71 |
+
self.robot_name = robot_name
|
| 72 |
+
|
| 73 |
+
self.config_path = config_path
|
| 74 |
+
|
| 75 |
+
self.urdf_path = urdf_path
|
| 76 |
+
# read urdf and srdf files
|
| 77 |
+
with open(self.urdf_path, 'r') as file:
|
| 78 |
+
self.urdf = file.read()
|
| 79 |
+
self._base_init = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0])
|
| 80 |
+
|
| 81 |
+
self._c_timelines = dict()
|
| 82 |
+
self._f_reg_timelines = dict()
|
| 83 |
+
|
| 84 |
+
self._custom_opts={"replace_continuous_joints": False,
|
| 85 |
+
"use_force_feedback": False,
|
| 86 |
+
"lin_a_feedback": False,
|
| 87 |
+
"is_open_loop": self._open_loop, # fully open (just for db)
|
| 88 |
+
"fully_closed": False, # closed loop with full feedback (just for db)
|
| 89 |
+
"closed_partial": False, # closed loop with partial feedback
|
| 90 |
+
"adaptive_is": True, # closed loop with adaptation
|
| 91 |
+
"estimate_v_root": False, # when adaptive_is or closed_partial, estimate vbase
|
| 92 |
+
"alpha_from_outside": False, # alpha set ext. from shared memory
|
| 93 |
+
"alpha_half": 1.0,
|
| 94 |
+
"only_vel_wheels": True, # whether wheels (if present) are just vel controlled
|
| 95 |
+
"use_jnt_v_feedback": False
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
self._custom_opts.update(custom_opts)
|
| 99 |
+
|
| 100 |
+
self._alpha_half=self._custom_opts["alpha_half"]
|
| 101 |
+
|
| 102 |
+
if self._open_loop:
|
| 103 |
+
self._custom_opts["fully_closed"]=False
|
| 104 |
+
self._custom_opts["adaptive_is"]=False
|
| 105 |
+
self._custom_opts["closed_partial"]=False
|
| 106 |
+
else:
|
| 107 |
+
self._custom_opts["is_open_loop"]=False
|
| 108 |
+
if self._custom_opts["fully_closed"]:
|
| 109 |
+
self._custom_opts["adaptive_is"]=False
|
| 110 |
+
self._custom_opts["closed_partial"]=False
|
| 111 |
+
self._custom_opts["lin_a_feedback"]=False
|
| 112 |
+
if self._custom_opts["closed_partial"]:
|
| 113 |
+
self._custom_opts["adaptive_is"]=False
|
| 114 |
+
self._custom_opts["fully_closed"]=False
|
| 115 |
+
self._custom_opts["lin_a_feedback"]=False
|
| 116 |
+
if self._custom_opts["adaptive_is"]:
|
| 117 |
+
self._custom_opts["closed_partial"]=False
|
| 118 |
+
self._custom_opts["fully_closed"]=False
|
| 119 |
+
|
| 120 |
+
super().__init__(srdf_path=srdf_path,
|
| 121 |
+
n_nodes=n_nodes,
|
| 122 |
+
dt=dt,
|
| 123 |
+
namespace=self.robot_name,
|
| 124 |
+
dtype=dtype,
|
| 125 |
+
verbose=verbose,
|
| 126 |
+
debug=debug,
|
| 127 |
+
timeout_ms=timeout_ms)
|
| 128 |
+
|
| 129 |
+
self._rhc_fpaths.append(self.config_path)
|
| 130 |
+
|
| 131 |
+
def _config_override(self):
|
| 132 |
+
pass
|
| 133 |
+
|
| 134 |
+
def _post_problem_init(self):
|
| 135 |
+
|
| 136 |
+
self.rhc_costs={}
|
| 137 |
+
self.rhc_constr={}
|
| 138 |
+
|
| 139 |
+
self._fail_idx_scale=0.0
|
| 140 |
+
self._expl_idx_window_size=int(1*self._n_nodes)
|
| 141 |
+
self._explosion_idx_buffer=np.zeros((1,self._expl_idx_window_size))
|
| 142 |
+
self._expl_idx_counter=0
|
| 143 |
+
self._expl_idx_buffer_counter=0
|
| 144 |
+
|
| 145 |
+
self._pred_node_idx=self._n_nodes-1
|
| 146 |
+
|
| 147 |
+
self._nq=self.nq()
|
| 148 |
+
self._nq_jnts=self._nq-7# assuming floating base
|
| 149 |
+
self._nv=self.nv()
|
| 150 |
+
self._nv_jnts=self._nv-6
|
| 151 |
+
|
| 152 |
+
self._alphas_q_root=np.zeros((7, 1), dtype=self._dtype)
|
| 153 |
+
self._alphas_q_jnts=np.zeros((self._nq_jnts, 1), dtype=self._dtype)
|
| 154 |
+
self._alphas_twist_root=np.zeros((6, 1), dtype=self._dtype)
|
| 155 |
+
self._alphas_v_jnts=np.zeros((self._nv_jnts, 1), dtype=self._dtype)
|
| 156 |
+
self._alphas_a=np.zeros((self._nv, 1), dtype=self._dtype)
|
| 157 |
+
self._alphas_q_root[:, :]=1.0 # default to all open
|
| 158 |
+
self._alphas_q_jnts[:, :]=1.0
|
| 159 |
+
self._alphas_twist_root[:, :]=1.0
|
| 160 |
+
self._alphas_v_jnts[:, :]=1.0
|
| 161 |
+
self._alphas_a[:, :]=1.0
|
| 162 |
+
|
| 163 |
+
def _init_problem(self,
|
| 164 |
+
fixed_jnt_patterns: List[str] = None,
|
| 165 |
+
wheels_patterns: List[str] = None,
|
| 166 |
+
foot_linkname: str = None,
|
| 167 |
+
flight_duration: int = 10,
|
| 168 |
+
post_flight_stance: int = 3,
|
| 169 |
+
step_height: float = 0.12,
|
| 170 |
+
keep_yaw_vert: bool = False,
|
| 171 |
+
yaw_vertical_weight: float = 2.0,
|
| 172 |
+
vertical_landing: bool = False,
|
| 173 |
+
vertical_land_weight: float = 1.0,
|
| 174 |
+
phase_force_reg: float = 1e-2,
|
| 175 |
+
vel_bounds_weight: float = 1.0):
|
| 176 |
+
|
| 177 |
+
self._fixed_jnt_patterns=fixed_jnt_patterns
|
| 178 |
+
|
| 179 |
+
self._config_override()
|
| 180 |
+
|
| 181 |
+
Journal.log(self.__class__.__name__,
|
| 182 |
+
"_init_problem",
|
| 183 |
+
f" Will use horizon config file at {self.config_path}",
|
| 184 |
+
LogType.INFO,
|
| 185 |
+
throw_when_excep=True)
|
| 186 |
+
|
| 187 |
+
self._vel_bounds_weight=vel_bounds_weight
|
| 188 |
+
self._phase_force_reg=phase_force_reg
|
| 189 |
+
self._yaw_vertical_weight=yaw_vertical_weight
|
| 190 |
+
self._vertical_land_weight=vertical_land_weight
|
| 191 |
+
# overrides parent
|
| 192 |
+
self._prb = Problem(self._n_intervals,
|
| 193 |
+
receding=True,
|
| 194 |
+
casadi_type=cs.SX)
|
| 195 |
+
self._prb.setDt(self._dt)
|
| 196 |
+
|
| 197 |
+
if "replace_continuous_joints" in self._custom_opts:
|
| 198 |
+
# continous joints are parametrized in So2
|
| 199 |
+
if self._custom_opts["replace_continuous_joints"]:
|
| 200 |
+
self.urdf = self.urdf.replace('continuous', 'revolute')
|
| 201 |
+
else:
|
| 202 |
+
self.urdf = self.urdf.replace('continuous', 'revolute')
|
| 203 |
+
|
| 204 |
+
self._kin_dyn = casadi_kin_dyn.CasadiKinDyn(self.urdf) # used for getting joint names
|
| 205 |
+
self._assign_controller_side_jnt_names(jnt_names=self._get_robot_jnt_names())
|
| 206 |
+
|
| 207 |
+
self._init_robot_homer()
|
| 208 |
+
|
| 209 |
+
# handle fixed joints
|
| 210 |
+
fixed_joint_map={}
|
| 211 |
+
if self._fixed_jnt_patterns is not None:
|
| 212 |
+
for jnt_name in self._get_robot_jnt_names():
|
| 213 |
+
for fixed_jnt_pattern in self._fixed_jnt_patterns:
|
| 214 |
+
if fixed_jnt_pattern in jnt_name:
|
| 215 |
+
fixed_joint_map.update({f"{jnt_name}":
|
| 216 |
+
self._homer.get_homing_val(jnt_name=jnt_name)})
|
| 217 |
+
break # do not search for other pattern matches
|
| 218 |
+
|
| 219 |
+
if not len(fixed_joint_map)==0: # we need to recreate kin dyn and homers
|
| 220 |
+
Journal.log(self.__class__.__name__,
|
| 221 |
+
"_init_problem",
|
| 222 |
+
f"Will fix following joints: \n{str(fixed_joint_map)}",
|
| 223 |
+
LogType.INFO,
|
| 224 |
+
throw_when_excep=True)
|
| 225 |
+
# with the fixed joint map
|
| 226 |
+
self._kin_dyn = casadi_kin_dyn.CasadiKinDyn(self.urdf,fixed_joints=fixed_joint_map)
|
| 227 |
+
# assign again controlled joints names
|
| 228 |
+
self._assign_controller_side_jnt_names(jnt_names=self._get_robot_jnt_names())
|
| 229 |
+
# updated robot homer for controlled joints
|
| 230 |
+
self._init_robot_homer()
|
| 231 |
+
|
| 232 |
+
# handle continuous joints (need to change homing and retrieve
|
| 233 |
+
# cont jnts indexes) and homing
|
| 234 |
+
self._continuous_joints=self._get_continuous_jnt_names()
|
| 235 |
+
# reduced
|
| 236 |
+
self._continuous_joints_idxs=[]
|
| 237 |
+
self._continuous_joints_idxs_cos=[]
|
| 238 |
+
self._continuous_joints_idxs_sin=[]
|
| 239 |
+
self._continuous_joints_idxs_red=[]
|
| 240 |
+
self._rev_joints_idxs=[]
|
| 241 |
+
self._rev_joints_idxs_red=[]
|
| 242 |
+
# qfull
|
| 243 |
+
self._continuous_joints_idxs_qfull=[]
|
| 244 |
+
self._continuous_joints_idxs_cos_qfull=[]
|
| 245 |
+
self._continuous_joints_idxs_sin_qfull=[]
|
| 246 |
+
self._continuous_joints_idxs_red_qfull=[]
|
| 247 |
+
self._rev_joints_idxs_qfull=[]
|
| 248 |
+
self._rev_joints_idxs_red_qfull=[]
|
| 249 |
+
jnt_homing=[""]*(len(self._homer.get_homing())+len(self._continuous_joints))
|
| 250 |
+
jnt_names=self._get_robot_jnt_names()
|
| 251 |
+
for i in range(len(jnt_names)):
|
| 252 |
+
jnt=jnt_names[i]
|
| 253 |
+
index=self._get_jnt_id(jnt)# accounting for floating joint
|
| 254 |
+
homing_idx=index-7 # homing is only for actuated joints
|
| 255 |
+
homing_value=self._homer.get_homing_val(jnt)
|
| 256 |
+
if jnt in self._continuous_joints:
|
| 257 |
+
jnt_homing[homing_idx]=np.cos(homing_value).item()
|
| 258 |
+
jnt_homing[homing_idx+1]=np.sin(homing_value).item()
|
| 259 |
+
# just actuated joints
|
| 260 |
+
self._continuous_joints_idxs.append(homing_idx) # cos
|
| 261 |
+
self._continuous_joints_idxs.append(homing_idx+1) # sin
|
| 262 |
+
self._continuous_joints_idxs_cos.append(homing_idx)
|
| 263 |
+
self._continuous_joints_idxs_sin.append(homing_idx+1)
|
| 264 |
+
self._continuous_joints_idxs_red.append(i)
|
| 265 |
+
# q full
|
| 266 |
+
self._continuous_joints_idxs_qfull.append(index) # cos
|
| 267 |
+
self._continuous_joints_idxs_qfull.append(index+1) # sin
|
| 268 |
+
self._continuous_joints_idxs_cos_qfull.append(index)
|
| 269 |
+
self._continuous_joints_idxs_sin_qfull.append(index+1)
|
| 270 |
+
self._continuous_joints_idxs_red_qfull.append(i+7)
|
| 271 |
+
else:
|
| 272 |
+
jnt_homing[homing_idx]=homing_value
|
| 273 |
+
# just actuated joints
|
| 274 |
+
self._rev_joints_idxs.append(homing_idx)
|
| 275 |
+
self._rev_joints_idxs_red.append(i)
|
| 276 |
+
# q full
|
| 277 |
+
self._rev_joints_idxs_qfull.append(index)
|
| 278 |
+
self._rev_joints_idxs_red_qfull.append(i+7)
|
| 279 |
+
|
| 280 |
+
self._jnts_q_reduced=None
|
| 281 |
+
if not len(self._continuous_joints)==0:
|
| 282 |
+
cont_joints=", ".join(self._continuous_joints)
|
| 283 |
+
|
| 284 |
+
Journal.log(self.__class__.__name__,
|
| 285 |
+
"_init_problem",
|
| 286 |
+
f"The following continuous joints were found: \n{cont_joints}",
|
| 287 |
+
LogType.INFO,
|
| 288 |
+
throw_when_excep=True)
|
| 289 |
+
# preallocating data
|
| 290 |
+
self._jnts_q_reduced=np.zeros((1,self.nv()-6),dtype=self._dtype)
|
| 291 |
+
self._jnts_q_expanded=np.zeros((self.nq()-7,1),dtype=self._dtype)
|
| 292 |
+
self._full_q_reduced=np.zeros((7+len(jnt_names), self._n_nodes),dtype=self._dtype)
|
| 293 |
+
self._jnts_q_delta_expanded=np.zeros((self.nq()-7,1),dtype=self._dtype)
|
| 294 |
+
else:
|
| 295 |
+
self._custom_opts["replace_continuous_joints"]=True
|
| 296 |
+
Journal.log(self.__class__.__name__,
|
| 297 |
+
"_init_problem",
|
| 298 |
+
f"No continuous joints were found.",
|
| 299 |
+
LogType.INFO,
|
| 300 |
+
throw_when_excep=True)
|
| 301 |
+
|
| 302 |
+
# retrieve wheels indexes (not considering continuous joints,
|
| 303 |
+
# ok just for v, eff, etc..)
|
| 304 |
+
self._wheel_patterns=wheels_patterns
|
| 305 |
+
self._wheels_idxs_v=self._get_wheels_jnt_v_idxs(wheel_patterns=self._wheel_patterns)
|
| 306 |
+
self._f0 = [0, 0, self._kin_dyn.mass()/4*9.81]
|
| 307 |
+
|
| 308 |
+
# we can create an init for the base
|
| 309 |
+
init = self._base_init.tolist() + jnt_homing
|
| 310 |
+
|
| 311 |
+
if foot_linkname is not None:
|
| 312 |
+
FK = self._kin_dyn.fk(foot_linkname) # just to get robot reference height
|
| 313 |
+
ground_level = FK(q=init)['ee_pos']
|
| 314 |
+
self._base_init[2] = -ground_level[2] # override init
|
| 315 |
+
|
| 316 |
+
self._model = FullModelInverseDynamics(problem=self._prb,
|
| 317 |
+
kd=self._kin_dyn,
|
| 318 |
+
q_init=self._homer.get_homing_map(),
|
| 319 |
+
base_init=self._base_init)
|
| 320 |
+
|
| 321 |
+
self._ti = TaskInterface(prb=self._prb,
|
| 322 |
+
model=self._model,
|
| 323 |
+
max_solver_iter=self.max_solver_iter,
|
| 324 |
+
debug = self._debug,
|
| 325 |
+
verbose = self._verbose,
|
| 326 |
+
codegen_workdir = self._codegen_dir)
|
| 327 |
+
self._ti.setTaskFromYaml(self.config_path)
|
| 328 |
+
|
| 329 |
+
# setting initial base pos ref if exists
|
| 330 |
+
base_pos = self._ti.getTask('base_height')
|
| 331 |
+
if base_pos is not None:
|
| 332 |
+
base_pos.setRef(np.atleast_2d(self._base_init).T)
|
| 333 |
+
|
| 334 |
+
self._pm = pymanager.PhaseManager(self._n_nodes, debug=False) # intervals or nodes?????
|
| 335 |
+
|
| 336 |
+
self._gm = GaitManager(self._ti,
|
| 337 |
+
self._pm,
|
| 338 |
+
self._injection_node,
|
| 339 |
+
keep_yaw_vert=keep_yaw_vert,
|
| 340 |
+
yaw_vertical_weight=self._yaw_vertical_weight,
|
| 341 |
+
vertical_landing=vertical_landing,
|
| 342 |
+
landing_vert_weight=self._vertical_land_weight,
|
| 343 |
+
phase_force_reg=self._phase_force_reg,
|
| 344 |
+
custom_opts=self._custom_opts,
|
| 345 |
+
flight_duration=flight_duration,
|
| 346 |
+
post_flight_stance=post_flight_stance,
|
| 347 |
+
step_height=step_height,
|
| 348 |
+
dh=0.0)
|
| 349 |
+
|
| 350 |
+
self._ti.model.q.setBounds(self._ti.model.q0, self._ti.model.q0, nodes=0)
|
| 351 |
+
self._ti.model.v.setBounds(self._ti.model.v0, self._ti.model.v0, nodes=0)
|
| 352 |
+
self._ti.model.q.setInitialGuess(self._ti.model.q0)
|
| 353 |
+
self._ti.model.v.setInitialGuess(self._ti.model.v0)
|
| 354 |
+
for _, cforces in self._ti.model.cmap.items():
|
| 355 |
+
n_contact_f=len(cforces)
|
| 356 |
+
for c in cforces:
|
| 357 |
+
c.setInitialGuess(np.array(self._f0)/n_contact_f)
|
| 358 |
+
|
| 359 |
+
vel_lims = self._model.kd.velocityLimits()
|
| 360 |
+
import horizon.utils as utils
|
| 361 |
+
self._prb.createResidual('vel_lb_barrier', self._vel_bounds_weight*utils.utils.barrier(vel_lims[7:] - self._model.v[7:]))
|
| 362 |
+
self._prb.createResidual('vel_ub_barrier', self._vel_bounds_weight*utils.utils.barrier1(-1 * vel_lims[7:] - self._model.v[7:]))
|
| 363 |
+
|
| 364 |
+
self._meas_lin_a_par=None
|
| 365 |
+
# if self._custom_opts["lin_a_feedback"]:
|
| 366 |
+
# # acceleration feedback on first node
|
| 367 |
+
# self._meas_lin_a_par=self._prb.createParameter(name="lin_a_feedback",
|
| 368 |
+
# dim=3, nodes=0)
|
| 369 |
+
# base_lin_a_prb=self._prb.getInput().getVars()[0:3]
|
| 370 |
+
# self._prb.createConstraint('lin_acceleration_feedback', base_lin_a_prb - self._meas_lin_a_par,
|
| 371 |
+
# nodes=[0])
|
| 372 |
+
|
| 373 |
+
# if not self._open_loop:
|
| 374 |
+
# # we create a residual cost to be used as an attractor to the measured state on the first node
|
| 375 |
+
# # hard constraints injecting meas. states are pure EVIL!
|
| 376 |
+
# prb_state=self._prb.getState()
|
| 377 |
+
# full_state=prb_state.getVars()
|
| 378 |
+
# state_dim=prb_state.getBounds()[0].shape[0]
|
| 379 |
+
# meas_state=self._prb.createParameter(name="measured_state",
|
| 380 |
+
# dim=state_dim, nodes=0)
|
| 381 |
+
# self._prb.createResidual('meas_state_attractor', meas_state_attractor_weight * (full_state - meas_state),
|
| 382 |
+
# nodes=[0])
|
| 383 |
+
|
| 384 |
+
self._ti.finalize()
|
| 385 |
+
self._ti.bootstrap()
|
| 386 |
+
|
| 387 |
+
self._ti.init_inv_dyn_for_res() # we initialize some objects for sol. postprocessing purposes
|
| 388 |
+
self._ti.load_initial_guess()
|
| 389 |
+
|
| 390 |
+
self.n_dofs = self._get_ndofs() # after loading the URDF and creating the controller we
|
| 391 |
+
# know n_dofs -> we assign it (by default = None)
|
| 392 |
+
|
| 393 |
+
self.n_contacts = len(self._model.cmap.keys())
|
| 394 |
+
|
| 395 |
+
# remove variables bounds (before they were necessary to have a good
|
| 396 |
+
# quality bootstrap solution)
|
| 397 |
+
self._q_inf=np.zeros((self.nq(), 1))
|
| 398 |
+
self._q_inf[:, :]=np.inf
|
| 399 |
+
self._v_inf=np.zeros((self.nv(), 1))
|
| 400 |
+
self._v_inf[:, :]=np.inf
|
| 401 |
+
self._ti.model.q.setBounds(-self._q_inf, self._q_inf, nodes=0)
|
| 402 |
+
self._ti.model.v.setBounds(-self._v_inf, self._v_inf, nodes=0)
|
| 403 |
+
|
| 404 |
+
# self.horizon_anal = analyzer.ProblemAnalyzer(self._prb)
|
| 405 |
+
|
| 406 |
+
def get_file_paths(self):
|
| 407 |
+
# can be overriden by child
|
| 408 |
+
paths = super().get_file_paths()
|
| 409 |
+
return paths
|
| 410 |
+
|
| 411 |
+
def _get_quat_remap(self):
|
| 412 |
+
# overrides parent
|
| 413 |
+
return [1, 2, 3, 0] # mapping from robot quat. to Horizon's quaternion convention
|
| 414 |
+
|
| 415 |
+
def _zmp(self, model):
|
| 416 |
+
|
| 417 |
+
num = cs.SX([0, 0])
|
| 418 |
+
den = cs.SX([0])
|
| 419 |
+
pos_contact = dict()
|
| 420 |
+
force_val = dict()
|
| 421 |
+
|
| 422 |
+
q = cs.SX.sym('q', model.nq)
|
| 423 |
+
v = cs.SX.sym('v', model.nv)
|
| 424 |
+
a = cs.SX.sym('a', model.nv)
|
| 425 |
+
|
| 426 |
+
com = model.kd.centerOfMass()(q=q, v=v, a=a)['com']
|
| 427 |
+
|
| 428 |
+
n = cs.SX([0, 0, 1])
|
| 429 |
+
for c in model.fmap.keys():
|
| 430 |
+
pos_contact[c] = model.kd.fk(c)(q=q)['ee_pos']
|
| 431 |
+
force_val[c] = cs.SX.sym('force_val', 3)
|
| 432 |
+
num += (pos_contact[c][0:2] - com[0:2]) * cs.dot(force_val[c], n)
|
| 433 |
+
den += cs.dot(force_val[c], n)
|
| 434 |
+
|
| 435 |
+
zmp = com[0:2] + (num / den)
|
| 436 |
+
input_list = []
|
| 437 |
+
input_list.append(q)
|
| 438 |
+
input_list.append(v)
|
| 439 |
+
input_list.append(a)
|
| 440 |
+
|
| 441 |
+
for elem in force_val.values():
|
| 442 |
+
input_list.append(elem)
|
| 443 |
+
|
| 444 |
+
f = cs.Function('zmp', input_list, [zmp])
|
| 445 |
+
return f
|
| 446 |
+
|
| 447 |
+
def _add_zmp(self):
|
| 448 |
+
|
| 449 |
+
input_zmp = []
|
| 450 |
+
|
| 451 |
+
input_zmp.append(self._model.q)
|
| 452 |
+
input_zmp.append(self._model.v)
|
| 453 |
+
input_zmp.append(self._model.a)
|
| 454 |
+
|
| 455 |
+
for f_var in self._model.fmap.values():
|
| 456 |
+
input_zmp.append(f_var)
|
| 457 |
+
|
| 458 |
+
c_mean = cs.SX([0, 0, 0])
|
| 459 |
+
for c_name, f_var in self._model.fmap.items():
|
| 460 |
+
fk_c_pos = self._kin_dyn.fk(c_name)(q=self._model.q)['ee_pos']
|
| 461 |
+
c_mean += fk_c_pos
|
| 462 |
+
|
| 463 |
+
c_mean /= len(self._model.cmap.keys())
|
| 464 |
+
|
| 465 |
+
zmp_nominal_weight = 10.
|
| 466 |
+
zmp_fun = self._zmp(self._model)(*input_zmp)
|
| 467 |
+
|
| 468 |
+
if 'wheel_joint_1' in self._model.kd.joint_names():
|
| 469 |
+
zmp_residual = self._prb.createIntermediateResidual('zmp', zmp_nominal_weight * (zmp_fun[0:2] - c_mean[0:2]))
|
| 470 |
+
|
| 471 |
+
def _quaternion_multiply(self,
|
| 472 |
+
q1, q2):
|
| 473 |
+
x1, y1, z1, w1 = q1
|
| 474 |
+
x2, y2, z2, w2 = q2
|
| 475 |
+
w = w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2
|
| 476 |
+
x = w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2
|
| 477 |
+
y = w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2
|
| 478 |
+
z = w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2
|
| 479 |
+
return np.array([x, y, z, w])
|
| 480 |
+
|
| 481 |
+
def _get_continuous_jnt_names(self):
|
| 482 |
+
import xml.etree.ElementTree as ET
|
| 483 |
+
root = ET.fromstring(self.urdf)
|
| 484 |
+
continuous_joints = []
|
| 485 |
+
for joint in root.findall('joint'):
|
| 486 |
+
joint_type = joint.get('type')
|
| 487 |
+
if joint_type == 'continuous':
|
| 488 |
+
joint_name = joint.get('name')
|
| 489 |
+
continuous_joints.append(joint_name)
|
| 490 |
+
return continuous_joints
|
| 491 |
+
|
| 492 |
+
def _get_wheels_jnt_v_idxs(self, wheel_patterns: List[str]):
|
| 493 |
+
jnt_names=self._get_robot_jnt_names()
|
| 494 |
+
wheels_idxs=[]
|
| 495 |
+
for i in range(len(jnt_names)):
|
| 496 |
+
jnt_name=jnt_names[i]
|
| 497 |
+
for wheel_pattern in wheel_patterns:
|
| 498 |
+
if wheel_pattern in jnt_name:
|
| 499 |
+
wheels_idxs.append(i)
|
| 500 |
+
break
|
| 501 |
+
return wheels_idxs
|
| 502 |
+
|
| 503 |
+
def _get_jnt_id(self, jnt_name):
|
| 504 |
+
return self._kin_dyn.joint_iq(jnt_name)
|
| 505 |
+
|
| 506 |
+
def _init_rhc_task_cmds(self):
|
| 507 |
+
|
| 508 |
+
rhc_refs = HybridQuadRhcRefs(gait_manager=self._gm,
|
| 509 |
+
robot_index_shm=self.controller_index,
|
| 510 |
+
robot_index_view=0, # when using optimize_mem the view if always of shape 1x...
|
| 511 |
+
namespace=self.namespace,
|
| 512 |
+
safe=False,
|
| 513 |
+
verbose=self._verbose,
|
| 514 |
+
vlevel=VLevel.V2,
|
| 515 |
+
use_force_feedback=self._custom_opts["use_force_feedback"],
|
| 516 |
+
optimize_mem=True)
|
| 517 |
+
|
| 518 |
+
rhc_refs.run()
|
| 519 |
+
|
| 520 |
+
rhc_refs.rob_refs.set_jnts_remapping(jnts_remapping=self._to_controller)
|
| 521 |
+
rhc_refs.rob_refs.set_q_remapping(q_remapping=self._get_quat_remap())
|
| 522 |
+
|
| 523 |
+
rhc_refs.set_default_refs(p_ref=np.atleast_2d(self._base_init)[:, 0:3],
|
| 524 |
+
q_ref=np.atleast_2d(self._base_init)[:, 3:7])
|
| 525 |
+
|
| 526 |
+
return rhc_refs
|
| 527 |
+
|
| 528 |
+
def get_vertex_fnames_from_ti(self):
|
| 529 |
+
tasks=self._ti.task_list
|
| 530 |
+
contact_f_names=[]
|
| 531 |
+
for task in tasks:
|
| 532 |
+
if isinstance(task, ContactTask):
|
| 533 |
+
interaction_task=task.dynamics_tasks[0]
|
| 534 |
+
contact_f_names.append(interaction_task.vertex_frames[0])
|
| 535 |
+
return contact_f_names
|
| 536 |
+
|
| 537 |
+
def _get_contact_names(self):
|
| 538 |
+
# should get contact names from vertex frames
|
| 539 |
+
# list(self._ti.model.cmap.keys())
|
| 540 |
+
return self.get_vertex_fnames_from_ti()
|
| 541 |
+
|
| 542 |
+
def _get_robot_jnt_names(self):
|
| 543 |
+
|
| 544 |
+
joints_names = self._kin_dyn.joint_names()
|
| 545 |
+
to_be_removed = ["universe",
|
| 546 |
+
"reference",
|
| 547 |
+
"world",
|
| 548 |
+
"floating",
|
| 549 |
+
"floating_base"]
|
| 550 |
+
for name in to_be_removed:
|
| 551 |
+
if name in joints_names:
|
| 552 |
+
joints_names.remove(name)
|
| 553 |
+
|
| 554 |
+
return joints_names
|
| 555 |
+
|
| 556 |
+
def _get_ndofs(self):
|
| 557 |
+
return len(self._model.joint_names)
|
| 558 |
+
|
| 559 |
+
def nq(self):
|
| 560 |
+
return self._kin_dyn.nq()
|
| 561 |
+
|
| 562 |
+
def nv(self):
|
| 563 |
+
return self._kin_dyn.nv()
|
| 564 |
+
|
| 565 |
+
def _get_robot_mass(self):
|
| 566 |
+
|
| 567 |
+
return self._kin_dyn.mass()
|
| 568 |
+
|
| 569 |
+
def _get_root_full_q_from_sol(self, node_idx=1):
|
| 570 |
+
|
| 571 |
+
root_q_full=self._ti.solution['q'][0:7, node_idx].reshape(1, 7).astype(self._dtype)
|
| 572 |
+
|
| 573 |
+
np.nan_to_num(root_q_full, nan=1e3, posinf=1e3, neginf=-1e3, copy=False)
|
| 574 |
+
np.clip(a=root_q_full, a_min=-1e3, a_max=1e3, out=root_q_full)
|
| 575 |
+
|
| 576 |
+
return root_q_full
|
| 577 |
+
|
| 578 |
+
def _get_full_q_from_sol(self, node_idx=1):
|
| 579 |
+
|
| 580 |
+
return self._ti.solution['q'][:, node_idx].reshape(1, -1).astype(self._dtype)
|
| 581 |
+
|
| 582 |
+
def _get_root_twist_from_sol(self, node_idx=1):
|
| 583 |
+
# provided in world frame
|
| 584 |
+
twist_base_local=self._get_v_from_sol()[0:6, node_idx].reshape(1, 6)
|
| 585 |
+
# if world_aligned:
|
| 586 |
+
# q_root_rhc = self._get_root_full_q_from_sol(node_idx=node_idx)[:, 0:4]
|
| 587 |
+
# r_base_rhc=Rotation.from_quat(q_root_rhc.flatten()).as_matrix()
|
| 588 |
+
# twist_base_local[:, 0:3] = r_base_rhc @ twist_base_local[0, 0:3]
|
| 589 |
+
# twist_base_local[:, 3:6] = r_base_rhc @ twist_base_local[0, 3:6]
|
| 590 |
+
return twist_base_local
|
| 591 |
+
|
| 592 |
+
def _get_root_a_from_sol(self, node_idx=0):
|
| 593 |
+
# provided in world frame
|
| 594 |
+
a_base_local=self._get_a_from_sol()[0:6, node_idx].reshape(1, 6)
|
| 595 |
+
# if world_aligned:
|
| 596 |
+
# q_root_rhc = self._get_root_full_q_from_sol(node_idx=node_idx)[:, 0:4]
|
| 597 |
+
# r_base_rhc=Rotation.from_quat(q_root_rhc.flatten()).as_matrix()
|
| 598 |
+
# a_base_local[:, 0:3] = r_base_rhc @ a_base_local[0, 0:3]
|
| 599 |
+
# a_base_local[:, 3:6] = r_base_rhc @ v[0, 3:6]
|
| 600 |
+
return a_base_local
|
| 601 |
+
|
| 602 |
+
def _get_jnt_q_from_sol(self, node_idx=0,
|
| 603 |
+
reduce: bool = True,
|
| 604 |
+
clamp: bool = True):
|
| 605 |
+
|
| 606 |
+
full_jnts_q=self._ti.solution['q'][7:, node_idx:node_idx+1].reshape(1,-1).astype(self._dtype)
|
| 607 |
+
|
| 608 |
+
np.nan_to_num(full_jnts_q, nan=1e3, posinf=1e3, neginf=-1e3, copy=False) # in place
|
| 609 |
+
np.clip(a=full_jnts_q, a_max=1e3, a_min=-1e3, out=full_jnts_q) # in place
|
| 610 |
+
|
| 611 |
+
if self._custom_opts["replace_continuous_joints"] or (not reduce):
|
| 612 |
+
if clamp:
|
| 613 |
+
return np.fmod(full_jnts_q, 2*np.pi)
|
| 614 |
+
else:
|
| 615 |
+
return full_jnts_q
|
| 616 |
+
else:
|
| 617 |
+
cos_sin=full_jnts_q[:,self._continuous_joints_idxs].reshape(-1,2)
|
| 618 |
+
# copy rev joint vals
|
| 619 |
+
self._jnts_q_reduced[:, self._rev_joints_idxs_red]=np.fmod(full_jnts_q[:, self._rev_joints_idxs], 2*np.pi).reshape(1, -1)
|
| 620 |
+
# and continuous
|
| 621 |
+
self._jnts_q_reduced[:, self._continuous_joints_idxs_red]=np.arctan2(cos_sin[:, 1], cos_sin[:, 0]).reshape(1,-1)
|
| 622 |
+
return self._jnts_q_reduced
|
| 623 |
+
|
| 624 |
+
def _get_jnt_v_from_sol(self, node_idx=1):
|
| 625 |
+
|
| 626 |
+
jnt_v_sol=self._get_v_from_sol()[6:, node_idx].reshape(1,
|
| 627 |
+
self._nv_jnts)
|
| 628 |
+
np.nan_to_num(jnt_v_sol, nan=1e5, posinf=1e5, neginf=-1e5, copy=False) # in place
|
| 629 |
+
# np.clip(a=jnt_v_sol, a_max=1e5, a_min=-1e5, out=jnt_v_sol) # in place
|
| 630 |
+
|
| 631 |
+
return jnt_v_sol
|
| 632 |
+
|
| 633 |
+
def _get_jnt_a_from_sol(self, node_idx=1):
|
| 634 |
+
|
| 635 |
+
return self._get_a_from_sol()[6:, node_idx].reshape(1,
|
| 636 |
+
self._nv_jnts)
|
| 637 |
+
|
| 638 |
+
def _get_jnt_eff_from_sol(self, node_idx=0):
|
| 639 |
+
|
| 640 |
+
efforts_on_node = self._ti.eval_efforts_on_node(node_idx=node_idx)
|
| 641 |
+
|
| 642 |
+
# if self._custom_opts["only_vel_wheels"]:
|
| 643 |
+
|
| 644 |
+
jnt_efforts=efforts_on_node[6:, 0]
|
| 645 |
+
|
| 646 |
+
if self._custom_opts["only_vel_wheels"] and self._wheels_idxs_v:
|
| 647 |
+
jnt_efforts[self._wheels_idxs_v]=0.0
|
| 648 |
+
|
| 649 |
+
return jnt_efforts.reshape(1,
|
| 650 |
+
self._nv_jnts).astype(self._dtype)
|
| 651 |
+
|
| 652 |
+
def _get_rhc_cost(self):
|
| 653 |
+
|
| 654 |
+
return self._ti.solution["opt_cost"]
|
| 655 |
+
|
| 656 |
+
def _get_rhc_constr_viol(self):
|
| 657 |
+
|
| 658 |
+
return self._ti.solution["residual_norm"]
|
| 659 |
+
|
| 660 |
+
def _get_rhc_nodes_cost(self):
|
| 661 |
+
|
| 662 |
+
cost = self._ti.solver_rti.getCostValOnNodes()
|
| 663 |
+
return cost.reshape((1, -1))
|
| 664 |
+
|
| 665 |
+
def _get_rhc_nodes_constr_viol(self):
|
| 666 |
+
|
| 667 |
+
constr_viol = self._ti.solver_rti.getConstrValOnNodes()
|
| 668 |
+
return constr_viol.reshape((1, -1))
|
| 669 |
+
|
| 670 |
+
def _get_rhc_niter_to_sol(self):
|
| 671 |
+
|
| 672 |
+
return self._ti.solution["n_iter2sol"]
|
| 673 |
+
|
| 674 |
+
def _set_ig(self):
|
| 675 |
+
|
| 676 |
+
shift_num = -1 # shift data by one node
|
| 677 |
+
|
| 678 |
+
x_opt = self._ti.solution['x_opt']
|
| 679 |
+
u_opt = self._ti.solution['u_opt']
|
| 680 |
+
|
| 681 |
+
# building ig for state
|
| 682 |
+
xig = np.roll(x_opt,
|
| 683 |
+
shift_num, axis=1) # rolling state sol.
|
| 684 |
+
for i in range(abs(shift_num)):
|
| 685 |
+
# state on last node is copied to the elements
|
| 686 |
+
# which are "lost" during the shift operation
|
| 687 |
+
xig[:, -1 - i] = x_opt[:, -1]
|
| 688 |
+
# building ig for inputs
|
| 689 |
+
uig = np.roll(u_opt,
|
| 690 |
+
shift_num, axis=1) # rolling state sol.
|
| 691 |
+
for i in range(abs(shift_num)):
|
| 692 |
+
# state on last node is copied to the elements
|
| 693 |
+
# which are "lost" during the shift operation
|
| 694 |
+
uig[:, -1 - i] = u_opt[:, -1]
|
| 695 |
+
|
| 696 |
+
# assigning ig
|
| 697 |
+
self._prb.getState().setInitialGuess(xig)
|
| 698 |
+
self._prb.getInput().setInitialGuess(uig)
|
| 699 |
+
|
| 700 |
+
return xig, uig
|
| 701 |
+
|
| 702 |
+
def _update_open_loop(self):
|
| 703 |
+
|
| 704 |
+
xig, _ = self._set_ig()
|
| 705 |
+
|
| 706 |
+
q_state, v_state, a_state=self._set_is_open()
|
| 707 |
+
|
| 708 |
+
# robot_state=xig[:, 0]
|
| 709 |
+
# # open loop update:
|
| 710 |
+
# self._prb.setInitialState(x0=robot_state) # (xig has been shifted, so node 0
|
| 711 |
+
# # is node 1 in the last opt solution)
|
| 712 |
+
|
| 713 |
+
return q_state, v_state, a_state
|
| 714 |
+
|
| 715 |
+
def _update_closed_loop(self):
|
| 716 |
+
|
| 717 |
+
# set initial guess for controller
|
| 718 |
+
xig, _ = self._set_ig()
|
| 719 |
+
# set initial state
|
| 720 |
+
q_state=None
|
| 721 |
+
v_state=None
|
| 722 |
+
a_state=None
|
| 723 |
+
if self._custom_opts["adaptive_is"]:
|
| 724 |
+
# adaptive closed loop
|
| 725 |
+
q_state, v_state, a_state=self._set_is_adaptive()
|
| 726 |
+
elif self._custom_opts["fully_closed"]:
|
| 727 |
+
q_state, v_state, a_state=self._set_is_full()
|
| 728 |
+
elif self._custom_opts["closed_partial"]:
|
| 729 |
+
q_state, v_state, a_state=self._set_is_partial()
|
| 730 |
+
else:
|
| 731 |
+
Journal.log(self.__class__.__name__,
|
| 732 |
+
"_update_closed_loop",
|
| 733 |
+
"Neither adaptive_is, fully_closed, or closed_partial.",
|
| 734 |
+
LogType.EXCEP,
|
| 735 |
+
throw_when_excep = False)
|
| 736 |
+
q_state, v_state, a_state=self._set_is()
|
| 737 |
+
|
| 738 |
+
return q_state, v_state, a_state
|
| 739 |
+
|
| 740 |
+
def _set_is_open(self):
|
| 741 |
+
|
| 742 |
+
# overriding states with rhc data
|
| 743 |
+
q_full_root=self._get_root_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 744 |
+
q_jnts=self._get_jnt_q_from_sol(node_idx=1, reduce=False).reshape(-1, 1)
|
| 745 |
+
|
| 746 |
+
twist_root=self._get_root_twist_from_sol(node_idx=1).reshape(-1, 1)
|
| 747 |
+
v_jnts=self._get_jnt_v_from_sol(node_idx=1).reshape(-1, 1)
|
| 748 |
+
|
| 749 |
+
# rhc variables to be set
|
| 750 |
+
q=self._prb.getVariables("q") # .setBounds()
|
| 751 |
+
root_q_full_rhc=q[0:7] # root full q
|
| 752 |
+
jnts_q_rhc=q[7:] # jnts q
|
| 753 |
+
vel=self._prb.getVariables("v")
|
| 754 |
+
root_twist_rhc=vel[0:6] # lin v.
|
| 755 |
+
jnts_v_rhc=vel[6:] # jnts v
|
| 756 |
+
|
| 757 |
+
self.rhc_refs.set_alpha(alpha=1.0) # fully open
|
| 758 |
+
|
| 759 |
+
# close state on known quantities
|
| 760 |
+
root_q_full_rhc.setBounds(lb=q_full_root,
|
| 761 |
+
ub=q_full_root, nodes=0)
|
| 762 |
+
jnts_q_rhc.setBounds(lb=q_jnts,
|
| 763 |
+
ub=q_jnts, nodes=0)
|
| 764 |
+
root_twist_rhc.setBounds(lb=twist_root,
|
| 765 |
+
ub=twist_root, nodes=0)
|
| 766 |
+
jnts_v_rhc.setBounds(lb=v_jnts,
|
| 767 |
+
ub=v_jnts, nodes=0)
|
| 768 |
+
|
| 769 |
+
# return state used for feedback
|
| 770 |
+
q_state=np.concatenate((q_full_root, q_jnts),
|
| 771 |
+
axis=0)
|
| 772 |
+
v_state=np.concatenate((twist_root, v_jnts),
|
| 773 |
+
axis=0)
|
| 774 |
+
|
| 775 |
+
return (q_state, v_state, None)
|
| 776 |
+
|
| 777 |
+
def _set_is_full(self):
|
| 778 |
+
|
| 779 |
+
# measurements
|
| 780 |
+
q_full_root = self.robot_state.root_state.get(data_type="q_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 781 |
+
v_root = self.robot_state.root_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 782 |
+
omega = self.robot_state.root_state.get(data_type="omega", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 783 |
+
a_root = self.robot_state.root_state.get(data_type="a_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 784 |
+
|
| 785 |
+
q_jnts = self.robot_state.jnts_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 786 |
+
v_jnts = self.robot_state.jnts_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 787 |
+
a_jnts = self.robot_state.jnts_state.get(data_type="a", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 788 |
+
|
| 789 |
+
if (not len(self._continuous_joints)==0): # we need do expand some meas. rev jnts to So2
|
| 790 |
+
self._jnts_q_expanded[self._rev_joints_idxs, :]=q_jnts[self._rev_joints_idxs_red ,:]
|
| 791 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_cos, :]=np.cos(q_jnts[self._continuous_joints_idxs_red, :]) # cos
|
| 792 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_sin, :]=np.sin(q_jnts[self._continuous_joints_idxs_red, :]) # sin
|
| 793 |
+
q_jnts=self._jnts_q_expanded.reshape(-1,1)
|
| 794 |
+
|
| 795 |
+
# rhc variables to be set
|
| 796 |
+
q=self._prb.getVariables("q") # .setBounds()
|
| 797 |
+
root_full_q_rhc=q[0:7] # root p
|
| 798 |
+
jnts_q_rhc=q[7:] # jnts q
|
| 799 |
+
vel=self._prb.getVariables("v")
|
| 800 |
+
root_v_rhc=vel[0:3] # lin v.
|
| 801 |
+
root_omega_rhc=vel[3:6] # omega
|
| 802 |
+
jnts_v_rhc=vel[6:] # jnts v
|
| 803 |
+
acc=self._prb.getVariables("a")
|
| 804 |
+
lin_a_prb=acc[0:3] # lin acc
|
| 805 |
+
|
| 806 |
+
self.rhc_refs.set_alpha(alpha=0.0) # non-adaptive
|
| 807 |
+
|
| 808 |
+
root_full_q_rhc.setBounds(lb=q_full_root,
|
| 809 |
+
ub=q_full_root, nodes=0)
|
| 810 |
+
jnts_q_rhc.setBounds(lb=q_jnts,
|
| 811 |
+
ub=q_jnts, nodes=0)
|
| 812 |
+
root_v_rhc.setBounds(lb=v_root,
|
| 813 |
+
ub=v_root, nodes=0) # leaving lin v of the base free (estimated from constraints)
|
| 814 |
+
root_omega_rhc.setBounds(lb=omega,
|
| 815 |
+
ub=omega, nodes=0)
|
| 816 |
+
jnts_v_rhc.setBounds(lb=v_jnts,
|
| 817 |
+
ub=v_jnts, nodes=0)
|
| 818 |
+
if self._custom_opts["lin_a_feedback"]:
|
| 819 |
+
# write base lin 13793197 from meas
|
| 820 |
+
lin_a_prb.setBounds(lb=a_root[0:3, :],
|
| 821 |
+
ub=a_root[0:3, :],
|
| 822 |
+
nodes=0)
|
| 823 |
+
|
| 824 |
+
# return state used for feedback
|
| 825 |
+
q_state=np.concatenate((q_full_root, q_jnts),
|
| 826 |
+
axis=0)
|
| 827 |
+
v_state=np.concatenate((v_root, omega, v_jnts),
|
| 828 |
+
axis=0)
|
| 829 |
+
a_state=np.concatenate((a_root, a_jnts),
|
| 830 |
+
axis=0)
|
| 831 |
+
|
| 832 |
+
return (q_state, v_state, a_state)
|
| 833 |
+
|
| 834 |
+
def _set_is_partial(self):
|
| 835 |
+
|
| 836 |
+
# measurements
|
| 837 |
+
p_root = self.robot_state.root_state.get(data_type="p", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 838 |
+
q_root = self.robot_state.root_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 839 |
+
v_root = self.robot_state.root_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 840 |
+
omega = self.robot_state.root_state.get(data_type="omega", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 841 |
+
a_root = self.robot_state.root_state.get(data_type="a_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 842 |
+
|
| 843 |
+
q_jnts = self.robot_state.jnts_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 844 |
+
v_jnts = self.robot_state.jnts_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 845 |
+
a_jnts = self.robot_state.jnts_state.get(data_type="a", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 846 |
+
|
| 847 |
+
if (not len(self._continuous_joints)==0): # we need do expand some meas. rev jnts to So2
|
| 848 |
+
self._jnts_q_expanded[self._rev_joints_idxs, :]=q_jnts[self._rev_joints_idxs_red ,:]
|
| 849 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_cos, :]=np.cos(q_jnts[self._continuous_joints_idxs_red, :]) # cos
|
| 850 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_sin, :]=np.sin(q_jnts[self._continuous_joints_idxs_red, :]) # sin
|
| 851 |
+
q_jnts=self._jnts_q_expanded.reshape(-1,1)
|
| 852 |
+
|
| 853 |
+
# overriding states with rhc data (-> all overridden state are open looop)
|
| 854 |
+
root_q_full_from_rhc=self._get_root_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 855 |
+
root_p_from_rhc=root_q_full_from_rhc[0:3, :]
|
| 856 |
+
p_root[:, :]=root_p_from_rhc # position is always open loop
|
| 857 |
+
if not self._custom_opts["estimate_v_root"]:
|
| 858 |
+
v_root[:, :]=self._get_root_twist_from_sol(node_idx=1)[:, 0:3].reshape(-1, 1)
|
| 859 |
+
# override v jnts with the ones from controller
|
| 860 |
+
if not self._custom_opts["use_jnt_v_feedback"]:
|
| 861 |
+
v_jnts[:, :]=self._get_jnt_v_from_sol(node_idx=1).reshape(-1, 1)
|
| 862 |
+
# v_jnts[:, :]=self._get_jnt_v_from_sol(node_idx=1).reshape(-1, 1)
|
| 863 |
+
# root_twist_from_rhc=self._get_root_twist_from_sol(node_idx=1)
|
| 864 |
+
# root_v_from_rhc=root_twist_from_rhc[:, 0:3].reshape(-1, 1)
|
| 865 |
+
# root_omega_from_rhc=root_twist_from_rhc[:, 3:6].reshape(-1, 1)
|
| 866 |
+
# jnt_q_from_rhc=self._get_jnt_q_from_sol(node_idx=1,reduce=False,clamp=False).reshape(-1, 1)
|
| 867 |
+
# jnt_v_from_rhc=self._get_jnt_v_from_sol(node_idx=1).reshape(-1, 1)
|
| 868 |
+
|
| 869 |
+
# rhc variables to be set
|
| 870 |
+
q=self._prb.getVariables("q") # .setBounds()
|
| 871 |
+
root_p_rhc=q[0:3] # root p
|
| 872 |
+
root_q_rhc=q[3:7] # root orientation
|
| 873 |
+
jnts_q_rhc=q[7:] # jnts q
|
| 874 |
+
vel=self._prb.getVariables("v")
|
| 875 |
+
root_v_rhc=vel[0:3] # lin v.
|
| 876 |
+
root_omega_rhc=vel[3:6] # omega
|
| 877 |
+
jnts_v_rhc=vel[6:] # jnts v
|
| 878 |
+
acc=self._prb.getVariables("a")
|
| 879 |
+
lin_a_prb=acc[0:3] # lin acc
|
| 880 |
+
|
| 881 |
+
self.rhc_refs.set_alpha(alpha=0.0) # non-adaptive
|
| 882 |
+
|
| 883 |
+
root_p_rhc.setBounds(lb=p_root,
|
| 884 |
+
ub=p_root, nodes=0)
|
| 885 |
+
root_q_rhc.setBounds(lb=q_root,
|
| 886 |
+
ub=q_root, nodes=0)
|
| 887 |
+
jnts_q_rhc.setBounds(lb=q_jnts,
|
| 888 |
+
ub=q_jnts, nodes=0)
|
| 889 |
+
if self._custom_opts["estimate_v_root"]:
|
| 890 |
+
root_v_rhc.setBounds(lb=-self._v_inf[0:3],
|
| 891 |
+
ub=self._v_inf[0:3], nodes=0) # leaving lin v of the base free (estimated from constraints)
|
| 892 |
+
else: # get it from controller
|
| 893 |
+
root_v_rhc.setBounds(lb=v_root,
|
| 894 |
+
ub=v_root, nodes=0)
|
| 895 |
+
root_omega_rhc.setBounds(lb=omega,
|
| 896 |
+
ub=omega, nodes=0)
|
| 897 |
+
jnts_v_rhc.setBounds(lb=v_jnts,
|
| 898 |
+
ub=v_jnts, nodes=0)
|
| 899 |
+
if self._custom_opts["lin_a_feedback"]:
|
| 900 |
+
# write base lin 13793197 from meas
|
| 901 |
+
lin_a_prb.setBounds(lb=a_root[0:3, :],
|
| 902 |
+
ub=a_root[0:3, :],
|
| 903 |
+
nodes=0)
|
| 904 |
+
|
| 905 |
+
# return state used for feedback
|
| 906 |
+
q_state=np.concatenate((p_root, q_root, q_jnts),
|
| 907 |
+
axis=0)
|
| 908 |
+
v_state=np.concatenate((v_root, omega, v_jnts),
|
| 909 |
+
axis=0)
|
| 910 |
+
a_state=np.concatenate((a_root, a_jnts),
|
| 911 |
+
axis=0)
|
| 912 |
+
|
| 913 |
+
return (q_state, v_state, a_state)
|
| 914 |
+
|
| 915 |
+
def _set_is_adaptive(self):
|
| 916 |
+
|
| 917 |
+
# measurements
|
| 918 |
+
p_root = self.robot_state.root_state.get(data_type="p", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 919 |
+
q_root = self.robot_state.root_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 920 |
+
v_root = self.robot_state.root_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 921 |
+
omega = self.robot_state.root_state.get(data_type="omega", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 922 |
+
a_root = self.robot_state.root_state.get(data_type="a_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 923 |
+
|
| 924 |
+
q_jnts = self.robot_state.jnts_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 925 |
+
v_jnts = self.robot_state.jnts_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 926 |
+
a_jnts = self.robot_state.jnts_state.get(data_type="a", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 927 |
+
|
| 928 |
+
# rhc variables to be set
|
| 929 |
+
q=self._prb.getVariables("q") # .setBounds()
|
| 930 |
+
root_p_rhc=q[0:3] # root p
|
| 931 |
+
root_q_rhc=q[3:7] # root orientation
|
| 932 |
+
jnts_q_rhc=q[7:] # jnts q
|
| 933 |
+
vel=self._prb.getVariables("v")
|
| 934 |
+
root_v_rhc=vel[0:3] # lin v.
|
| 935 |
+
root_omega_rhc=vel[3:6] # omega
|
| 936 |
+
jnts_v_rhc=vel[6:] # jnts v
|
| 937 |
+
acc=self._prb.getVariables("a")
|
| 938 |
+
lin_a_prb=acc[0:3] # lin acc
|
| 939 |
+
|
| 940 |
+
# getting prediction defects
|
| 941 |
+
root_q_delta=self.rhc_pred_delta.root_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 942 |
+
jnt_q_delta=self.rhc_pred_delta.jnts_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 943 |
+
jnt_v_delta=self.rhc_pred_delta.jnts_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 944 |
+
v_root_delta = self.rhc_pred_delta.root_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 945 |
+
omega_root_delta = self.rhc_pred_delta.root_state.get(data_type="omega", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 946 |
+
a_root_delta = self.rhc_pred_delta.root_state.get(data_type="a_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 947 |
+
|
| 948 |
+
# close state on known quantities, estimate some (e.g. lin vel) and
|
| 949 |
+
# open loop if thing start to explode
|
| 950 |
+
alpha_now=1.0
|
| 951 |
+
delta=0.0
|
| 952 |
+
if self._custom_opts["alpha_from_outside"]:
|
| 953 |
+
alpha_now=self.rhc_refs.get_alpha()
|
| 954 |
+
else: # "autotuned" alpha
|
| 955 |
+
if self._custom_opts["estimate_v_root"]: # we copmute delta based on jnt v (since we use meas.)
|
| 956 |
+
delta=np.max(np.abs(jnt_v_delta))
|
| 957 |
+
else:
|
| 958 |
+
delta=np.max(np.abs(omega_root_delta))
|
| 959 |
+
# fail_idx=self._get_failure_index()
|
| 960 |
+
# fail_idx=self._get_explosion_idx()/self._fail_idx_thresh
|
| 961 |
+
alpha_now=(np.tanh(2*self._alpha_half*(delta-self._alpha_half))+1)/2.0
|
| 962 |
+
|
| 963 |
+
bound_relaxation=-np.log(1-alpha_now+1e-16) # [~0, ~inf] if alpha_now [0, 1]
|
| 964 |
+
self.rhc_refs.set_alpha(alpha=alpha_now) # also writes on shared mem for db
|
| 965 |
+
self.rhc_refs.set_bound_relax(bound_relax=bound_relaxation) # also writes on shared mem for db
|
| 966 |
+
|
| 967 |
+
self._alphas_q_root[:]=alpha_now # for now single alpha for everything
|
| 968 |
+
self._alphas_q_jnts[:]=alpha_now
|
| 969 |
+
self._alphas_twist_root[:]=alpha_now
|
| 970 |
+
self._alphas_v_jnts[:]=alpha_now
|
| 971 |
+
self._alphas_a[:]=alpha_now
|
| 972 |
+
if not self._custom_opts["estimate_v_root"]:
|
| 973 |
+
self._alphas_twist_root[0:3]=1.0 # open
|
| 974 |
+
self._alphas_v_jnts[:]=1.0 # open
|
| 975 |
+
|
| 976 |
+
# position is always open loop
|
| 977 |
+
root_q_full_from_rhc=self._get_root_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 978 |
+
root_p_from_rhc=root_q_full_from_rhc[0:3, :]
|
| 979 |
+
p_root[:, :]=root_p_from_rhc
|
| 980 |
+
|
| 981 |
+
# expaning meas q if continuous joints
|
| 982 |
+
if (not len(self._continuous_joints)==0): # we need do expand some meas. rev jnts to So2
|
| 983 |
+
self._jnts_q_expanded[self._rev_joints_idxs, :]=q_jnts[self._rev_joints_idxs_red ,:]
|
| 984 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_cos, :]=np.cos(q_jnts[self._continuous_joints_idxs_red, :]) # cos
|
| 985 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_sin, :]=np.sin(q_jnts[self._continuous_joints_idxs_red, :]) # sin
|
| 986 |
+
|
| 987 |
+
# continous joints position is always open loop, but we need a delta vector of matching dimension
|
| 988 |
+
q_jnts_from_rhc=self._get_jnt_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 989 |
+
|
| 990 |
+
self._jnts_q_delta_expanded[self._rev_joints_idxs, :]=jnt_q_delta[self._rev_joints_idxs_red ,:]
|
| 991 |
+
|
| 992 |
+
self._jnts_q_delta_expanded[self._continuous_joints_idxs_cos, :]=\
|
| 993 |
+
np.cos(q_jnts_from_rhc[self._continuous_joints_idxs_red, :]) - \
|
| 994 |
+
np.cos(q_jnts[self._continuous_joints_idxs_red, :])
|
| 995 |
+
self._jnts_q_delta_expanded[self._continuous_joints_idxs_sin, :]=\
|
| 996 |
+
np.sin(q_jnts_from_rhc[self._continuous_joints_idxs_red, :]) - \
|
| 997 |
+
np.sin(q_jnts[self._continuous_joints_idxs_red, :])
|
| 998 |
+
|
| 999 |
+
q_jnts=self._jnts_q_expanded.reshape(-1,1) # overriting with expanded jnts
|
| 1000 |
+
jnt_q_delta=self._jnts_q_delta_expanded.reshape(-1, 1) # overriting with expanded jnts
|
| 1001 |
+
|
| 1002 |
+
self._alphas_q_jnts[self._continuous_joints_idxs_cos, :]=1.0 # open loop
|
| 1003 |
+
self._alphas_q_jnts[self._continuous_joints_idxs_sin, :]=1.0 # open loop
|
| 1004 |
+
|
| 1005 |
+
# self._alphas_v_jnts[self._continuous_joints_idxs_red, :]=0.0 # open loop
|
| 1006 |
+
|
| 1007 |
+
root_p_rhc.setBounds(lb=p_root,
|
| 1008 |
+
ub=p_root, nodes=0)
|
| 1009 |
+
root_q_rhc.setBounds(lb=q_root+self._alphas_q_root[3:7]*root_q_delta,
|
| 1010 |
+
ub=q_root+self._alphas_q_root[3:7]*root_q_delta, nodes=0)
|
| 1011 |
+
jnts_q_rhc.setBounds(lb=q_jnts+self._alphas_q_jnts*jnt_q_delta,
|
| 1012 |
+
ub=q_jnts+self._alphas_q_jnts*jnt_q_delta, nodes=0)
|
| 1013 |
+
if self._custom_opts["estimate_v_root"]:
|
| 1014 |
+
root_v_rhc.setBounds(lb=-self._v_inf[0:3],
|
| 1015 |
+
ub=self._v_inf[0:3], nodes=0)
|
| 1016 |
+
else:
|
| 1017 |
+
root_v_rhc.setBounds(lb=v_root+self._alphas_twist_root[0:3, :]*v_root_delta,
|
| 1018 |
+
ub=v_root+self._alphas_twist_root[0:3, :]*v_root_delta, nodes=0)
|
| 1019 |
+
root_omega_rhc.setBounds(lb=omega+self._alphas_twist_root[3:6, :]*omega_root_delta,
|
| 1020 |
+
ub=omega+self._alphas_twist_root[3:6, :]*omega_root_delta, nodes=0)
|
| 1021 |
+
jnts_v_rhc.setBounds(lb=v_jnts+self._alphas_v_jnts*jnt_v_delta,
|
| 1022 |
+
ub=v_jnts+self._alphas_v_jnts*jnt_v_delta, nodes=0)
|
| 1023 |
+
if self._custom_opts["lin_a_feedback"]:
|
| 1024 |
+
lin_a_prb.setBounds(lb=a_root[0:3, :]+self._alphas_a[0:3]*a_root_delta[0:3, :],
|
| 1025 |
+
ub=a_root[0:3, :]+self._alphas_a[0:3]*a_root_delta[0:3, :],
|
| 1026 |
+
nodes=0)
|
| 1027 |
+
|
| 1028 |
+
# return state used for feedback
|
| 1029 |
+
q_state=np.concatenate((p_root, q_root, q_jnts),
|
| 1030 |
+
axis=0)
|
| 1031 |
+
v_state=np.concatenate((v_root, omega, v_jnts),
|
| 1032 |
+
axis=0)
|
| 1033 |
+
a_state=np.concatenate((a_root, a_jnts),
|
| 1034 |
+
axis=0)
|
| 1035 |
+
|
| 1036 |
+
return (q_state, v_state, a_state)
|
| 1037 |
+
|
| 1038 |
+
def _solve(self):
|
| 1039 |
+
|
| 1040 |
+
if self._debug:
|
| 1041 |
+
return self._db_solve()
|
| 1042 |
+
else:
|
| 1043 |
+
return self._min_solve()
|
| 1044 |
+
|
| 1045 |
+
def _min_solve(self):
|
| 1046 |
+
# minimal solve version -> no debug
|
| 1047 |
+
robot_qstate=None
|
| 1048 |
+
robot_vstate=None
|
| 1049 |
+
robot_astate=None
|
| 1050 |
+
if self._open_loop:
|
| 1051 |
+
robot_qstate, robot_vstate, robot_astate = self._update_open_loop() # updates the TO ig and
|
| 1052 |
+
# initial conditions using data from the solution itself
|
| 1053 |
+
else:
|
| 1054 |
+
robot_qstate, robot_vstate, robot_astate = self._update_closed_loop() # updates the TO ig and
|
| 1055 |
+
# initial conditions using robot measurements
|
| 1056 |
+
|
| 1057 |
+
self._pm.shift() # shifts phases of one dt
|
| 1058 |
+
if self._refs_in_hor_frame:
|
| 1059 |
+
# q_base=self.robot_state.root_state.get(data_type="q",
|
| 1060 |
+
# robot_idxs=self.controller_index).reshape(-1, 1)
|
| 1061 |
+
# q_full=self._get_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 1062 |
+
# using internal base pose from rhc. in case of closed loop, it will be the meas state
|
| 1063 |
+
force_norm=None
|
| 1064 |
+
if self._custom_opts["use_force_feedback"]:
|
| 1065 |
+
contact_forces=self.robot_state.contact_wrenches.get(data_type="f",
|
| 1066 |
+
robot_idxs=self.controller_index_np,
|
| 1067 |
+
contact_name=None).reshape(self.n_contacts,3)
|
| 1068 |
+
force_norm=np.linalg.norm(contact_forces, axis=1)
|
| 1069 |
+
self.rhc_refs.step(qstate=robot_qstate, vstate=robot_vstate,
|
| 1070 |
+
force_norm=force_norm)
|
| 1071 |
+
else:
|
| 1072 |
+
self.rhc_refs.step()
|
| 1073 |
+
|
| 1074 |
+
try:
|
| 1075 |
+
converged = self._ti.rti() # solves the problem
|
| 1076 |
+
self.sol_counter = self.sol_counter + 1
|
| 1077 |
+
return not self._check_rhc_failure()
|
| 1078 |
+
except Exception as e: # fail in case of exceptions
|
| 1079 |
+
return False
|
| 1080 |
+
|
| 1081 |
+
def _db_solve(self):
|
| 1082 |
+
|
| 1083 |
+
self._timer_start = time.perf_counter()
|
| 1084 |
+
|
| 1085 |
+
robot_qstate=None
|
| 1086 |
+
robot_vstate=None
|
| 1087 |
+
robot_astate=None
|
| 1088 |
+
if self._open_loop:
|
| 1089 |
+
robot_qstate, robot_vstate, robot_astate = self._update_open_loop() # updates the TO ig and
|
| 1090 |
+
# initial conditions using data from the solution itself
|
| 1091 |
+
else:
|
| 1092 |
+
robot_qstate, robot_vstate, robot_astate = self._update_closed_loop() # updates the TO ig and
|
| 1093 |
+
# initial conditions using robot measurements
|
| 1094 |
+
|
| 1095 |
+
self._prb_update_time = time.perf_counter()
|
| 1096 |
+
self._pm.shift() # shifts phases of one dt
|
| 1097 |
+
self._phase_shift_time = time.perf_counter()
|
| 1098 |
+
|
| 1099 |
+
if self._refs_in_hor_frame:
|
| 1100 |
+
# q_base=self.robot_state.root_state.get(data_type="q",
|
| 1101 |
+
# robot_idxs=self.controller_index).reshape(-1, 1)
|
| 1102 |
+
# q_full=self._get_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 1103 |
+
# using internal base pose from rhc. in case of closed loop, it will be the meas state
|
| 1104 |
+
force_norm=None
|
| 1105 |
+
if self._custom_opts["use_force_feedback"]:
|
| 1106 |
+
contact_forces=self.robot_state.contact_wrenches.get(data_type="f",
|
| 1107 |
+
robot_idxs=self.controller_index_np,
|
| 1108 |
+
contact_name=None).reshape(self.n_contacts,3)
|
| 1109 |
+
force_norm=np.linalg.norm(contact_forces, axis=1)
|
| 1110 |
+
self.rhc_refs.step(qstate=robot_qstate, vstate=robot_vstate,
|
| 1111 |
+
force_norm=force_norm)
|
| 1112 |
+
else:
|
| 1113 |
+
self.rhc_refs.step()
|
| 1114 |
+
|
| 1115 |
+
self._task_ref_update_time = time.perf_counter()
|
| 1116 |
+
|
| 1117 |
+
try:
|
| 1118 |
+
converged = self._ti.rti() # solves the problem
|
| 1119 |
+
self._rti_time = time.perf_counter()
|
| 1120 |
+
self.sol_counter = self.sol_counter + 1
|
| 1121 |
+
self._update_db_data()
|
| 1122 |
+
return not self._check_rhc_failure()
|
| 1123 |
+
except Exception as e: # fail in case of exceptions
|
| 1124 |
+
if self._verbose:
|
| 1125 |
+
exception = f"Rti() for controller {self.controller_index} failed" + \
|
| 1126 |
+
f" with exception{type(e).__name__}"
|
| 1127 |
+
Journal.log(self.__class__.__name__,
|
| 1128 |
+
"solve",
|
| 1129 |
+
exception,
|
| 1130 |
+
LogType.EXCEP,
|
| 1131 |
+
throw_when_excep = False)
|
| 1132 |
+
self._update_db_data()
|
| 1133 |
+
return False
|
| 1134 |
+
|
| 1135 |
+
def _get_fail_idx(self):
|
| 1136 |
+
|
| 1137 |
+
self._explosion_idx_buffer[:, self._expl_idx_buffer_counter]=self._get_explosion_idx()
|
| 1138 |
+
self._expl_idx_buffer_counter+=1
|
| 1139 |
+
self._expl_idx_counter+=1
|
| 1140 |
+
if self._expl_idx_counter%self._expl_idx_window_size==0:
|
| 1141 |
+
self._expl_idx_buffer_counter=0 # restart from 0
|
| 1142 |
+
|
| 1143 |
+
running_avrg=np.mean(self._explosion_idx_buffer).item()
|
| 1144 |
+
|
| 1145 |
+
return running_avrg
|
| 1146 |
+
|
| 1147 |
+
def _get_explosion_idx(self):
|
| 1148 |
+
explosion_index = self._get_rhc_constr_viol() + self._get_rhc_cost()*self._fail_idx_scale
|
| 1149 |
+
return explosion_index
|
| 1150 |
+
|
| 1151 |
+
def _update_db_data(self):
|
| 1152 |
+
|
| 1153 |
+
self._profiling_data_dict["problem_update_dt"] = self._prb_update_time - self._timer_start
|
| 1154 |
+
self._profiling_data_dict["phases_shift_dt"] = self._phase_shift_time - self._prb_update_time
|
| 1155 |
+
self._profiling_data_dict["task_ref_update"] = self._task_ref_update_time - self._phase_shift_time
|
| 1156 |
+
self._profiling_data_dict["rti_solve_dt"] = self._rti_time - self._task_ref_update_time
|
| 1157 |
+
self.rhc_costs.update(self._ti.solver_rti.getCostsValues())
|
| 1158 |
+
self.rhc_constr.update(self._ti.solver_rti.getConstraintsValues())
|
| 1159 |
+
|
| 1160 |
+
def _reset(self):
|
| 1161 |
+
|
| 1162 |
+
# reset task interface (ig, solvers, etc..) +
|
| 1163 |
+
# phase manager and sets bootstap as solution
|
| 1164 |
+
self._gm.reset()
|
| 1165 |
+
self._explosion_idx_buffer[:, :]=self._get_explosion_idx() # reset with data from reset solution
|
| 1166 |
+
self._expl_idx_counter=0.0
|
| 1167 |
+
self._expl_idx_buffer_counter=0
|
| 1168 |
+
|
| 1169 |
+
def _get_cost_data(self):
|
| 1170 |
+
|
| 1171 |
+
cost_dict = self._ti.solver_rti.getCostsValues()
|
| 1172 |
+
cost_names = list(cost_dict.keys())
|
| 1173 |
+
cost_dims = [1] * len(cost_names) # costs are always scalar
|
| 1174 |
+
return cost_names, cost_dims
|
| 1175 |
+
|
| 1176 |
+
def _get_constr_data(self):
|
| 1177 |
+
|
| 1178 |
+
constr_dict = self._ti.solver_rti.getConstraintsValues()
|
| 1179 |
+
constr_names = list(constr_dict.keys())
|
| 1180 |
+
constr_dims = [-1] * len(constr_names)
|
| 1181 |
+
i = 0
|
| 1182 |
+
for constr in constr_dict:
|
| 1183 |
+
constr_val = constr_dict[constr]
|
| 1184 |
+
constr_shape = constr_val.shape
|
| 1185 |
+
constr_dims[i] = constr_shape[0]
|
| 1186 |
+
i+=1
|
| 1187 |
+
return constr_names, constr_dims
|
| 1188 |
+
|
| 1189 |
+
def _get_q_from_sol(self):
|
| 1190 |
+
full_q=self._ti.solution['q'].astype(self._dtype)
|
| 1191 |
+
if self._custom_opts["replace_continuous_joints"]:
|
| 1192 |
+
return full_q
|
| 1193 |
+
else:
|
| 1194 |
+
cont_jnts=full_q[self._continuous_joints_idxs_qfull, :]
|
| 1195 |
+
cos=cont_jnts[::2, :]
|
| 1196 |
+
sin=cont_jnts[1::2, :]
|
| 1197 |
+
# copy root
|
| 1198 |
+
self._full_q_reduced[0:7, :]=full_q[0:7, :]
|
| 1199 |
+
# copy rev joint vals
|
| 1200 |
+
self._full_q_reduced[self._rev_joints_idxs_red_qfull, :]=full_q[self._rev_joints_idxs_qfull, :]
|
| 1201 |
+
# and continuous
|
| 1202 |
+
angle=np.arctan2(sin, cos)
|
| 1203 |
+
self._full_q_reduced[self._continuous_joints_idxs_red_qfull, :]=angle
|
| 1204 |
+
return self._full_q_reduced
|
| 1205 |
+
|
| 1206 |
+
def _get_v_from_sol(self):
|
| 1207 |
+
return self._ti.solution['v'].astype(self._dtype)
|
| 1208 |
+
|
| 1209 |
+
def _get_a_from_sol(self):
|
| 1210 |
+
return self._ti.solution['a'].astype(self._dtype)
|
| 1211 |
+
|
| 1212 |
+
def _get_a_dot_from_sol(self):
|
| 1213 |
+
return None
|
| 1214 |
+
|
| 1215 |
+
def _get_f_from_sol(self):
|
| 1216 |
+
# to be overridden by child class
|
| 1217 |
+
contact_names =self._get_contacts() # we use controller-side names
|
| 1218 |
+
try:
|
| 1219 |
+
data=[]
|
| 1220 |
+
for key in contact_names:
|
| 1221 |
+
contact_f=self._ti.solution["f_" + key].astype(self._dtype)
|
| 1222 |
+
np.nan_to_num(contact_f, nan=1e6, posinf=1e6, neginf=-1e6, copy=False)
|
| 1223 |
+
np.clip(a=contact_f, a_max=1e6, a_min=-1e6, out=contact_f)
|
| 1224 |
+
data.append(contact_f)
|
| 1225 |
+
return np.concatenate(data, axis=0)
|
| 1226 |
+
except:
|
| 1227 |
+
return None
|
| 1228 |
+
|
| 1229 |
+
def _get_f_dot_from_sol(self):
|
| 1230 |
+
# to be overridden by child class
|
| 1231 |
+
return None
|
| 1232 |
+
|
| 1233 |
+
def _get_eff_from_sol(self):
|
| 1234 |
+
# to be overridden by child class
|
| 1235 |
+
return None
|
| 1236 |
+
|
| 1237 |
+
def _get_cost_from_sol(self,
|
| 1238 |
+
cost_name: str):
|
| 1239 |
+
return self.rhc_costs[cost_name]
|
| 1240 |
+
|
| 1241 |
+
def _get_constr_from_sol(self,
|
| 1242 |
+
constr_name: str):
|
| 1243 |
+
return self.rhc_constr[constr_name]
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/hybrid_quad_rhc_refs.py
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from aug_mpc.controllers.rhc.horizon_based.gait_manager import GaitManager
|
| 2 |
+
from aug_mpc.controllers.rhc.horizon_based.utils.math_utils import hor2w_frame
|
| 3 |
+
|
| 4 |
+
from mpc_hive.utilities.shared_data.rhc_data import RhcRefs
|
| 5 |
+
|
| 6 |
+
from EigenIPC.PyEigenIPC import VLevel
|
| 7 |
+
from EigenIPC.PyEigenIPC import LogType
|
| 8 |
+
from EigenIPC.PyEigenIPC import Journal
|
| 9 |
+
|
| 10 |
+
from typing import Union
|
| 11 |
+
|
| 12 |
+
import numpy as np
|
| 13 |
+
|
| 14 |
+
class HybridQuadRhcRefs(RhcRefs):
|
| 15 |
+
|
| 16 |
+
def __init__(self,
|
| 17 |
+
gait_manager: GaitManager,
|
| 18 |
+
robot_index_shm: int,
|
| 19 |
+
robot_index_view: int,
|
| 20 |
+
namespace: str, # namespace used for shared mem
|
| 21 |
+
verbose: bool = True,
|
| 22 |
+
vlevel: bool = VLevel.V2,
|
| 23 |
+
safe: bool = True,
|
| 24 |
+
use_force_feedback: bool = False,
|
| 25 |
+
optimize_mem: bool = False):
|
| 26 |
+
|
| 27 |
+
self.robot_index = robot_index_shm
|
| 28 |
+
self.robot_index_view = robot_index_view
|
| 29 |
+
self.robot_index_np_view = np.array(self.robot_index_view)
|
| 30 |
+
|
| 31 |
+
self._step_idx = 0
|
| 32 |
+
self._print_frequency = 100
|
| 33 |
+
|
| 34 |
+
self._verbose = verbose
|
| 35 |
+
|
| 36 |
+
self._use_force_feedback=use_force_feedback
|
| 37 |
+
|
| 38 |
+
if optimize_mem:
|
| 39 |
+
super().__init__(
|
| 40 |
+
is_server=False,
|
| 41 |
+
with_gpu_mirror=False,
|
| 42 |
+
namespace=namespace,
|
| 43 |
+
safe=safe,
|
| 44 |
+
verbose=verbose,
|
| 45 |
+
vlevel=vlevel,
|
| 46 |
+
optimize_mem=optimize_mem,
|
| 47 |
+
n_robots=1, # we just need the row corresponding to this controller
|
| 48 |
+
n_jnts=None, # got from server
|
| 49 |
+
n_contacts=None # got from server
|
| 50 |
+
)
|
| 51 |
+
else:
|
| 52 |
+
super().__init__(
|
| 53 |
+
is_server=False,
|
| 54 |
+
with_gpu_mirror=False,
|
| 55 |
+
namespace=namespace,
|
| 56 |
+
safe=safe,
|
| 57 |
+
verbose=verbose,
|
| 58 |
+
vlevel=vlevel)
|
| 59 |
+
|
| 60 |
+
if not isinstance(gait_manager, GaitManager):
|
| 61 |
+
exception = f"Provided gait_manager argument should be of GaitManager type!"
|
| 62 |
+
Journal.log(self.__class__.__name__,
|
| 63 |
+
"__init__",
|
| 64 |
+
exception,
|
| 65 |
+
LogType.EXCEP,
|
| 66 |
+
throw_when_excep = True)
|
| 67 |
+
|
| 68 |
+
self.gait_manager = gait_manager
|
| 69 |
+
|
| 70 |
+
self.timeline_names = self.gait_manager.timeline_names
|
| 71 |
+
|
| 72 |
+
# task interfaces from horizon for setting commands to rhc
|
| 73 |
+
self._get_tasks()
|
| 74 |
+
|
| 75 |
+
self._p_ref_default=np.zeros((1, 3))
|
| 76 |
+
self._q_ref_default=np.zeros((1, 4))
|
| 77 |
+
self._q_ref_default[0, 0]=1
|
| 78 |
+
|
| 79 |
+
def _get_tasks(self):
|
| 80 |
+
# can be overridden by child
|
| 81 |
+
# cartesian tasks are in LOCAL_WORLD_ALIGNED (frame centered at distal link, oriented as WORLD)
|
| 82 |
+
self.base_lin_velxy = self.gait_manager.task_interface.getTask('base_lin_velxy')
|
| 83 |
+
self.base_lin_velz = self.gait_manager.task_interface.getTask('base_lin_velz')
|
| 84 |
+
self.base_omega = self.gait_manager.task_interface.getTask('base_omega')
|
| 85 |
+
self.base_height = self.gait_manager.task_interface.getTask('base_height')
|
| 86 |
+
|
| 87 |
+
def run(self):
|
| 88 |
+
|
| 89 |
+
super().run()
|
| 90 |
+
if not (self.robot_index < self.rob_refs.n_robots()):
|
| 91 |
+
exception = f"Provided \(0-based\) robot index {self.robot_index} exceeds number of " + \
|
| 92 |
+
" available robots {self.rob_refs.n_robots()}."
|
| 93 |
+
Journal.log(self.__class__.__name__,
|
| 94 |
+
"run",
|
| 95 |
+
exception,
|
| 96 |
+
LogType.EXCEP,
|
| 97 |
+
throw_when_excep = True)
|
| 98 |
+
contact_names = list(self.gait_manager.task_interface.model.cmap.keys())
|
| 99 |
+
if not (self.n_contacts() == len(contact_names)):
|
| 100 |
+
exception = f"N of contacts within problem {len(contact_names)} does not match n of contacts {self.n_contacts()}"
|
| 101 |
+
Journal.log(self.__class__.__name__,
|
| 102 |
+
"run",
|
| 103 |
+
exception,
|
| 104 |
+
LogType.EXCEP,
|
| 105 |
+
throw_when_excep = True)
|
| 106 |
+
|
| 107 |
+
# set some defaults from gait manager
|
| 108 |
+
for i in range(self.n_contacts()):
|
| 109 |
+
self.flight_settings_req.set(data=self.gait_manager.get_flight_duration(contact_name=contact_names[i]),
|
| 110 |
+
data_type="len_remain",
|
| 111 |
+
robot_idxs=self.robot_index_np_view,
|
| 112 |
+
contact_idx=i)
|
| 113 |
+
self.flight_settings_req.set(data=self.gait_manager.get_step_apexdh(contact_name=contact_names[i]),
|
| 114 |
+
data_type="apex_dpos",
|
| 115 |
+
robot_idxs=self.robot_index_np_view,
|
| 116 |
+
contact_idx=i)
|
| 117 |
+
self.flight_settings_req.set(data=self.gait_manager.get_step_enddh(contact_name=contact_names[i]),
|
| 118 |
+
data_type="end_dpos",
|
| 119 |
+
robot_idxs=self.robot_index_np_view,
|
| 120 |
+
contact_idx=i)
|
| 121 |
+
|
| 122 |
+
self.flight_settings_req.synch_retry(row_index=self.robot_index,
|
| 123 |
+
col_index=0,
|
| 124 |
+
row_index_view=self.robot_index_view,
|
| 125 |
+
n_rows=1,
|
| 126 |
+
n_cols=self.flight_settings_req.n_cols,
|
| 127 |
+
read=False)
|
| 128 |
+
|
| 129 |
+
def step(self, qstate: np.ndarray = None,
|
| 130 |
+
vstate: np.ndarray = None,
|
| 131 |
+
force_norm: np.ndarray = None):
|
| 132 |
+
|
| 133 |
+
if self.is_running():
|
| 134 |
+
|
| 135 |
+
# updates robot refs from shared mem
|
| 136 |
+
self.rob_refs.synch_from_shared_mem(robot_idx=self.robot_index, robot_idx_view=self.robot_index_view)
|
| 137 |
+
self.phase_id.synch_all(read=True, retry=True,
|
| 138 |
+
row_index=self.robot_index,
|
| 139 |
+
row_index_view=self.robot_index_view)
|
| 140 |
+
self.contact_flags.synch_all(read=True, retry=True,
|
| 141 |
+
row_index=self.robot_index,
|
| 142 |
+
row_index_view=self.robot_index_view)
|
| 143 |
+
self.flight_settings_req.synch_all(read=True, retry=True,
|
| 144 |
+
row_index=self.robot_index,
|
| 145 |
+
row_index_view=self.robot_index_view)
|
| 146 |
+
self._set_contact_phases(q_full=qstate)
|
| 147 |
+
|
| 148 |
+
# updated internal references with latest available ones
|
| 149 |
+
q_base=qstate[3:7,0:1] # quaternion
|
| 150 |
+
self._apply_refs_to_tasks(q_base=q_base)
|
| 151 |
+
|
| 152 |
+
# if self._use_force_feedback:
|
| 153 |
+
# self._set_force_feedback(force_norm=force_norm)
|
| 154 |
+
|
| 155 |
+
self._step_idx +=1
|
| 156 |
+
|
| 157 |
+
else:
|
| 158 |
+
exception = f"{self.__class__.__name__} is not running"
|
| 159 |
+
Journal.log(self.__class__.__name__,
|
| 160 |
+
"step",
|
| 161 |
+
exception,
|
| 162 |
+
LogType.EXCEP,
|
| 163 |
+
throw_when_excep = True)
|
| 164 |
+
|
| 165 |
+
def _set_contact_phases(self,
|
| 166 |
+
q_full: np.ndarray):
|
| 167 |
+
|
| 168 |
+
# phase_id = self.phase_id.read_retry(row_index=self.robot_index,
|
| 169 |
+
# col_index=0)[0]
|
| 170 |
+
|
| 171 |
+
contact_flags_refs = self.contact_flags.get_numpy_mirror()[self.robot_index_np_view, :]
|
| 172 |
+
target_n_limbs_in_contact=np.sum(contact_flags_refs).item()
|
| 173 |
+
if target_n_limbs_in_contact==0:
|
| 174 |
+
target_n_limbs_in_contact=4
|
| 175 |
+
|
| 176 |
+
is_contact = contact_flags_refs.flatten().tolist()
|
| 177 |
+
n_contacts=len(is_contact)
|
| 178 |
+
|
| 179 |
+
for i in range(n_contacts): # loop through contact timelines
|
| 180 |
+
timeline_name = self.timeline_names[i]
|
| 181 |
+
|
| 182 |
+
self.gait_manager.set_f_reg(contact_name=timeline_name,
|
| 183 |
+
scale=target_n_limbs_in_contact)
|
| 184 |
+
|
| 185 |
+
if is_contact[i]==False: # release contact
|
| 186 |
+
|
| 187 |
+
# flight parameters requests are set only when inserting a flight phase
|
| 188 |
+
len_req_now=int(self.flight_settings_req.get(data_type="len_remain",
|
| 189 |
+
robot_idxs=self.robot_index_np_view,
|
| 190 |
+
contact_idx=i).item())
|
| 191 |
+
apex_req_now=self.flight_settings_req.get(data_type="apex_dpos",
|
| 192 |
+
robot_idxs=self.robot_index_np_view,
|
| 193 |
+
contact_idx=i).item()
|
| 194 |
+
end_req_now=self.flight_settings_req.get(data_type="end_dpos",
|
| 195 |
+
robot_idxs=self.robot_index_np_view,
|
| 196 |
+
contact_idx=i).item()
|
| 197 |
+
landing_dx_req_now=self.flight_settings_req.get(data_type="land_dx",
|
| 198 |
+
robot_idxs=self.robot_index_np_view,
|
| 199 |
+
contact_idx=i).item()
|
| 200 |
+
landing_dy_req_now=self.flight_settings_req.get(data_type="land_dy",
|
| 201 |
+
robot_idxs=self.robot_index_np_view,
|
| 202 |
+
contact_idx=i).item()
|
| 203 |
+
|
| 204 |
+
# set flight phase properties depending on last value on shared memory
|
| 205 |
+
self.gait_manager.set_flight_duration(contact_name=timeline_name,
|
| 206 |
+
val=len_req_now)
|
| 207 |
+
self.gait_manager.set_step_apexdh(contact_name=timeline_name,
|
| 208 |
+
val=apex_req_now)
|
| 209 |
+
self.gait_manager.set_step_enddh(contact_name=timeline_name,
|
| 210 |
+
val=end_req_now)
|
| 211 |
+
self.gait_manager.set_step_landing_dx(contact_name=timeline_name,
|
| 212 |
+
val=landing_dx_req_now)
|
| 213 |
+
self.gait_manager.set_step_landing_dy(contact_name=timeline_name,
|
| 214 |
+
val=landing_dy_req_now)
|
| 215 |
+
# insert flight phase over the horizon
|
| 216 |
+
self.gait_manager.add_flight(contact_name=timeline_name,
|
| 217 |
+
robot_q=q_full)
|
| 218 |
+
|
| 219 |
+
else: # contact phase
|
| 220 |
+
self.gait_manager.add_stand(contact_name=timeline_name)
|
| 221 |
+
|
| 222 |
+
at_least_one_flight=self.gait_manager.update_flight_info(timeline_name)
|
| 223 |
+
# flight_info=self.gait_manager.get_flight_info(timeline_name)
|
| 224 |
+
|
| 225 |
+
self.gait_manager.check_horizon_full(timeline_name=timeline_name)
|
| 226 |
+
|
| 227 |
+
# write flight info to shared mem for all contacts in one shot (we follow same order as in flight_info shm)
|
| 228 |
+
all_flight_info=self.gait_manager.get_flight_info_all()
|
| 229 |
+
flight_info_shared=self.flight_info.get_numpy_mirror()
|
| 230 |
+
flight_info_shared[self.robot_index_np_view, :]=all_flight_info
|
| 231 |
+
self.flight_info.synch_retry(row_index=self.robot_index,
|
| 232 |
+
col_index=0,
|
| 233 |
+
row_index_view=self.robot_index_np_view,
|
| 234 |
+
n_rows=1, n_cols=self.flight_info.n_cols,
|
| 235 |
+
read=False)
|
| 236 |
+
|
| 237 |
+
self.gait_manager.update()
|
| 238 |
+
|
| 239 |
+
def _apply_refs_to_tasks(self, q_base = None):
|
| 240 |
+
# overrides parent
|
| 241 |
+
if q_base is not None: # rhc refs are assumed to be specified in the so called "horizontal"
|
| 242 |
+
# frame, i.e. a vertical frame, with the x axis aligned with the projection of the base x axis
|
| 243 |
+
# onto the plane
|
| 244 |
+
root_pose = self.rob_refs.root_state.get(data_type = "q_full",
|
| 245 |
+
robot_idxs=self.robot_index_np_view).reshape(-1, 1) # this should also be
|
| 246 |
+
# rotated into the horizontal frame (however, for now only the z componet is used, so it's ok)
|
| 247 |
+
|
| 248 |
+
root_twist_ref = self.rob_refs.root_state.get(data_type="twist",
|
| 249 |
+
robot_idxs=self.robot_index_np_view).reshape(-1, 1)
|
| 250 |
+
|
| 251 |
+
root_twist_ref_h = root_twist_ref.copy()
|
| 252 |
+
|
| 253 |
+
hor2w_frame(root_twist_ref, q_base, root_twist_ref_h) # horizon works in local world aligned frame
|
| 254 |
+
|
| 255 |
+
if self.base_lin_velxy is not None:
|
| 256 |
+
self.base_lin_velxy.setRef(root_twist_ref_h[0:2, :])
|
| 257 |
+
if self.base_omega is not None:
|
| 258 |
+
self.base_omega.setRef(root_twist_ref_h[3:, :])
|
| 259 |
+
if self.base_lin_velz is not None:
|
| 260 |
+
self.base_lin_velz.setRef(root_twist_ref_h[2:3, :])
|
| 261 |
+
if self.base_height is not None:
|
| 262 |
+
self.base_height.setRef(root_pose)
|
| 263 |
+
else:
|
| 264 |
+
root_pose = self.rob_refs.root_state.get(data_type = "q_full",
|
| 265 |
+
robot_idxs=self.robot_index_np_view).reshape(-1, 1)
|
| 266 |
+
root_twist_ref = self.rob_refs.root_state.get(data_type="twist",
|
| 267 |
+
robot_idxs=self.robot_index_np_view).reshape(-1, 1)
|
| 268 |
+
|
| 269 |
+
if self.base_lin_velxy is not None:
|
| 270 |
+
self.base_lin_velxy.setRef(root_twist_ref[0:2, :])
|
| 271 |
+
if self.base_omega is not None:
|
| 272 |
+
self.base_omega.setRef(root_twist_ref[3:, :])
|
| 273 |
+
if self.base_lin_velz is not None:
|
| 274 |
+
self.base_lin_velz.setRef(root_twist_ref[2:3, :])
|
| 275 |
+
if self.base_height is not None:
|
| 276 |
+
self.base_height.setRef(root_pose)
|
| 277 |
+
|
| 278 |
+
# def _set_force_feedback(self,
|
| 279 |
+
# force_norm: np.ndarray = None):
|
| 280 |
+
|
| 281 |
+
# is_contact=force_norm>1.0
|
| 282 |
+
|
| 283 |
+
# for i in range(len(is_contact)):
|
| 284 |
+
# timeline_name = self._timeline_names[i]
|
| 285 |
+
# self.gait_manager.set_force_feedback(timeline_name=timeline_name,
|
| 286 |
+
# force_norm=force_norm[i])
|
| 287 |
+
|
| 288 |
+
# if not is_contact[i]:
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
def set_default_refs(self,
|
| 292 |
+
p_ref: np.ndarray,
|
| 293 |
+
q_ref: np.ndarray):
|
| 294 |
+
|
| 295 |
+
self._p_ref_default[:, :]=p_ref
|
| 296 |
+
self._q_ref_default[:, :]=q_ref
|
| 297 |
+
|
| 298 |
+
def set_alpha(self, alpha:float):
|
| 299 |
+
# set provided value
|
| 300 |
+
alpha_shared=self.alpha.get_numpy_mirror()
|
| 301 |
+
alpha_shared[self.robot_index_np_view, :] = alpha
|
| 302 |
+
self.alpha.synch_retry(row_index=self.robot_index, col_index=0,
|
| 303 |
+
row_index_view=self.robot_index_view,
|
| 304 |
+
n_rows=1, n_cols=self.alpha.n_cols,
|
| 305 |
+
read=False)
|
| 306 |
+
|
| 307 |
+
def get_alpha(self):
|
| 308 |
+
self.alpha.synch_retry(row_index=self.robot_index, col_index=0,
|
| 309 |
+
row_index_view=self.robot_index_view,
|
| 310 |
+
n_rows=1, n_cols=self.alpha.n_cols,
|
| 311 |
+
read=True)
|
| 312 |
+
alpha=self.alpha.get_numpy_mirror()[self.robot_index_np_view, :].item()
|
| 313 |
+
return alpha
|
| 314 |
+
|
| 315 |
+
def set_bound_relax(self, bound_relax:float):
|
| 316 |
+
# set provided value
|
| 317 |
+
bound_rel_shared=self.bound_rel.get_numpy_mirror()
|
| 318 |
+
bound_rel_shared[self.robot_index_np_view, :] = bound_relax
|
| 319 |
+
self.bound_rel.synch_retry(row_index=self.robot_index, col_index=0, n_rows=1,
|
| 320 |
+
row_index_view=self.robot_index_view,
|
| 321 |
+
n_cols=self.alpha.n_cols,
|
| 322 |
+
read=False)
|
| 323 |
+
|
| 324 |
+
def reset(self):
|
| 325 |
+
|
| 326 |
+
if self.is_running():
|
| 327 |
+
|
| 328 |
+
# resets shared mem
|
| 329 |
+
contact_flags_current = self.contact_flags.get_numpy_mirror()
|
| 330 |
+
phase_id_current = self.phase_id.get_numpy_mirror()
|
| 331 |
+
contact_flags_current[self.robot_index_np_view, :] = np.full((1, self.n_contacts()), dtype=np.bool_, fill_value=True)
|
| 332 |
+
phase_id_current[self.robot_index_np_view, :] = -1 # defaults to custom phase id
|
| 333 |
+
|
| 334 |
+
contact_pos_current=self.rob_refs.contact_pos.get_numpy_mirror()
|
| 335 |
+
contact_pos_current[self.robot_index_np_view, :] = 0.0
|
| 336 |
+
|
| 337 |
+
flight_info_current=self.flight_info.get_numpy_mirror()
|
| 338 |
+
flight_info_current[self.robot_index_np_view, :] = 0.0
|
| 339 |
+
|
| 340 |
+
alpha=self.alpha.get_numpy_mirror()
|
| 341 |
+
alpha[self.robot_index_np_view, :] = 0.0
|
| 342 |
+
|
| 343 |
+
self.rob_refs.root_state.set(data_type="p", data=self._p_ref_default, robot_idxs=self.robot_index_np_view)
|
| 344 |
+
self.rob_refs.root_state.set(data_type="q", data=self._q_ref_default, robot_idxs=self.robot_index_np_view)
|
| 345 |
+
self.rob_refs.root_state.set(data_type="twist", data=np.zeros((1, 6)), robot_idxs=self.robot_index_np_view)
|
| 346 |
+
|
| 347 |
+
self.contact_flags.synch_retry(row_index=self.robot_index, col_index=0,
|
| 348 |
+
row_index_view=self.robot_index_view,
|
| 349 |
+
n_rows=1, n_cols=self.contact_flags.n_cols,
|
| 350 |
+
read=False)
|
| 351 |
+
self.phase_id.synch_retry(row_index=self.robot_index, col_index=0,
|
| 352 |
+
row_index_view=self.robot_index_view,
|
| 353 |
+
n_rows=1, n_cols=self.phase_id.n_cols,
|
| 354 |
+
read=False)
|
| 355 |
+
self.rob_refs.root_state.synch_retry(row_index=self.robot_index, col_index=0,
|
| 356 |
+
row_index_view=self.robot_index_view,
|
| 357 |
+
n_rows=1, n_cols=self.rob_refs.root_state.n_cols,
|
| 358 |
+
read=False)
|
| 359 |
+
|
| 360 |
+
self.rob_refs.contact_pos.synch_retry(row_index=self.robot_index, col_index=0,
|
| 361 |
+
row_index_view=self.robot_index_view,
|
| 362 |
+
n_rows=1, n_cols=self.rob_refs.contact_pos.n_cols,
|
| 363 |
+
read=False)
|
| 364 |
+
|
| 365 |
+
self.flight_info.synch_retry(row_index=self.robot_index,
|
| 366 |
+
col_index=0,
|
| 367 |
+
row_index_view=self.robot_index_view,
|
| 368 |
+
n_rows=1, n_cols=self.flight_info.n_cols,
|
| 369 |
+
read=False)
|
| 370 |
+
|
| 371 |
+
# should also empty the timeline for stepping phases
|
| 372 |
+
self._step_idx = 0
|
| 373 |
+
|
| 374 |
+
else:
|
| 375 |
+
exception = f"Cannot call reset() since run() was not called!"
|
| 376 |
+
Journal.log(self.__class__.__name__,
|
| 377 |
+
"reset",
|
| 378 |
+
exception,
|
| 379 |
+
LogType.EXCEP,
|
| 380 |
+
throw_when_excep = True)
|
| 381 |
+
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/utils/__init__.py
ADDED
|
File without changes
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/horizon_based/utils/math_utils.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import numpy as np
|
| 3 |
+
|
| 4 |
+
def w2hor_frame(t_w: np.ndarray,
|
| 5 |
+
q_b: np.ndarray,
|
| 6 |
+
t_out: np.ndarray):
|
| 7 |
+
"""
|
| 8 |
+
Transforms a twist vector expressed in WORLD frame to
|
| 9 |
+
an "horizontal" frame (z aligned as world, x aligned as the projection
|
| 10 |
+
of the x-axis of the base frame described by q_b). This is useful for specifying locomotion
|
| 11 |
+
references in a "game"-like fashion.
|
| 12 |
+
t_out will hold the result
|
| 13 |
+
"""
|
| 14 |
+
# q_b = q_b / q_b.norm(dim=1, keepdim=True)
|
| 15 |
+
q_w, q_i, q_j, q_k = q_b[3, :], q_b[0, :], q_b[1, :], q_b[2, :]
|
| 16 |
+
|
| 17 |
+
R_11 = 1 - 2 * (q_j ** 2 + q_k ** 2)
|
| 18 |
+
R_21 = 2 * (q_i * q_j + q_k * q_w)
|
| 19 |
+
|
| 20 |
+
norm = np.sqrt(R_11 ** 2 + R_21 ** 2)
|
| 21 |
+
x_proj_x = R_11 / norm
|
| 22 |
+
x_proj_y = R_21 / norm
|
| 23 |
+
|
| 24 |
+
y_proj_x = -x_proj_y
|
| 25 |
+
y_proj_y = x_proj_x
|
| 26 |
+
|
| 27 |
+
t_out[0, :] = t_w[0, :] * x_proj_x + t_w[1, :] * x_proj_y
|
| 28 |
+
t_out[1, :] = t_w[0, :] * y_proj_x + t_w[1, :] * y_proj_y
|
| 29 |
+
t_out[2, :] = t_w[2, :] # z-component remains the same
|
| 30 |
+
t_out[3, :] = t_w[3, :] * x_proj_x + t_w[4, :] * x_proj_y
|
| 31 |
+
t_out[4, :] = t_w[3, :] * y_proj_x + t_w[4, :] * y_proj_y
|
| 32 |
+
t_out[5, :] = t_w[5, :] # z-component remains the same
|
| 33 |
+
|
| 34 |
+
def hor2w_frame(t_h: np.ndarray,
|
| 35 |
+
q_b: np.ndarray,
|
| 36 |
+
t_out: np.ndarray):
|
| 37 |
+
"""
|
| 38 |
+
Transforms a velocity vector expressed in "horizontal" frame to WORLD
|
| 39 |
+
v_out will hold the result
|
| 40 |
+
"""
|
| 41 |
+
|
| 42 |
+
# Extract quaternion components
|
| 43 |
+
q_w, q_i, q_j, q_k = q_b[3, :], q_b[0, :], q_b[1, :], q_b[2, :]
|
| 44 |
+
|
| 45 |
+
# Compute rotation matrix elements
|
| 46 |
+
R_11 = 1 - 2 * (q_j ** 2 + q_k ** 2)
|
| 47 |
+
R_21 = 2 * (q_i * q_j + q_k * q_w)
|
| 48 |
+
|
| 49 |
+
# Normalize to get projection components
|
| 50 |
+
norm = np.sqrt(R_11 ** 2 + R_21 ** 2)
|
| 51 |
+
x_proj_x = R_11 / norm
|
| 52 |
+
x_proj_y = R_21 / norm
|
| 53 |
+
|
| 54 |
+
# Orthogonal vector components
|
| 55 |
+
y_proj_x = -x_proj_y
|
| 56 |
+
y_proj_y = x_proj_x
|
| 57 |
+
|
| 58 |
+
# Transform velocity vector components from horizontal to world frame
|
| 59 |
+
t_out[0, :] = t_h[0, :] * x_proj_x + t_h[1, :] * y_proj_x
|
| 60 |
+
t_out[1, :] = t_h[0, :] * x_proj_y + t_h[1, :] * y_proj_y
|
| 61 |
+
t_out[2, :] = t_h[2, :] # z-component remains the same
|
| 62 |
+
t_out[3, :] = t_h[3, :] * x_proj_x + t_h[4, :] * y_proj_x
|
| 63 |
+
t_out[4, :] = t_h[3, :] * x_proj_y + t_h[4, :] * y_proj_y
|
| 64 |
+
t_out[5, :] = t_h[5, :] # z-component remains the same
|
| 65 |
+
|
| 66 |
+
def base2world_frame(t_b: np.ndarray,
|
| 67 |
+
q_b: np.ndarray,
|
| 68 |
+
t_out: np.ndarray):
|
| 69 |
+
"""
|
| 70 |
+
Transforms a velocity vector expressed in the base frame to
|
| 71 |
+
the WORLD frame using the given quaternion that describes the orientation
|
| 72 |
+
of the base with respect to the world frame. The result is written in v_out.
|
| 73 |
+
"""
|
| 74 |
+
# q_b = q_b / q_b.norm(dim=1, keepdim=True)
|
| 75 |
+
q_w, q_i, q_j, q_k = q_b[3, :], q_b[0, :], q_b[1, :], q_b[2, :]
|
| 76 |
+
|
| 77 |
+
R_00 = 1 - 2 * (q_j ** 2 + q_k ** 2)
|
| 78 |
+
R_01 = 2 * (q_i * q_j - q_k * q_w)
|
| 79 |
+
R_02 = 2 * (q_i * q_k + q_j * q_w)
|
| 80 |
+
|
| 81 |
+
R_10 = 2 * (q_i * q_j + q_k * q_w)
|
| 82 |
+
R_11 = 1 - 2 * (q_i ** 2 + q_k ** 2)
|
| 83 |
+
R_12 = 2 * (q_j * q_k - q_i * q_w)
|
| 84 |
+
|
| 85 |
+
R_20 = 2 * (q_i * q_k - q_j * q_w)
|
| 86 |
+
R_21 = 2 * (q_j * q_k + q_i * q_w)
|
| 87 |
+
R_22 = 1 - 2 * (q_i ** 2 + q_j ** 2)
|
| 88 |
+
|
| 89 |
+
# Transform the velocity to the world frame
|
| 90 |
+
t_out[0, :] = t_b[0, :] * R_00 + t_b[1, :] * R_01 + t_b[2, :] * R_02
|
| 91 |
+
t_out[1, :] = t_b[0, :] * R_10 + t_b[1, :] * R_11 + t_b[2, :] * R_12
|
| 92 |
+
t_out[2, :] = t_b[0, :] * R_20 + t_b[1, :] * R_21 + t_b[2, :] * R_22
|
| 93 |
+
t_out[3, :] = t_b[3, :] * R_00 + t_b[4, :] * R_01 + t_b[5, :] * R_02
|
| 94 |
+
t_out[4, :] = t_b[3, :] * R_10 + t_b[4, :] * R_11 + t_b[5, :] * R_12
|
| 95 |
+
t_out[5, :] = t_b[3, :] * R_20 + t_b[4, :] * R_21 + t_b[5, :] * R_22
|
| 96 |
+
|
| 97 |
+
def world2base_frame(t_w: np.ndarray,
|
| 98 |
+
q_b: np.ndarray,
|
| 99 |
+
t_out: np.ndarray):
|
| 100 |
+
"""
|
| 101 |
+
Transforms a velocity vector expressed in the WORLD frame to
|
| 102 |
+
the base frame using the given quaternion that describes the orientation
|
| 103 |
+
of the base with respect to the world frame. The result is written in v_out.
|
| 104 |
+
"""
|
| 105 |
+
# q_b = q_b / q_b.norm(dim=1, keepdim=True)
|
| 106 |
+
q_w, q_i, q_j, q_k = q_b[3, :], q_b[0, :], q_b[1, :], q_b[2, :]
|
| 107 |
+
|
| 108 |
+
R_00 = 1 - 2 * (q_j ** 2 + q_k ** 2)
|
| 109 |
+
R_01 = 2 * (q_i * q_j - q_k * q_w)
|
| 110 |
+
R_02 = 2 * (q_i * q_k + q_j * q_w)
|
| 111 |
+
|
| 112 |
+
R_10 = 2 * (q_i * q_j + q_k * q_w)
|
| 113 |
+
R_11 = 1 - 2 * (q_i ** 2 + q_k ** 2)
|
| 114 |
+
R_12 = 2 * (q_j * q_k - q_i * q_w)
|
| 115 |
+
|
| 116 |
+
R_20 = 2 * (q_i * q_k - q_j * q_w)
|
| 117 |
+
R_21 = 2 * (q_j * q_k + q_i * q_w)
|
| 118 |
+
R_22 = 1 - 2 * (q_i ** 2 + q_j ** 2)
|
| 119 |
+
|
| 120 |
+
# Transform the velocity to the base frame using the transpose of the rotation matrix
|
| 121 |
+
t_out[0, :] = t_w[0, :] * R_00 + t_w[1, :] * R_10 + t_w[2, :] * R_20
|
| 122 |
+
t_out[1, :] = t_w[0, :] * R_01 + t_w[1, :] * R_11 + t_w[2, :] * R_21
|
| 123 |
+
t_out[2, :] = t_w[0, :] * R_02 + t_w[1, :] * R_12 + t_w[2, :] * R_22
|
| 124 |
+
t_out[3, :] = t_w[3, :] * R_00 + t_w[4, :] * R_10 + t_w[5, :] * R_20
|
| 125 |
+
t_out[4, :] = t_w[3, :] * R_01 + t_w[4, :] * R_11 + t_w[5, :] * R_21
|
| 126 |
+
t_out[5, :] = t_w[3, :] * R_02 + t_w[4, :] * R_12 + t_w[5, :] * R_22
|
| 127 |
+
|
| 128 |
+
if __name__ == "__main__":
|
| 129 |
+
|
| 130 |
+
n_envs = 5000
|
| 131 |
+
t_b = np.random.rand(6, n_envs)
|
| 132 |
+
|
| 133 |
+
q_b = np.random.rand(4, n_envs)
|
| 134 |
+
q_b_norm = q_b / np.linalg.norm(q_b, axis=0, keepdims=True)
|
| 135 |
+
|
| 136 |
+
t_w = np.zeros_like(t_b) # To hold horizontal frame velocities
|
| 137 |
+
t_b_recovered = np.zeros_like(t_b) # To hold recovered world frame velocities
|
| 138 |
+
base2world_frame(t_b, q_b_norm, t_w)
|
| 139 |
+
world2base_frame(t_w, q_b_norm, t_b_recovered)
|
| 140 |
+
assert np.allclose(t_b, t_b_recovered, atol=1e-6), "Test failed: t_w_recovered does not match t_b"
|
| 141 |
+
print("Forward test passed: t_b_recovered matches t_b")
|
| 142 |
+
|
| 143 |
+
t_b2 = np.zeros_like(t_b) # To hold horizontal frame velocities
|
| 144 |
+
t_w_recovered = np.zeros_like(t_b)
|
| 145 |
+
world2base_frame(t_b, q_b_norm, t_b2)
|
| 146 |
+
base2world_frame(t_b2, q_b_norm, t_w_recovered)
|
| 147 |
+
assert np.allclose(t_b, t_w_recovered, atol=1e-6), "Test failed: t_w_recovered does not match t_b"
|
| 148 |
+
print("Backward test passed: t_w_recovered matches t_w")
|
| 149 |
+
|
| 150 |
+
# test transf. world-horizontal frame
|
| 151 |
+
v_h = np.zeros_like(t_b) # To hold horizontal frame velocities
|
| 152 |
+
v_recovered = np.zeros_like(t_b)
|
| 153 |
+
w2hor_frame(t_b, q_b_norm, v_h)
|
| 154 |
+
hor2w_frame(v_h, q_b_norm, v_recovered)
|
| 155 |
+
assert np.allclose(t_b, v_recovered, atol=1e-6), "Test failed: v_recovered does not match t_b"
|
| 156 |
+
print("horizontal forward frame test passed: matches ")
|
| 157 |
+
|
| 158 |
+
t_w = np.zeros_like(t_b) # To hold horizontal frame velocities
|
| 159 |
+
v_h_recovered = np.zeros_like(t_b)
|
| 160 |
+
hor2w_frame(t_b, q_b_norm, t_w)
|
| 161 |
+
w2hor_frame(t_w, q_b_norm, v_h_recovered)
|
| 162 |
+
assert np.allclose(t_b, v_h_recovered, atol=1e-6), "Test failed: v_h_recovered does not match t_b"
|
| 163 |
+
print("horizontal backward frame test passed: matches ")
|
| 164 |
+
|
| 165 |
+
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/other/hybrid_quad_client.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from aug_mpc.controllers.rhc.augmpc_cluster_client import AugMpcClusterClient
|
| 2 |
+
|
| 3 |
+
from aug_mpc.controllers.rhc.horizon_based.hybrid_quad_rhc import HybridQuadRhc
|
| 4 |
+
from aug_mpc.utils.hybrid_quad_xrdf_gen import get_xrdf_cmds_horizon
|
| 5 |
+
from aug_mpc.utils.sys_utils import PathsGetter
|
| 6 |
+
|
| 7 |
+
from typing import List, Dict
|
| 8 |
+
|
| 9 |
+
class HybridQuadrupedClusterClient(AugMpcClusterClient):
|
| 10 |
+
|
| 11 |
+
def _import_aux_libs(self):
|
| 12 |
+
super()._import_aux_libs()
|
| 13 |
+
# Import Horizon and related dependencies as global libs
|
| 14 |
+
from aug_mpc.controllers.rhc.horizon_based.horizon_imports_glob import import_horizon_global
|
| 15 |
+
import_horizon_global()
|
| 16 |
+
|
| 17 |
+
def __init__(self,
|
| 18 |
+
namespace: str,
|
| 19 |
+
urdf_xacro_path: str,
|
| 20 |
+
srdf_xacro_path: str,
|
| 21 |
+
cluster_size: int,
|
| 22 |
+
set_affinity: bool = False,
|
| 23 |
+
use_mp_fork: bool = False,
|
| 24 |
+
isolated_cores_only: bool = False,
|
| 25 |
+
core_ids_override_list: List[int] = None,
|
| 26 |
+
verbose: bool = False,
|
| 27 |
+
debug: bool = False,
|
| 28 |
+
open_loop: bool = True,
|
| 29 |
+
base_dump_dir: str = "/tmp",
|
| 30 |
+
timeout_ms: int = 60000,
|
| 31 |
+
codegen_override: str = None,
|
| 32 |
+
custom_opts: Dict = {}):
|
| 33 |
+
|
| 34 |
+
self._open_loop = open_loop
|
| 35 |
+
|
| 36 |
+
self._paths = PathsGetter()
|
| 37 |
+
|
| 38 |
+
self._codegen_dir_name = namespace
|
| 39 |
+
|
| 40 |
+
self._timeout_ms = timeout_ms
|
| 41 |
+
|
| 42 |
+
super().__init__(namespace = namespace,
|
| 43 |
+
urdf_xacro_path = urdf_xacro_path,
|
| 44 |
+
srdf_xacro_path = srdf_xacro_path,
|
| 45 |
+
cluster_size=cluster_size,
|
| 46 |
+
set_affinity = set_affinity,
|
| 47 |
+
use_mp_fork = use_mp_fork,
|
| 48 |
+
isolated_cores_only = isolated_cores_only,
|
| 49 |
+
core_ids_override_list = core_ids_override_list,
|
| 50 |
+
verbose = verbose,
|
| 51 |
+
debug = debug,
|
| 52 |
+
base_dump_dir=base_dump_dir,
|
| 53 |
+
codegen_override=codegen_override,
|
| 54 |
+
custom_opts=custom_opts)
|
| 55 |
+
|
| 56 |
+
self._n_nodes = 31 if not ("n_nodes" in self._custom_opts) else self._custom_opts["n_nodes"]
|
| 57 |
+
self._dt = 0.05 if not ("cluster_dt" in self._custom_opts) else self._custom_opts["cluster_dt"]
|
| 58 |
+
|
| 59 |
+
def _xrdf_cmds(self):
|
| 60 |
+
parts = self._urdf_path.split('/')
|
| 61 |
+
urdf_descr_root_path = '/'.join(parts[:-2])
|
| 62 |
+
cmds = get_xrdf_cmds_horizon(urdf_descr_root_path=urdf_descr_root_path)
|
| 63 |
+
return cmds
|
| 64 |
+
|
| 65 |
+
def _process_codegen_dir(self,idx:int):
|
| 66 |
+
|
| 67 |
+
codegen_dir = self.codegen_dir() + f"/{self._codegen_dir_name}Rhc{idx}"
|
| 68 |
+
codegen_dir_ovveride = self.codegen_dir_override()
|
| 69 |
+
if not (codegen_dir_ovveride=="" or \
|
| 70 |
+
codegen_dir_ovveride=="none" or \
|
| 71 |
+
codegen_dir_ovveride=="None" or \
|
| 72 |
+
(codegen_dir_ovveride is None)): # if overrde was provided
|
| 73 |
+
codegen_dir = f"{codegen_dir_ovveride}{idx}"# override
|
| 74 |
+
|
| 75 |
+
return codegen_dir
|
| 76 |
+
|
| 77 |
+
def _generate_controller(self,
|
| 78 |
+
idx: int):
|
| 79 |
+
|
| 80 |
+
codegen_dir=self._process_codegen_dir(idx=idx)
|
| 81 |
+
|
| 82 |
+
controller = HybridQuadRhc(
|
| 83 |
+
urdf_path=self._urdf_path,
|
| 84 |
+
srdf_path=self._srdf_path,
|
| 85 |
+
config_path = self._paths.CONFIGPATH,
|
| 86 |
+
robot_name=self._namespace,
|
| 87 |
+
codegen_dir=codegen_dir,
|
| 88 |
+
n_nodes=self._n_nodes,
|
| 89 |
+
dt=self._dt,
|
| 90 |
+
max_solver_iter = 1, # rti
|
| 91 |
+
open_loop = self._open_loop,
|
| 92 |
+
verbose = self._verbose,
|
| 93 |
+
debug = self._debug)
|
| 94 |
+
|
| 95 |
+
return controller
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/rhc.py
ADDED
|
@@ -0,0 +1,1226 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (C) 2023 Andrea Patrizi (AndrePatri, andreapatrizi1b6e6@gmail.com)
|
| 2 |
+
#
|
| 3 |
+
# This file is part of MPCHive and distributed under the General Public License version 2 license.
|
| 4 |
+
#
|
| 5 |
+
# MPCHive is free software: you can redistribute it and/or modify
|
| 6 |
+
# it under the terms of the GNU General Public License as published by
|
| 7 |
+
# the Free Software Foundation, either version 2 of the License, or
|
| 8 |
+
# (at your option) any later version.
|
| 9 |
+
#
|
| 10 |
+
# MPCHive is distributed in the hope that it will be useful,
|
| 11 |
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
+
# GNU General Public License for more details.
|
| 14 |
+
#
|
| 15 |
+
# You should have received a copy of the GNU General Public License
|
| 16 |
+
# along with MPCHive. If not, see <http://www.gnu.org/licenses/>.
|
| 17 |
+
#
|
| 18 |
+
from abc import ABC, abstractmethod
|
| 19 |
+
# from perf_sleep.pyperfsleep import PerfSleep
|
| 20 |
+
# from mpc_hive.utilities.cpu_utils.core_utils import get_memory_usage
|
| 21 |
+
|
| 22 |
+
import time
|
| 23 |
+
|
| 24 |
+
import numpy as np
|
| 25 |
+
|
| 26 |
+
from mpc_hive.utilities.shared_data.rhc_data import RobotState
|
| 27 |
+
from mpc_hive.utilities.shared_data.rhc_data import RhcCmds, RhcPred, RhcPredDelta
|
| 28 |
+
from mpc_hive.utilities.shared_data.rhc_data import RhcStatus
|
| 29 |
+
from mpc_hive.utilities.shared_data.rhc_data import RhcInternal
|
| 30 |
+
from mpc_hive.utilities.shared_data.cluster_profiling import RhcProfiling
|
| 31 |
+
from mpc_hive.utilities.remote_triggering import RemoteTriggererClnt
|
| 32 |
+
|
| 33 |
+
from mpc_hive.utilities.homing import RobotHomer
|
| 34 |
+
|
| 35 |
+
from mpc_hive.utilities.math_utils import world2base_frame
|
| 36 |
+
|
| 37 |
+
from EigenIPC.PyEigenIPC import VLevel
|
| 38 |
+
from EigenIPC.PyEigenIPC import Journal, LogType
|
| 39 |
+
from EigenIPC.PyEigenIPCExt.wrappers.shared_data_view import SharedTWrapper
|
| 40 |
+
from EigenIPC.PyEigenIPC import dtype
|
| 41 |
+
|
| 42 |
+
from typing import List
|
| 43 |
+
# from typing import TypeVar, Union
|
| 44 |
+
|
| 45 |
+
import signal
|
| 46 |
+
import os
|
| 47 |
+
import inspect
|
| 48 |
+
|
| 49 |
+
class RHController(ABC):
|
| 50 |
+
|
| 51 |
+
def __init__(self,
|
| 52 |
+
srdf_path: str,
|
| 53 |
+
n_nodes: int,
|
| 54 |
+
dt: float,
|
| 55 |
+
namespace: str, # shared mem namespace
|
| 56 |
+
dtype = np.float32,
|
| 57 |
+
verbose = False,
|
| 58 |
+
debug = False,
|
| 59 |
+
timeout_ms: int = 60000,
|
| 60 |
+
allow_less_jnts: bool = True):
|
| 61 |
+
|
| 62 |
+
signal.signal(signal.SIGINT, self._handle_sigint)
|
| 63 |
+
|
| 64 |
+
self._allow_less_jnts = allow_less_jnts # whether to allow less joints in rhc controller than the ones on the robot
|
| 65 |
+
# (e.g. some joints might not be desirable for control purposes)
|
| 66 |
+
|
| 67 |
+
self.namespace = namespace
|
| 68 |
+
self._dtype = dtype
|
| 69 |
+
self._verbose = verbose
|
| 70 |
+
self._debug = debug
|
| 71 |
+
|
| 72 |
+
# if not self._debug:
|
| 73 |
+
np.seterr(over='ignore') # ignoring overflows
|
| 74 |
+
|
| 75 |
+
self._n_nodes = n_nodes
|
| 76 |
+
self._dt = dt
|
| 77 |
+
self._n_intervals = self._n_nodes - 1
|
| 78 |
+
self._t_horizon = self._n_intervals * dt
|
| 79 |
+
self._set_rhc_pred_idx() # prection is by default written on last node
|
| 80 |
+
self._set_rhc_cmds_idx() # default to idx 2 (i.e. cmds to get to third node)
|
| 81 |
+
self.controller_index = None # will be assigned upon registration to a cluster
|
| 82 |
+
self.controller_index_np = None
|
| 83 |
+
self._robot_mass=1.0
|
| 84 |
+
|
| 85 |
+
self.srdf_path = srdf_path # using for parsing robot homing
|
| 86 |
+
|
| 87 |
+
self._registered = False
|
| 88 |
+
self._closed = False
|
| 89 |
+
|
| 90 |
+
self._allow_triggering_when_failed = True
|
| 91 |
+
|
| 92 |
+
self._profiling_data_dict = {}
|
| 93 |
+
self._profiling_data_dict["full_solve_dt"] = np.nan
|
| 94 |
+
self._profiling_data_dict["rti_solve_dt"] = np.nan
|
| 95 |
+
self._profiling_data_dict["problem_update_dt"] = np.nan
|
| 96 |
+
self._profiling_data_dict["phases_shift_dt"] = np.nan
|
| 97 |
+
self._profiling_data_dict["task_ref_update"] = np.nan
|
| 98 |
+
|
| 99 |
+
self.n_dofs = None
|
| 100 |
+
self.n_contacts = None
|
| 101 |
+
|
| 102 |
+
# shared mem
|
| 103 |
+
self.robot_state = None
|
| 104 |
+
self.rhc_status = None
|
| 105 |
+
self.rhc_internal = None
|
| 106 |
+
self.cluster_stats = None
|
| 107 |
+
self.robot_cmds = None
|
| 108 |
+
self.robot_pred = None
|
| 109 |
+
self.rhc_pred_delta = None
|
| 110 |
+
self.rhc_refs = None
|
| 111 |
+
self._remote_triggerer = None
|
| 112 |
+
self._remote_triggerer_timeout = timeout_ms # [ms]
|
| 113 |
+
|
| 114 |
+
# remote termination
|
| 115 |
+
self._remote_term = None
|
| 116 |
+
self._term_req_received = False
|
| 117 |
+
|
| 118 |
+
# jnt names
|
| 119 |
+
self._env_side_jnt_names = []
|
| 120 |
+
self._controller_side_jnt_names = []
|
| 121 |
+
self._got_jnt_names_from_controllers = False
|
| 122 |
+
|
| 123 |
+
# data maps
|
| 124 |
+
self._to_controller = []
|
| 125 |
+
self._quat_remap = [0, 1, 2, 3] # defaults to no remap (to be overridden)
|
| 126 |
+
|
| 127 |
+
self._got_contact_names = False
|
| 128 |
+
|
| 129 |
+
self._received_trigger = False # used for proper termination
|
| 130 |
+
|
| 131 |
+
self._n_resets = 0
|
| 132 |
+
self._n_fails = 0
|
| 133 |
+
self._fail_idx_thresh = 5e3
|
| 134 |
+
self._contact_f_thresh = 1e5
|
| 135 |
+
|
| 136 |
+
self._failed = False
|
| 137 |
+
|
| 138 |
+
self._start_time = time.perf_counter() # used for profiling when in debug mode
|
| 139 |
+
|
| 140 |
+
self._homer = None # robot homing manager
|
| 141 |
+
self._homer_env = None # used for setting homing to jnts not contained in rhc prb
|
| 142 |
+
|
| 143 |
+
self._class_name_base = f"{self.__class__.__name__}"
|
| 144 |
+
|
| 145 |
+
self._contact_force_base_loc_aux=np.zeros((1,3),dtype=self._dtype)
|
| 146 |
+
self._norm_grav_vector_w=np.zeros((1,3),dtype=self._dtype)
|
| 147 |
+
self._norm_grav_vector_w[:, 2]=-1.0
|
| 148 |
+
self._norm_grav_vector_base_loc=np.zeros((1,3),dtype=self._dtype)
|
| 149 |
+
|
| 150 |
+
self._init() # initialize controller
|
| 151 |
+
|
| 152 |
+
if not hasattr(self, '_rhc_fpaths'):
|
| 153 |
+
self._rhc_fpaths = []
|
| 154 |
+
self._rhc_fpaths.append(os.path.abspath(__file__))
|
| 155 |
+
|
| 156 |
+
def __init_subclass__(cls, **kwargs):
|
| 157 |
+
super().__init_subclass__(**kwargs)
|
| 158 |
+
# Get the file path of the class being initialized and append it to the list
|
| 159 |
+
if not hasattr(cls, '_rhc_fpaths'):
|
| 160 |
+
cls._rhc_fpaths = []
|
| 161 |
+
child_class_file_path = os.path.abspath(inspect.getfile(cls))
|
| 162 |
+
cls._rhc_fpaths.append(child_class_file_path)
|
| 163 |
+
|
| 164 |
+
def this_paths(self):
|
| 165 |
+
return self._rhc_fpaths
|
| 166 |
+
|
| 167 |
+
def __del__(self):
|
| 168 |
+
self._close()
|
| 169 |
+
|
| 170 |
+
def _handle_sigint(self, signum, frame):
|
| 171 |
+
Journal.log(self._class_name_base,
|
| 172 |
+
"_handle_sigint",
|
| 173 |
+
"SIGINT received",
|
| 174 |
+
LogType.WARN)
|
| 175 |
+
self._term_req_received = True
|
| 176 |
+
|
| 177 |
+
def _set_rhc_pred_idx(self):
|
| 178 |
+
# default to last node
|
| 179 |
+
self._pred_node_idx=self._n_nodes-1
|
| 180 |
+
|
| 181 |
+
def _set_rhc_cmds_idx(self):
|
| 182 |
+
# use index 2 by default to compensate for
|
| 183 |
+
# the inevitable action delay
|
| 184 |
+
# (get_state, trigger sol -> +dt -> apply sol )
|
| 185 |
+
# if we apply action from second node (idenx 1)
|
| 186 |
+
# that action will already be one dt old. We assume we were already
|
| 187 |
+
# applying the right action to get to the state of node idx 1 and get the
|
| 188 |
+
# cmds for reaching the state at idx 1
|
| 189 |
+
self._rhc_cmds_node_idx=2
|
| 190 |
+
|
| 191 |
+
def _close(self):
|
| 192 |
+
if not self._closed:
|
| 193 |
+
self._unregister_from_cluster()
|
| 194 |
+
if self.robot_cmds is not None:
|
| 195 |
+
self.robot_cmds.close()
|
| 196 |
+
if self.robot_pred is not None:
|
| 197 |
+
self.robot_pred.close()
|
| 198 |
+
if self.rhc_pred_delta is not None:
|
| 199 |
+
self.rhc_pred_delta.close()
|
| 200 |
+
if self.robot_state is not None:
|
| 201 |
+
self.robot_state.close()
|
| 202 |
+
if self.rhc_status is not None:
|
| 203 |
+
self.rhc_status.close()
|
| 204 |
+
if self.rhc_internal is not None:
|
| 205 |
+
self.rhc_internal.close()
|
| 206 |
+
if self.cluster_stats is not None:
|
| 207 |
+
self.cluster_stats.close()
|
| 208 |
+
if self._remote_triggerer is not None:
|
| 209 |
+
self._remote_triggerer.close()
|
| 210 |
+
if self._remote_term is not None:
|
| 211 |
+
self._remote_term.close()
|
| 212 |
+
self._closed = True
|
| 213 |
+
|
| 214 |
+
def close(self):
|
| 215 |
+
self._close()
|
| 216 |
+
|
| 217 |
+
def get_file_paths(self):
|
| 218 |
+
# can be overriden by child
|
| 219 |
+
base_paths = []
|
| 220 |
+
base_paths.append(self._this_path)
|
| 221 |
+
return base_paths
|
| 222 |
+
|
| 223 |
+
def init_rhc_task_cmds(self):
|
| 224 |
+
|
| 225 |
+
self.rhc_refs = self._init_rhc_task_cmds()
|
| 226 |
+
self.rhc_refs.reset()
|
| 227 |
+
|
| 228 |
+
def _init_states(self):
|
| 229 |
+
|
| 230 |
+
quat_remap = self._get_quat_remap()
|
| 231 |
+
self.robot_state = RobotState(namespace=self.namespace,
|
| 232 |
+
is_server=False,
|
| 233 |
+
q_remapping=quat_remap, # remapping from environment to controller
|
| 234 |
+
with_gpu_mirror=False,
|
| 235 |
+
with_torch_view=False,
|
| 236 |
+
safe=False,
|
| 237 |
+
verbose=self._verbose,
|
| 238 |
+
vlevel=VLevel.V2,
|
| 239 |
+
optimize_mem=True,
|
| 240 |
+
n_robots=1, # we just need the row corresponding to this controller
|
| 241 |
+
n_jnts=None, # got from server
|
| 242 |
+
n_contacts=None # got from server
|
| 243 |
+
)
|
| 244 |
+
self.robot_state.run()
|
| 245 |
+
self.robot_cmds = RhcCmds(namespace=self.namespace,
|
| 246 |
+
is_server=False,
|
| 247 |
+
q_remapping=quat_remap, # remapping from environment to controller
|
| 248 |
+
with_gpu_mirror=False,
|
| 249 |
+
with_torch_view=False,
|
| 250 |
+
safe=False,
|
| 251 |
+
verbose=self._verbose,
|
| 252 |
+
vlevel=VLevel.V2,
|
| 253 |
+
optimize_mem=True,
|
| 254 |
+
n_robots=1, # we just need the row corresponding to this controller
|
| 255 |
+
n_jnts=None, # got from server
|
| 256 |
+
n_contacts=None # got from server
|
| 257 |
+
)
|
| 258 |
+
self.robot_cmds.run()
|
| 259 |
+
self.robot_pred = RhcPred(namespace=self.namespace,
|
| 260 |
+
is_server=False,
|
| 261 |
+
q_remapping=quat_remap, # remapping from environment to controller
|
| 262 |
+
with_gpu_mirror=False,
|
| 263 |
+
with_torch_view=False,
|
| 264 |
+
safe=False,
|
| 265 |
+
verbose=self._verbose,
|
| 266 |
+
vlevel=VLevel.V2,
|
| 267 |
+
optimize_mem=True,
|
| 268 |
+
n_robots=1, # we just need the row corresponding to this controller
|
| 269 |
+
n_jnts=None, # got from server
|
| 270 |
+
n_contacts=None # got from server
|
| 271 |
+
)
|
| 272 |
+
self.robot_pred.run()
|
| 273 |
+
self.rhc_pred_delta = RhcPredDelta(namespace=self.namespace,
|
| 274 |
+
is_server=False,
|
| 275 |
+
q_remapping=quat_remap, # remapping from environment to controller
|
| 276 |
+
with_gpu_mirror=False,
|
| 277 |
+
with_torch_view=False,
|
| 278 |
+
safe=False,
|
| 279 |
+
verbose=self._verbose,
|
| 280 |
+
vlevel=VLevel.V2,
|
| 281 |
+
optimize_mem=True,
|
| 282 |
+
n_robots=1, # we just need the row corresponding to this controller
|
| 283 |
+
n_jnts=None, # got from server
|
| 284 |
+
n_contacts=None # got from server
|
| 285 |
+
)
|
| 286 |
+
self.rhc_pred_delta.run()
|
| 287 |
+
|
| 288 |
+
def _rhc(self):
|
| 289 |
+
if self._debug:
|
| 290 |
+
self._rhc_db()
|
| 291 |
+
else:
|
| 292 |
+
self._rhc_min()
|
| 293 |
+
|
| 294 |
+
def _rhc_db(self):
|
| 295 |
+
# rhc with debug data
|
| 296 |
+
self._start_time = time.perf_counter()
|
| 297 |
+
|
| 298 |
+
self.robot_state.synch_from_shared_mem(robot_idx=self.controller_index, robot_idx_view=self.controller_index_np) # updates robot state with
|
| 299 |
+
# latest data on shared mem
|
| 300 |
+
|
| 301 |
+
self._compute_pred_delta()
|
| 302 |
+
|
| 303 |
+
if not self.failed():
|
| 304 |
+
# we can solve only if not in failure state
|
| 305 |
+
self._failed = not self._solve() # solve actual TO
|
| 306 |
+
if (self._failed):
|
| 307 |
+
# perform failure procedure
|
| 308 |
+
self._on_failure()
|
| 309 |
+
else:
|
| 310 |
+
if not self._allow_triggering_when_failed:
|
| 311 |
+
Journal.log(self._class_name_base,
|
| 312 |
+
"solve",
|
| 313 |
+
"Received solution req, but controller is in failure state. " + \
|
| 314 |
+
" You should have reset() the controller!",
|
| 315 |
+
LogType.EXCEP,
|
| 316 |
+
throw_when_excep = True)
|
| 317 |
+
else:
|
| 318 |
+
if self._verbose:
|
| 319 |
+
Journal.log(self._class_name_base,
|
| 320 |
+
"solve",
|
| 321 |
+
"Received solution req, but controller is in failure state. No solution will be performed. " + \
|
| 322 |
+
" Use the reset() method to continue solving!",
|
| 323 |
+
LogType.WARN)
|
| 324 |
+
|
| 325 |
+
self._write_cmds_from_sol() # we update update the views of the cmds
|
| 326 |
+
# from the latest solution
|
| 327 |
+
|
| 328 |
+
# in debug, rhc internal state is streamed over
|
| 329 |
+
# shared mem.
|
| 330 |
+
self._update_rhc_internal()
|
| 331 |
+
self._profiling_data_dict["full_solve_dt"] = time.perf_counter() - self._start_time
|
| 332 |
+
self._update_profiling_data() # updates all profiling data
|
| 333 |
+
if self._verbose:
|
| 334 |
+
Journal.log(self._class_name_base,
|
| 335 |
+
"solve",
|
| 336 |
+
f"RHC full solve loop execution time -> " + str(self._profiling_data_dict["full_solve_dt"]),
|
| 337 |
+
LogType.INFO,
|
| 338 |
+
throw_when_excep = True)
|
| 339 |
+
|
| 340 |
+
def _rhc_min(self):
|
| 341 |
+
|
| 342 |
+
self.robot_state.synch_from_shared_mem(robot_idx=self.controller_index, robot_idx_view=self.controller_index_np) # updates robot state with
|
| 343 |
+
# latest data on shared mem
|
| 344 |
+
|
| 345 |
+
self._compute_pred_delta()
|
| 346 |
+
|
| 347 |
+
if not self.failed():
|
| 348 |
+
# we can solve only if not in failure state
|
| 349 |
+
self._failed = not self._solve() # solve actual TO
|
| 350 |
+
if (self._failed):
|
| 351 |
+
# perform failure procedure
|
| 352 |
+
self._on_failure()
|
| 353 |
+
else:
|
| 354 |
+
if not self._allow_triggering_when_failed:
|
| 355 |
+
Journal.log(self._class_name_base,
|
| 356 |
+
"solve",
|
| 357 |
+
"Received solution req, but controller is in failure state. " + \
|
| 358 |
+
" You should have reset() the controller!",
|
| 359 |
+
LogType.EXCEP,
|
| 360 |
+
throw_when_excep = True)
|
| 361 |
+
else:
|
| 362 |
+
if self._verbose:
|
| 363 |
+
Journal.log(self._class_name_base,
|
| 364 |
+
"solve",
|
| 365 |
+
"Received solution req, but controller is in failure state. No solution will be performed. " + \
|
| 366 |
+
" Use the reset() method to continue solving!",
|
| 367 |
+
LogType.WARN)
|
| 368 |
+
|
| 369 |
+
self._write_cmds_from_sol() # we update the views of the cmds
|
| 370 |
+
# from the latest solution even if failed
|
| 371 |
+
|
| 372 |
+
def solve(self):
|
| 373 |
+
|
| 374 |
+
# run the solution loop and wait for trigger signals
|
| 375 |
+
# using cond. variables (efficient)
|
| 376 |
+
while not self._term_req_received:
|
| 377 |
+
# we are always listening for a trigger signal
|
| 378 |
+
if not self._remote_triggerer.wait(self._remote_triggerer_timeout):
|
| 379 |
+
Journal.log(self._class_name_base,
|
| 380 |
+
"solve",
|
| 381 |
+
"Didn't receive any remote trigger req within timeout!",
|
| 382 |
+
LogType.EXCEP,
|
| 383 |
+
throw_when_excep = False)
|
| 384 |
+
break
|
| 385 |
+
self._received_trigger = True
|
| 386 |
+
# signal received -> we process incoming requests
|
| 387 |
+
# perform reset, if required
|
| 388 |
+
if self.rhc_status.resets.read_retry(row_index=self.controller_index,
|
| 389 |
+
col_index=0,
|
| 390 |
+
row_index_view=0)[0]:
|
| 391 |
+
self.reset() # rhc is reset
|
| 392 |
+
# check if a trigger request was received
|
| 393 |
+
if self.rhc_status.trigger.read_retry(row_index=self.controller_index,
|
| 394 |
+
col_index=0,
|
| 395 |
+
row_index_view=0)[0]:
|
| 396 |
+
self._rhc() # run solution
|
| 397 |
+
self.rhc_status.trigger.write_retry(False,
|
| 398 |
+
row_index=self.controller_index,
|
| 399 |
+
col_index=0,
|
| 400 |
+
row_index_view=0) # allow next solution trigger
|
| 401 |
+
|
| 402 |
+
self._remote_triggerer.ack() # send ack signal to server
|
| 403 |
+
self._received_trigger = False
|
| 404 |
+
|
| 405 |
+
self._term_req_received = self._term_req_received or self._remote_term.read_retry(row_index=0,
|
| 406 |
+
col_index=0,
|
| 407 |
+
row_index_view=0)[0]
|
| 408 |
+
self.close() # is not stricly necessary
|
| 409 |
+
|
| 410 |
+
def reset(self):
|
| 411 |
+
|
| 412 |
+
if not self._closed:
|
| 413 |
+
self.reset_rhc_data()
|
| 414 |
+
self._failed = False # allow triggering
|
| 415 |
+
self._n_resets += 1
|
| 416 |
+
self.rhc_status.fails.write_retry(False,
|
| 417 |
+
row_index=self.controller_index,
|
| 418 |
+
col_index=0,
|
| 419 |
+
row_index_view=0)
|
| 420 |
+
self.rhc_status.resets.write_retry(False,
|
| 421 |
+
row_index=self.controller_index,
|
| 422 |
+
col_index=0,
|
| 423 |
+
row_index_view=0)
|
| 424 |
+
|
| 425 |
+
def _create_jnt_maps(self):
|
| 426 |
+
|
| 427 |
+
# retrieve env-side joint names from shared mem
|
| 428 |
+
self._env_side_jnt_names = self.robot_state.jnt_names()
|
| 429 |
+
self._check_jnt_names_compatibility() # will raise exception if not self._allow_less_jnts
|
| 430 |
+
if not self._got_jnt_names_from_controllers:
|
| 431 |
+
exception = f"Cannot run the solve(). assign_env_side_jnt_names() was not called!"
|
| 432 |
+
Journal.log(self._class_name_base,
|
| 433 |
+
"_create_jnt_maps",
|
| 434 |
+
exception,
|
| 435 |
+
LogType.EXCEP,
|
| 436 |
+
throw_when_excep = True)
|
| 437 |
+
|
| 438 |
+
# robot homer guarantees that _controller_side_jnt_names is at least contained in self._env_side_jnt_names (or equal)
|
| 439 |
+
self._to_controller = [self._env_side_jnt_names.index(element) for element in self._controller_side_jnt_names]
|
| 440 |
+
# set joint remappings for shared data from env data to controller
|
| 441 |
+
# all shared data is by convention specified according to the env (jnts are ordered that way)
|
| 442 |
+
# the remapping is used so that when data is returned, its a remapped view from env to controller,
|
| 443 |
+
# so that data can be assigned direclty from the rhc controller without any issues
|
| 444 |
+
self.robot_state.set_jnts_remapping(jnts_remapping=self._to_controller)
|
| 445 |
+
self.robot_cmds.set_jnts_remapping(jnts_remapping=self._to_controller)
|
| 446 |
+
self.robot_pred.set_jnts_remapping(jnts_remapping=self._to_controller)
|
| 447 |
+
self.rhc_pred_delta.set_jnts_remapping(jnts_remapping=self._to_controller)
|
| 448 |
+
|
| 449 |
+
return True
|
| 450 |
+
|
| 451 |
+
def reset_rhc_data(self):
|
| 452 |
+
|
| 453 |
+
self._reset() # custom reset (e.g. it should set the current solution to some
|
| 454 |
+
# default solution, like a bootstrap)
|
| 455 |
+
|
| 456 |
+
self.rhc_refs.reset() # reset rhc refs to default (has to be called after _reset)
|
| 457 |
+
|
| 458 |
+
self._write_cmds_from_sol() # use latest solution (e.g. from bootstrap if called before running
|
| 459 |
+
# the first solve) as default state
|
| 460 |
+
|
| 461 |
+
def failed(self):
|
| 462 |
+
return self._failed
|
| 463 |
+
|
| 464 |
+
def robot_mass(self):
|
| 465 |
+
return self._robot_mass
|
| 466 |
+
|
| 467 |
+
def _assign_cntrl_index(self, reg_state: np.ndarray):
|
| 468 |
+
state = reg_state.flatten() # ensure 1D tensor
|
| 469 |
+
free_spots = np.nonzero(~state.flatten())[0]
|
| 470 |
+
return free_spots[0].item() # just return the first free spot
|
| 471 |
+
|
| 472 |
+
def _register_to_cluster(self):
|
| 473 |
+
|
| 474 |
+
self.rhc_status = RhcStatus(is_server=False,
|
| 475 |
+
namespace=self.namespace,
|
| 476 |
+
verbose=self._verbose,
|
| 477 |
+
vlevel=VLevel.V2,
|
| 478 |
+
with_torch_view=False,
|
| 479 |
+
with_gpu_mirror=False,
|
| 480 |
+
optimize_mem=True,
|
| 481 |
+
cluster_size=1, # we just need the row corresponding to this controller
|
| 482 |
+
n_contacts=None, # we get this from server
|
| 483 |
+
n_nodes=None # we get this from server
|
| 484 |
+
)
|
| 485 |
+
self.rhc_status.run() # rhc status (reg. flags, failure, tot cost, tot cnstrl viol, etc...)
|
| 486 |
+
|
| 487 |
+
# acquire semaphores since we have to perform non-atomic operations
|
| 488 |
+
# on the whole memory views
|
| 489 |
+
self.rhc_status.registration.data_sem_acquire()
|
| 490 |
+
self.rhc_status.controllers_counter.data_sem_acquire()
|
| 491 |
+
self.rhc_status.controllers_counter.synch_all(retry = True,
|
| 492 |
+
read = True)
|
| 493 |
+
|
| 494 |
+
available_spots = self.rhc_status.cluster_size
|
| 495 |
+
# from here on all pre registration ops can be done
|
| 496 |
+
|
| 497 |
+
# incrementing cluster controllers counter
|
| 498 |
+
controllers_counter = self.rhc_status.controllers_counter.get_numpy_mirror()
|
| 499 |
+
if controllers_counter[0, 0] + 1 > available_spots: # no space left -> return
|
| 500 |
+
self.rhc_status.controllers_counter.data_sem_release()
|
| 501 |
+
self.rhc_status.registration.data_sem_release()
|
| 502 |
+
exception = "Cannot register to cluster. No space left " + \
|
| 503 |
+
f"({controllers_counter[0, 0]} controllers already registered)"
|
| 504 |
+
Journal.log(self._class_name_base,
|
| 505 |
+
"_register_to_cluster",
|
| 506 |
+
exception,
|
| 507 |
+
LogType.EXCEP,
|
| 508 |
+
throw_when_excep = True)
|
| 509 |
+
|
| 510 |
+
# now we can register
|
| 511 |
+
|
| 512 |
+
# increment controllers counter
|
| 513 |
+
controllers_counter += 1
|
| 514 |
+
self.controller_index = controllers_counter.item() -1
|
| 515 |
+
|
| 516 |
+
# actually register to cluster
|
| 517 |
+
self.rhc_status.controllers_counter.synch_all(retry = True,
|
| 518 |
+
read = False) # writes to shared mem (just one for all controllers (i.e n_rows = 1))
|
| 519 |
+
|
| 520 |
+
# read current registration state
|
| 521 |
+
self.rhc_status.registration.synch_all(retry = True,
|
| 522 |
+
read = True,
|
| 523 |
+
row_index=self.controller_index,
|
| 524 |
+
row_index_view=0)
|
| 525 |
+
registrations = self.rhc_status.registration.get_numpy_mirror()
|
| 526 |
+
# self.controller_index = self._assign_cntrl_index(registrations)
|
| 527 |
+
|
| 528 |
+
|
| 529 |
+
self._class_name_base = self._class_name_base+str(self.controller_index)
|
| 530 |
+
# self.controller_index_np = np.array(self.controller_index)
|
| 531 |
+
self.controller_index_np = np.array(0) # given that we use optimize_mem, the shared mem copy has shape 1 x n_cols (we can write and read at [0, :])
|
| 532 |
+
|
| 533 |
+
registrations[self.controller_index_np, 0] = True
|
| 534 |
+
self.rhc_status.registration.synch_all(retry = True,
|
| 535 |
+
read = False,
|
| 536 |
+
row_index=self.controller_index,
|
| 537 |
+
col_index=0,
|
| 538 |
+
row_index_view=0)
|
| 539 |
+
|
| 540 |
+
# now all heavy stuff that would otherwise make the registration slow
|
| 541 |
+
self._remote_term = SharedTWrapper(namespace=self.namespace,
|
| 542 |
+
basename="RemoteTermination",
|
| 543 |
+
is_server=False,
|
| 544 |
+
verbose = self._verbose,
|
| 545 |
+
vlevel = VLevel.V2,
|
| 546 |
+
with_gpu_mirror=False,
|
| 547 |
+
with_torch_view=False,
|
| 548 |
+
dtype=dtype.Bool)
|
| 549 |
+
self._remote_term.run()
|
| 550 |
+
|
| 551 |
+
# other initializations
|
| 552 |
+
|
| 553 |
+
self.cluster_stats = RhcProfiling(is_server=False,
|
| 554 |
+
name=self.namespace,
|
| 555 |
+
verbose=self._verbose,
|
| 556 |
+
vlevel=VLevel.V2,
|
| 557 |
+
safe=True,
|
| 558 |
+
optimize_mem=True,
|
| 559 |
+
cluster_size=1 # we just need the row corresponding to this controller
|
| 560 |
+
) # profiling data
|
| 561 |
+
self.cluster_stats.run()
|
| 562 |
+
self.cluster_stats.synch_info()
|
| 563 |
+
|
| 564 |
+
self._create_jnt_maps()
|
| 565 |
+
self.init_rhc_task_cmds() # initializes rhc interface to external commands (defined by child class)
|
| 566 |
+
self._consinstency_checks() # sanity checks
|
| 567 |
+
|
| 568 |
+
if self._homer is None:
|
| 569 |
+
self._init_robot_homer() # call this in case it wasn't called by child
|
| 570 |
+
|
| 571 |
+
self._robot_mass = self._get_robot_mass() # uses child class implemented method
|
| 572 |
+
self._contact_f_scale = self._get_robot_mass() * 9.81
|
| 573 |
+
|
| 574 |
+
# writing some static info about this controller
|
| 575 |
+
# self.rhc_status.rhc_static_info.synch_all(retry = True,
|
| 576 |
+
# read = True,
|
| 577 |
+
# row_index=self.controller_index,
|
| 578 |
+
# col_index=0) # first read current static info from other controllers (not necessary if optimize_mem==True)
|
| 579 |
+
self.rhc_status.rhc_static_info.set(data=np.array(self._dt),
|
| 580 |
+
data_type="dts",
|
| 581 |
+
rhc_idxs=self.controller_index_np,
|
| 582 |
+
gpu=False)
|
| 583 |
+
self.rhc_status.rhc_static_info.set(data=np.array(self._t_horizon),
|
| 584 |
+
data_type="horizons",
|
| 585 |
+
rhc_idxs=self.controller_index_np,
|
| 586 |
+
gpu=False)
|
| 587 |
+
self.rhc_status.rhc_static_info.set(data=np.array(self._n_nodes),
|
| 588 |
+
data_type="nnodes",
|
| 589 |
+
rhc_idxs=self.controller_index_np,
|
| 590 |
+
gpu=False)
|
| 591 |
+
# writing some static rhc info which is only available after problem init
|
| 592 |
+
self.rhc_status.rhc_static_info.set(data=np.array(len(self._get_contacts())),
|
| 593 |
+
data_type="ncontacts",
|
| 594 |
+
rhc_idxs=self.controller_index_np,
|
| 595 |
+
gpu=False)
|
| 596 |
+
self.rhc_status.rhc_static_info.set(data=np.array(self.robot_mass()),
|
| 597 |
+
data_type="robot_mass",
|
| 598 |
+
rhc_idxs=self.controller_index_np,
|
| 599 |
+
gpu=False)
|
| 600 |
+
self.rhc_status.rhc_static_info.set(data=np.array(self._pred_node_idx),
|
| 601 |
+
data_type="pred_node_idx",
|
| 602 |
+
rhc_idxs=self.controller_index_np,
|
| 603 |
+
gpu=False)
|
| 604 |
+
|
| 605 |
+
self.rhc_status.rhc_static_info.synch_retry(row_index=self.controller_index,
|
| 606 |
+
col_index=0,
|
| 607 |
+
row_index_view=0,
|
| 608 |
+
n_rows=1, n_cols=self.rhc_status.rhc_static_info.n_cols,
|
| 609 |
+
read=False)
|
| 610 |
+
|
| 611 |
+
# we set homings also for joints which are not in the rhc homing map
|
| 612 |
+
# since this is usually required on env side
|
| 613 |
+
|
| 614 |
+
homing_full = self._homer_env.get_homing().reshape(1,
|
| 615 |
+
self.robot_cmds.n_jnts())
|
| 616 |
+
|
| 617 |
+
null_action = np.zeros((1, self.robot_cmds.n_jnts()),
|
| 618 |
+
dtype=self._dtype)
|
| 619 |
+
|
| 620 |
+
self.robot_cmds.jnts_state.set(data=homing_full, data_type="q",
|
| 621 |
+
robot_idxs=self.controller_index_np,
|
| 622 |
+
no_remap=True)
|
| 623 |
+
self.robot_cmds.jnts_state.set(data=null_action, data_type="v",
|
| 624 |
+
robot_idxs=self.controller_index_np,
|
| 625 |
+
no_remap=True)
|
| 626 |
+
self.robot_cmds.jnts_state.set(data=null_action, data_type="eff",
|
| 627 |
+
robot_idxs=self.controller_index_np,
|
| 628 |
+
no_remap=True)
|
| 629 |
+
|
| 630 |
+
# write all joints (including homing for env-only ones)
|
| 631 |
+
self.robot_cmds.jnts_state.synch_retry(row_index=self.controller_index, col_index=0,
|
| 632 |
+
row_index_view=0,
|
| 633 |
+
n_rows=1, n_cols=self.robot_cmds.jnts_state.n_cols,
|
| 634 |
+
read=False) # only write data corresponding to this controller
|
| 635 |
+
|
| 636 |
+
self.reset() # reset controller
|
| 637 |
+
self._n_resets=0
|
| 638 |
+
|
| 639 |
+
# for last we create the trigger client
|
| 640 |
+
self._remote_triggerer = RemoteTriggererClnt(namespace=self.namespace,
|
| 641 |
+
verbose=self._verbose,
|
| 642 |
+
vlevel=VLevel.V2) # remote triggering
|
| 643 |
+
self._remote_triggerer.run()
|
| 644 |
+
|
| 645 |
+
if self._debug:
|
| 646 |
+
# internal solution is published on shared mem
|
| 647 |
+
# we assume the user has made available the cost
|
| 648 |
+
# and constraint data at this point (e.g. through
|
| 649 |
+
# the solution of a bootstrap)
|
| 650 |
+
cost_data = self._get_cost_data()
|
| 651 |
+
constr_data = self._get_constr_data()
|
| 652 |
+
config = RhcInternal.Config(is_server=True,
|
| 653 |
+
enable_q= True,
|
| 654 |
+
enable_v=True,
|
| 655 |
+
enable_a=True,
|
| 656 |
+
enable_a_dot=False,
|
| 657 |
+
enable_f=True,
|
| 658 |
+
enable_f_dot=False,
|
| 659 |
+
enable_eff=False,
|
| 660 |
+
cost_names=cost_data[0],
|
| 661 |
+
cost_dims=cost_data[1],
|
| 662 |
+
constr_names=constr_data[0],
|
| 663 |
+
constr_dims=constr_data[1],
|
| 664 |
+
)
|
| 665 |
+
self.rhc_internal = RhcInternal(config=config,
|
| 666 |
+
namespace=self.namespace,
|
| 667 |
+
rhc_index = self.controller_index,
|
| 668 |
+
n_contacts=self.n_contacts,
|
| 669 |
+
n_jnts=self.n_dofs,
|
| 670 |
+
jnt_names=self._controller_side_jnt_names,
|
| 671 |
+
n_nodes=self._n_nodes,
|
| 672 |
+
verbose = self._verbose,
|
| 673 |
+
vlevel=VLevel.V2,
|
| 674 |
+
force_reconnection=True,
|
| 675 |
+
safe=True)
|
| 676 |
+
self.rhc_internal.run()
|
| 677 |
+
|
| 678 |
+
Journal.log(self._class_name_base,
|
| 679 |
+
"_register_to_cluster",
|
| 680 |
+
f"controller {self.controller_index} registered",
|
| 681 |
+
LogType.STAT,
|
| 682 |
+
throw_when_excep = True)
|
| 683 |
+
|
| 684 |
+
# we can now release everything so that other controllers can register
|
| 685 |
+
self.rhc_status.controllers_counter.data_sem_release()
|
| 686 |
+
self.rhc_status.registration.data_sem_release()
|
| 687 |
+
|
| 688 |
+
self._registered = True
|
| 689 |
+
|
| 690 |
+
def _unregister_from_cluster(self):
|
| 691 |
+
|
| 692 |
+
if self._received_trigger:
|
| 693 |
+
# received interrupt during solution -->
|
| 694 |
+
# send ack signal to server anyway
|
| 695 |
+
self._remote_triggerer.ack()
|
| 696 |
+
if self._registered:
|
| 697 |
+
# acquire semaphores since we have to perform operations
|
| 698 |
+
# on the whole memory views
|
| 699 |
+
self.rhc_status.registration.data_sem_acquire()
|
| 700 |
+
self.rhc_status.controllers_counter.data_sem_acquire()
|
| 701 |
+
self.rhc_status.registration.write_retry(False,
|
| 702 |
+
row_index=self.controller_index,
|
| 703 |
+
col_index=0,
|
| 704 |
+
row_index_view=0)
|
| 705 |
+
self._deactivate()
|
| 706 |
+
# decrementing controllers counter
|
| 707 |
+
self.rhc_status.controllers_counter.synch_all(retry = True,
|
| 708 |
+
read = True)
|
| 709 |
+
controllers_counter = self.rhc_status.controllers_counter.get_numpy_mirror()
|
| 710 |
+
controllers_counter -= 1
|
| 711 |
+
self.rhc_status.controllers_counter.synch_all(retry = True,
|
| 712 |
+
read = False)
|
| 713 |
+
Journal.log(self._class_name_base,
|
| 714 |
+
"_unregister_from_cluster",
|
| 715 |
+
"Done",
|
| 716 |
+
LogType.STAT,
|
| 717 |
+
throw_when_excep = True)
|
| 718 |
+
# we can now release everything
|
| 719 |
+
self.rhc_status.registration.data_sem_release()
|
| 720 |
+
self.rhc_status.controllers_counter.data_sem_release()
|
| 721 |
+
self._registered = False
|
| 722 |
+
|
| 723 |
+
def _get_quat_remap(self):
|
| 724 |
+
# to be overridden by child class if necessary
|
| 725 |
+
return [0, 1, 2, 3]
|
| 726 |
+
|
| 727 |
+
def _consinstency_checks(self):
|
| 728 |
+
|
| 729 |
+
# check controller dt
|
| 730 |
+
server_side_cluster_dt = self.cluster_stats.get_info(info_name="cluster_dt")
|
| 731 |
+
if not (abs(server_side_cluster_dt - self._dt) < 1e-4):
|
| 732 |
+
exception = f"Trying to initialize a controller with control dt {self._dt}, which" + \
|
| 733 |
+
f"does not match the cluster control dt {server_side_cluster_dt}"
|
| 734 |
+
Journal.log(self._class_name_base,
|
| 735 |
+
"_consinstency_checks",
|
| 736 |
+
exception,
|
| 737 |
+
LogType.EXCEP,
|
| 738 |
+
throw_when_excep = True)
|
| 739 |
+
# check contact names
|
| 740 |
+
|
| 741 |
+
server_side_contact_names = set(self.robot_state.contact_names())
|
| 742 |
+
control_side_contact_names = set(self._get_contacts())
|
| 743 |
+
|
| 744 |
+
if not server_side_contact_names == control_side_contact_names:
|
| 745 |
+
warn = f"Controller-side contact names do not match server-side names!" + \
|
| 746 |
+
f"\nServer: {self.robot_state.contact_names()}\n Controller: {self._get_contacts()}"
|
| 747 |
+
Journal.log(self._class_name_base,
|
| 748 |
+
"_consinstency_checks",
|
| 749 |
+
warn,
|
| 750 |
+
LogType.WARN,
|
| 751 |
+
throw_when_excep = True)
|
| 752 |
+
if not len(self.robot_state.contact_names()) == len(self._get_contacts()):
|
| 753 |
+
# at least, we need the n of contacts to match!
|
| 754 |
+
exception = f"Controller-side n contacts {self._get_contacts()} do not match " + \
|
| 755 |
+
f"server-side n contacts {len(self.robot_state.contact_names())}!"
|
| 756 |
+
Journal.log(self._class_name_base,
|
| 757 |
+
"_consinstency_checks",
|
| 758 |
+
exception,
|
| 759 |
+
LogType.EXCEP,
|
| 760 |
+
throw_when_excep = True)
|
| 761 |
+
|
| 762 |
+
def _init(self):
|
| 763 |
+
|
| 764 |
+
stat = f"Trying to initialize RHC controller " + \
|
| 765 |
+
f"with dt: {self._dt} s, t_horizon: {self._t_horizon} s, n_intervals: {self._n_intervals}"
|
| 766 |
+
Journal.log(self._class_name_base,
|
| 767 |
+
"_init",
|
| 768 |
+
stat,
|
| 769 |
+
LogType.STAT,
|
| 770 |
+
throw_when_excep = True)
|
| 771 |
+
|
| 772 |
+
self._init_states() # initializes shared mem. states
|
| 773 |
+
|
| 774 |
+
self._init_problem() # we call the child's initialization method for the actual problem
|
| 775 |
+
self._post_problem_init()
|
| 776 |
+
|
| 777 |
+
self._register_to_cluster() # registers the controller to the cluster
|
| 778 |
+
|
| 779 |
+
Journal.log(self._class_name_base,
|
| 780 |
+
"_init",
|
| 781 |
+
f"RHC controller initialized with cluster index {self.controller_index} on process {os.getpid()}",
|
| 782 |
+
LogType.STAT,
|
| 783 |
+
throw_when_excep = True)
|
| 784 |
+
|
| 785 |
+
def _deactivate(self):
|
| 786 |
+
# signal controller deactivation over shared mem
|
| 787 |
+
self.rhc_status.activation_state.write_retry(False,
|
| 788 |
+
row_index=self.controller_index,
|
| 789 |
+
col_index=0,
|
| 790 |
+
row_index_view=0)
|
| 791 |
+
# also set cmds to homing for safety
|
| 792 |
+
# self.reset_rhc_data()
|
| 793 |
+
|
| 794 |
+
def _on_failure(self):
|
| 795 |
+
|
| 796 |
+
self.rhc_status.fails.write_retry(True,
|
| 797 |
+
row_index=self.controller_index,
|
| 798 |
+
col_index=0,
|
| 799 |
+
row_index_view=0)
|
| 800 |
+
self._deactivate()
|
| 801 |
+
self._n_fails += 1
|
| 802 |
+
self.rhc_status.controllers_fail_counter.write_retry(self._n_fails,
|
| 803 |
+
row_index=self.controller_index,
|
| 804 |
+
col_index=0,
|
| 805 |
+
row_index_view=0)
|
| 806 |
+
|
| 807 |
+
def _init_robot_homer(self):
|
| 808 |
+
self._homer = RobotHomer(srdf_path=self.srdf_path,
|
| 809 |
+
jnt_names=self._controller_side_jnt_names)
|
| 810 |
+
|
| 811 |
+
self._homer_env = RobotHomer(srdf_path=self.srdf_path,
|
| 812 |
+
jnt_names=self.robot_state.jnt_names())
|
| 813 |
+
|
| 814 |
+
def _update_profiling_data(self):
|
| 815 |
+
|
| 816 |
+
# updated debug data on shared memory
|
| 817 |
+
# with the latest info available
|
| 818 |
+
self.cluster_stats.solve_loop_dt.write_retry(self._profiling_data_dict["full_solve_dt"],
|
| 819 |
+
row_index=self.controller_index,
|
| 820 |
+
col_index=0,
|
| 821 |
+
row_index_view=0)
|
| 822 |
+
self.cluster_stats.rti_sol_time.write_retry(self._profiling_data_dict["rti_solve_dt"],
|
| 823 |
+
row_index=self.controller_index,
|
| 824 |
+
col_index=0,
|
| 825 |
+
row_index_view=0)
|
| 826 |
+
self.cluster_stats.prb_update_dt.write_retry(self._profiling_data_dict["problem_update_dt"],
|
| 827 |
+
row_index=self.controller_index,
|
| 828 |
+
col_index=0,
|
| 829 |
+
row_index_view=0)
|
| 830 |
+
self.cluster_stats.phase_shift_dt.write_retry(self._profiling_data_dict["phases_shift_dt"],
|
| 831 |
+
row_index=self.controller_index,
|
| 832 |
+
col_index=0,
|
| 833 |
+
row_index_view=0)
|
| 834 |
+
self.cluster_stats.task_ref_update_dt.write_retry(self._profiling_data_dict["task_ref_update"],
|
| 835 |
+
row_index=self.controller_index,
|
| 836 |
+
col_index=0,
|
| 837 |
+
row_index_view=0)
|
| 838 |
+
|
| 839 |
+
def _write_cmds_from_sol(self):
|
| 840 |
+
|
| 841 |
+
# gets data from the solution and updates the view on the shared data
|
| 842 |
+
|
| 843 |
+
# cmds for robot
|
| 844 |
+
# jnts
|
| 845 |
+
self.robot_cmds.jnts_state.set(data=self._get_jnt_q_from_sol(node_idx=self._rhc_cmds_node_idx), data_type="q", robot_idxs=self.controller_index_np)
|
| 846 |
+
self.robot_cmds.jnts_state.set(data=self._get_jnt_v_from_sol(node_idx=self._rhc_cmds_node_idx), data_type="v", robot_idxs=self.controller_index_np)
|
| 847 |
+
self.robot_cmds.jnts_state.set(data=self._get_jnt_a_from_sol(node_idx=self._rhc_cmds_node_idx-1), data_type="a", robot_idxs=self.controller_index_np)
|
| 848 |
+
self.robot_cmds.jnts_state.set(data=self._get_jnt_eff_from_sol(node_idx=self._rhc_cmds_node_idx-1), data_type="eff", robot_idxs=self.controller_index_np)
|
| 849 |
+
# root
|
| 850 |
+
self.robot_cmds.root_state.set(data=self._get_root_full_q_from_sol(node_idx=self._rhc_cmds_node_idx), data_type="q_full", robot_idxs=self.controller_index_np)
|
| 851 |
+
self.robot_cmds.root_state.set(data=self._get_root_twist_from_sol(node_idx=self._rhc_cmds_node_idx), data_type="twist", robot_idxs=self.controller_index_np)
|
| 852 |
+
self.robot_cmds.root_state.set(data=self._get_root_a_from_sol(node_idx=self._rhc_cmds_node_idx-1), data_type="a_full", robot_idxs=self.controller_index_np)
|
| 853 |
+
self.robot_cmds.root_state.set(data=self._get_norm_grav_vector_from_sol(node_idx=self._rhc_cmds_node_idx-1), data_type="gn", robot_idxs=self.controller_index_np)
|
| 854 |
+
f_contact = self._get_f_from_sol()
|
| 855 |
+
if f_contact is not None:
|
| 856 |
+
contact_names = self.robot_state.contact_names()
|
| 857 |
+
node_idx_f_estimate=self._rhc_cmds_node_idx-1 # we always write the force to reach the desired state (prev node)
|
| 858 |
+
rhc_q_estimate=self._get_root_full_q_from_sol(node_idx=node_idx_f_estimate)[:, 3:7]
|
| 859 |
+
for i in range(len(contact_names)):
|
| 860 |
+
contact = contact_names[i]
|
| 861 |
+
contact_idx = i*3
|
| 862 |
+
contact_force_rhc_world=f_contact[contact_idx:(contact_idx+3), node_idx_f_estimate:node_idx_f_estimate+1].T
|
| 863 |
+
world2base_frame(v_w=contact_force_rhc_world,
|
| 864 |
+
q_b=rhc_q_estimate,
|
| 865 |
+
v_out=self._contact_force_base_loc_aux,
|
| 866 |
+
is_q_wijk=False # horizon q is ijkw
|
| 867 |
+
)
|
| 868 |
+
self.robot_cmds.contact_wrenches.set(data=self._contact_force_base_loc_aux,
|
| 869 |
+
data_type="f",
|
| 870 |
+
robot_idxs=self.controller_index_np,
|
| 871 |
+
contact_name=contact)
|
| 872 |
+
|
| 873 |
+
# prediction data from MPC horizon
|
| 874 |
+
self.robot_pred.jnts_state.set(data=self._get_jnt_q_from_sol(node_idx=self._pred_node_idx), data_type="q", robot_idxs=self.controller_index_np)
|
| 875 |
+
self.robot_pred.jnts_state.set(data=self._get_jnt_v_from_sol(node_idx=self._pred_node_idx), data_type="v", robot_idxs=self.controller_index_np)
|
| 876 |
+
self.robot_pred.jnts_state.set(data=self._get_jnt_a_from_sol(node_idx=self._pred_node_idx-1), data_type="a", robot_idxs=self.controller_index_np)
|
| 877 |
+
self.robot_pred.jnts_state.set(data=self._get_jnt_eff_from_sol(node_idx=self._pred_node_idx-1), data_type="eff", robot_idxs=self.controller_index_np)
|
| 878 |
+
self.robot_pred.root_state.set(data=self._get_root_full_q_from_sol(node_idx=self._pred_node_idx), data_type="q_full", robot_idxs=self.controller_index_np)
|
| 879 |
+
self.robot_pred.root_state.set(data=self._get_root_twist_from_sol(node_idx=self._pred_node_idx), data_type="twist", robot_idxs=self.controller_index_np)
|
| 880 |
+
self.robot_pred.root_state.set(data=self._get_root_a_from_sol(node_idx=self._pred_node_idx-1), data_type="a_full", robot_idxs=self.controller_index_np)
|
| 881 |
+
self.robot_pred.root_state.set(data=self._get_norm_grav_vector_from_sol(node_idx=self._pred_node_idx-1), data_type="gn", robot_idxs=self.controller_index_np)
|
| 882 |
+
|
| 883 |
+
# write robot commands
|
| 884 |
+
self.robot_cmds.jnts_state.synch_retry(row_index=self.controller_index, col_index=0,
|
| 885 |
+
row_index_view=0,
|
| 886 |
+
n_rows=1, n_cols=self.robot_cmds.jnts_state.n_cols,
|
| 887 |
+
read=False) # jnt state
|
| 888 |
+
self.robot_cmds.root_state.synch_retry(row_index=self.controller_index, col_index=0,
|
| 889 |
+
row_index_view=0,
|
| 890 |
+
n_rows=1, n_cols=self.robot_cmds.root_state.n_cols,
|
| 891 |
+
read=False) # root state, in case it was written
|
| 892 |
+
self.robot_cmds.contact_wrenches.synch_retry(row_index=self.controller_index, col_index=0,
|
| 893 |
+
row_index_view=0,
|
| 894 |
+
n_rows=1, n_cols=self.robot_cmds.contact_wrenches.n_cols,
|
| 895 |
+
read=False) # contact state
|
| 896 |
+
|
| 897 |
+
# write robot pred
|
| 898 |
+
self.robot_pred.jnts_state.synch_retry(row_index=self.controller_index, col_index=0,
|
| 899 |
+
row_index_view=0,
|
| 900 |
+
n_rows=1, n_cols=self.robot_cmds.jnts_state.n_cols,
|
| 901 |
+
read=False)
|
| 902 |
+
self.robot_pred.root_state.synch_retry(row_index=self.controller_index, col_index=0,
|
| 903 |
+
row_index_view=0,
|
| 904 |
+
n_rows=1, n_cols=self.robot_cmds.root_state.n_cols,
|
| 905 |
+
read=False)
|
| 906 |
+
|
| 907 |
+
# we also fill other data (cost, constr. violation, etc..)
|
| 908 |
+
self.rhc_status.rhc_cost.write_retry(self._get_rhc_cost(),
|
| 909 |
+
row_index=self.controller_index,
|
| 910 |
+
col_index=0,
|
| 911 |
+
row_index_view=0)
|
| 912 |
+
self.rhc_status.rhc_constr_viol.write_retry(self._get_rhc_constr_viol(),
|
| 913 |
+
row_index=self.controller_index,
|
| 914 |
+
col_index=0,
|
| 915 |
+
row_index_view=0)
|
| 916 |
+
self.rhc_status.rhc_n_iter.write_retry(self._get_rhc_niter_to_sol(),
|
| 917 |
+
row_index=self.controller_index,
|
| 918 |
+
col_index=0,
|
| 919 |
+
row_index_view=0)
|
| 920 |
+
self.rhc_status.rhc_nodes_cost.write_retry(data=self._get_rhc_nodes_cost(),
|
| 921 |
+
row_index=self.controller_index,
|
| 922 |
+
col_index=0,
|
| 923 |
+
row_index_view=0)
|
| 924 |
+
self.rhc_status.rhc_nodes_constr_viol.write_retry(data=self._get_rhc_nodes_constr_viol(),
|
| 925 |
+
row_index=self.controller_index,
|
| 926 |
+
col_index=0,
|
| 927 |
+
row_index_view=0)
|
| 928 |
+
self.rhc_status.rhc_fail_idx.write_retry(self._get_failure_index(),
|
| 929 |
+
row_index=self.controller_index,
|
| 930 |
+
col_index=0,
|
| 931 |
+
row_index_view=0) # write idx on shared mem
|
| 932 |
+
|
| 933 |
+
def _compute_pred_delta(self):
|
| 934 |
+
|
| 935 |
+
# measurements
|
| 936 |
+
q_full_root_meas = self.robot_state.root_state.get(data_type="q_full", robot_idxs=self.controller_index_np)
|
| 937 |
+
twist_root_meas = self.robot_state.root_state.get(data_type="twist", robot_idxs=self.controller_index_np)
|
| 938 |
+
a_root_meas = self.robot_state.root_state.get(data_type="a_full", robot_idxs=self.controller_index_np)
|
| 939 |
+
g_vec_root_meas = self.robot_state.root_state.get(data_type="gn", robot_idxs=self.controller_index_np)
|
| 940 |
+
|
| 941 |
+
q_jnts_meas = self.robot_state.jnts_state.get(data_type="q", robot_idxs=self.controller_index_np)
|
| 942 |
+
v_jnts_meas = self.robot_state.jnts_state.get(data_type="v", robot_idxs=self.controller_index_np)
|
| 943 |
+
a_jnts_meas = self.robot_state.jnts_state.get(data_type="a", robot_idxs=self.controller_index_np)
|
| 944 |
+
eff_jnts_meas = self.robot_state.jnts_state.get(data_type="eff", robot_idxs=self.controller_index_np)
|
| 945 |
+
|
| 946 |
+
# prediction from rhc
|
| 947 |
+
delta_root_q_full=self._get_root_full_q_from_sol(node_idx=1)-q_full_root_meas
|
| 948 |
+
delta_root_twist=self._get_root_twist_from_sol(node_idx=1)-twist_root_meas
|
| 949 |
+
delta_root_a=self._get_root_a_from_sol(node_idx=0)-a_root_meas
|
| 950 |
+
delta_g_vec=self._get_norm_grav_vector_from_sol(node_idx=0)-g_vec_root_meas
|
| 951 |
+
|
| 952 |
+
delta_jnts_q=self._get_jnt_q_from_sol(node_idx=1)-q_jnts_meas
|
| 953 |
+
delta_jnts_v=self._get_jnt_v_from_sol(node_idx=1)-v_jnts_meas
|
| 954 |
+
delta_jnts_a=self._get_jnt_a_from_sol(node_idx=0)-a_jnts_meas
|
| 955 |
+
delta_jnts_eff=self._get_jnt_eff_from_sol(node_idx=0)-eff_jnts_meas
|
| 956 |
+
|
| 957 |
+
# writing pred. errors
|
| 958 |
+
self.rhc_pred_delta.root_state.set(data=delta_root_q_full, data_type="q_full", robot_idxs=self.controller_index_np)
|
| 959 |
+
self.rhc_pred_delta.root_state.set(data=delta_root_twist,data_type="twist", robot_idxs=self.controller_index_np)
|
| 960 |
+
self.rhc_pred_delta.root_state.set(data=delta_root_a,data_type="a_full", robot_idxs=self.controller_index_np)
|
| 961 |
+
self.rhc_pred_delta.root_state.set(data=delta_g_vec, data_type="gn", robot_idxs=self.controller_index_np)
|
| 962 |
+
|
| 963 |
+
self.rhc_pred_delta.jnts_state.set(data=delta_jnts_q,data_type="q", robot_idxs=self.controller_index_np)
|
| 964 |
+
self.rhc_pred_delta.jnts_state.set(data=delta_jnts_v,data_type="v", robot_idxs=self.controller_index_np)
|
| 965 |
+
self.rhc_pred_delta.jnts_state.set(data=delta_jnts_a,data_type="a", robot_idxs=self.controller_index_np)
|
| 966 |
+
self.rhc_pred_delta.jnts_state.set(data=delta_jnts_eff, data_type="eff", robot_idxs=self.controller_index_np)
|
| 967 |
+
|
| 968 |
+
# write on shared memory
|
| 969 |
+
self.rhc_pred_delta.jnts_state.synch_retry(row_index=self.controller_index,
|
| 970 |
+
col_index=0,
|
| 971 |
+
n_rows=1,
|
| 972 |
+
row_index_view=0,
|
| 973 |
+
n_cols=self.robot_cmds.jnts_state.n_cols,
|
| 974 |
+
read=False) # jnt state
|
| 975 |
+
self.rhc_pred_delta.root_state.synch_retry(row_index=self.controller_index,
|
| 976 |
+
col_index=0,
|
| 977 |
+
n_rows=1,
|
| 978 |
+
row_index_view=0,
|
| 979 |
+
n_cols=self.robot_cmds.root_state.n_cols,
|
| 980 |
+
read=False) # root state
|
| 981 |
+
|
| 982 |
+
def _assign_controller_side_jnt_names(self,
|
| 983 |
+
jnt_names: List[str]):
|
| 984 |
+
|
| 985 |
+
self._controller_side_jnt_names = jnt_names
|
| 986 |
+
self._got_jnt_names_from_controllers = True
|
| 987 |
+
|
| 988 |
+
def _check_jnt_names_compatibility(self):
|
| 989 |
+
|
| 990 |
+
set_rhc = set(self._controller_side_jnt_names)
|
| 991 |
+
set_env = set(self._env_side_jnt_names)
|
| 992 |
+
|
| 993 |
+
if not set_rhc == set_env:
|
| 994 |
+
rhc_is_missing=set_env-set_rhc
|
| 995 |
+
env_is_missing=set_rhc-set_env
|
| 996 |
+
|
| 997 |
+
msg_type=LogType.WARN
|
| 998 |
+
message=""
|
| 999 |
+
if not len(rhc_is_missing)==0: # allowed
|
| 1000 |
+
message = "\nSome env-side joint names are missing on rhc-side!\n" + \
|
| 1001 |
+
"ENV-SIDE-> \n" + \
|
| 1002 |
+
" ".join(self._env_side_jnt_names) + "\n" +\
|
| 1003 |
+
"RHC-SIDE -> \n" + \
|
| 1004 |
+
" ".join(self._controller_side_jnt_names) + "\n" \
|
| 1005 |
+
"\MISSING -> \n" + \
|
| 1006 |
+
" ".join(list(rhc_is_missing)) + "\n"
|
| 1007 |
+
if not self._allow_less_jnts: # raise exception
|
| 1008 |
+
msg_type=LogType.EXCEP
|
| 1009 |
+
|
| 1010 |
+
if not len(env_is_missing)==0: # not allowed
|
| 1011 |
+
message = "\nSome rhc-side joint names are missing on env-side!\n" + \
|
| 1012 |
+
"ENV-SIDE-> \n" + \
|
| 1013 |
+
" ".join(self._env_side_jnt_names) + \
|
| 1014 |
+
"RHC-SIDE -> \n" + \
|
| 1015 |
+
" ".join(self._controller_side_jnt_names) + "\n" \
|
| 1016 |
+
"\nmissing -> \n" + \
|
| 1017 |
+
" ".join(list(env_is_missing))
|
| 1018 |
+
msg_type=LogType.EXCEP
|
| 1019 |
+
|
| 1020 |
+
Journal.log(self._class_name_base,
|
| 1021 |
+
"_check_jnt_names_compatibility",
|
| 1022 |
+
message,
|
| 1023 |
+
msg_type,
|
| 1024 |
+
throw_when_excep = True)
|
| 1025 |
+
|
| 1026 |
+
def _get_cost_data(self):
|
| 1027 |
+
# to be overridden by child class
|
| 1028 |
+
return None, None
|
| 1029 |
+
|
| 1030 |
+
def _get_constr_data(self):
|
| 1031 |
+
# to be overridden by child class
|
| 1032 |
+
return None, None
|
| 1033 |
+
|
| 1034 |
+
def _get_fail_idx(self):
|
| 1035 |
+
# to be overriden by parent
|
| 1036 |
+
return 0.0
|
| 1037 |
+
|
| 1038 |
+
def _get_failure_index(self):
|
| 1039 |
+
fail_idx=self._get_fail_idx()/self._fail_idx_thresh
|
| 1040 |
+
if fail_idx>1.0:
|
| 1041 |
+
fail_idx=1.0
|
| 1042 |
+
return fail_idx
|
| 1043 |
+
|
| 1044 |
+
def _check_rhc_failure(self):
|
| 1045 |
+
# we use fail idx viol to detect failures
|
| 1046 |
+
idx = self._get_failure_index()
|
| 1047 |
+
return idx>=1.0
|
| 1048 |
+
|
| 1049 |
+
def _update_rhc_internal(self):
|
| 1050 |
+
# data which is not enabled in the config is not actually
|
| 1051 |
+
# written so overhead is minimal for non-enabled data
|
| 1052 |
+
self.rhc_internal.write_q(data= self._get_q_from_sol(),
|
| 1053 |
+
retry=True)
|
| 1054 |
+
self.rhc_internal.write_v(data= self._get_v_from_sol(),
|
| 1055 |
+
retry=True)
|
| 1056 |
+
self.rhc_internal.write_a(data= self._get_a_from_sol(),
|
| 1057 |
+
retry=True)
|
| 1058 |
+
self.rhc_internal.write_a_dot(data= self._get_a_dot_from_sol(),
|
| 1059 |
+
retry=True)
|
| 1060 |
+
self.rhc_internal.write_f(data= self._get_f_from_sol(),
|
| 1061 |
+
retry=True)
|
| 1062 |
+
self.rhc_internal.write_f_dot(data= self._get_f_dot_from_sol(),
|
| 1063 |
+
retry=True)
|
| 1064 |
+
self.rhc_internal.write_eff(data= self._get_eff_from_sol(),
|
| 1065 |
+
retry=True)
|
| 1066 |
+
for cost_idx in range(self.rhc_internal.config.n_costs):
|
| 1067 |
+
# iterate over all costs and update all values
|
| 1068 |
+
cost_name = self.rhc_internal.config.cost_names[cost_idx]
|
| 1069 |
+
self.rhc_internal.write_cost(data= self._get_cost_from_sol(cost_name = cost_name),
|
| 1070 |
+
cost_name = cost_name,
|
| 1071 |
+
retry=True)
|
| 1072 |
+
for constr_idx in range(self.rhc_internal.config.n_constr):
|
| 1073 |
+
# iterate over all constraints and update all values
|
| 1074 |
+
constr_name = self.rhc_internal.config.constr_names[constr_idx]
|
| 1075 |
+
self.rhc_internal.write_constr(data= self._get_constr_from_sol(constr_name=constr_name),
|
| 1076 |
+
constr_name = constr_name,
|
| 1077 |
+
retry=True)
|
| 1078 |
+
|
| 1079 |
+
def _get_contacts(self):
|
| 1080 |
+
contact_names = self._get_contact_names()
|
| 1081 |
+
self._got_contact_names = True
|
| 1082 |
+
return contact_names
|
| 1083 |
+
|
| 1084 |
+
def _get_q_from_sol(self):
|
| 1085 |
+
# to be overridden by child class
|
| 1086 |
+
return None
|
| 1087 |
+
|
| 1088 |
+
def _get_v_from_sol(self):
|
| 1089 |
+
# to be overridden by child class
|
| 1090 |
+
return None
|
| 1091 |
+
|
| 1092 |
+
def _get_a_from_sol(self):
|
| 1093 |
+
# to be overridden by child class
|
| 1094 |
+
return None
|
| 1095 |
+
|
| 1096 |
+
def _get_a_dot_from_sol(self):
|
| 1097 |
+
# to be overridden by child class
|
| 1098 |
+
return None
|
| 1099 |
+
|
| 1100 |
+
def _get_f_from_sol(self):
|
| 1101 |
+
# to be overridden by child class
|
| 1102 |
+
return None
|
| 1103 |
+
|
| 1104 |
+
def _get_f_dot_from_sol(self):
|
| 1105 |
+
# to be overridden by child class
|
| 1106 |
+
return None
|
| 1107 |
+
|
| 1108 |
+
def _get_eff_from_sol(self):
|
| 1109 |
+
# to be overridden by child class
|
| 1110 |
+
return None
|
| 1111 |
+
|
| 1112 |
+
def _get_cost_from_sol(self,
|
| 1113 |
+
cost_name: str):
|
| 1114 |
+
# to be overridden by child class
|
| 1115 |
+
return None
|
| 1116 |
+
|
| 1117 |
+
def _get_constr_from_sol(self,
|
| 1118 |
+
constr_name: str):
|
| 1119 |
+
# to be overridden by child class
|
| 1120 |
+
return None
|
| 1121 |
+
|
| 1122 |
+
@abstractmethod
|
| 1123 |
+
def _reset(self):
|
| 1124 |
+
pass
|
| 1125 |
+
|
| 1126 |
+
@abstractmethod
|
| 1127 |
+
def _init_rhc_task_cmds(self):
|
| 1128 |
+
pass
|
| 1129 |
+
|
| 1130 |
+
@abstractmethod
|
| 1131 |
+
def _get_robot_jnt_names(self):
|
| 1132 |
+
pass
|
| 1133 |
+
|
| 1134 |
+
@abstractmethod
|
| 1135 |
+
def _get_contact_names(self):
|
| 1136 |
+
pass
|
| 1137 |
+
|
| 1138 |
+
@abstractmethod
|
| 1139 |
+
def _get_jnt_q_from_sol(self, node_idx=1) -> np.ndarray:
|
| 1140 |
+
pass
|
| 1141 |
+
|
| 1142 |
+
@abstractmethod
|
| 1143 |
+
def _get_jnt_v_from_sol(self, node_idx=1) -> np.ndarray:
|
| 1144 |
+
pass
|
| 1145 |
+
|
| 1146 |
+
@abstractmethod
|
| 1147 |
+
def _get_jnt_a_from_sol(self, node_idx=0) -> np.ndarray:
|
| 1148 |
+
pass
|
| 1149 |
+
|
| 1150 |
+
@abstractmethod
|
| 1151 |
+
def _get_jnt_eff_from_sol(self, node_idx=0) -> np.ndarray:
|
| 1152 |
+
pass
|
| 1153 |
+
|
| 1154 |
+
@abstractmethod
|
| 1155 |
+
def _get_root_full_q_from_sol(self, node_idx=1) -> np.ndarray:
|
| 1156 |
+
pass
|
| 1157 |
+
|
| 1158 |
+
@abstractmethod
|
| 1159 |
+
def _get_full_q_from_sol(self, node_idx=1) -> np.ndarray:
|
| 1160 |
+
pass
|
| 1161 |
+
|
| 1162 |
+
@abstractmethod
|
| 1163 |
+
def _get_root_twist_from_sol(self, node_idx=1) -> np.ndarray:
|
| 1164 |
+
pass
|
| 1165 |
+
|
| 1166 |
+
@abstractmethod
|
| 1167 |
+
def _get_root_a_from_sol(self, node_idx=0) -> np.ndarray:
|
| 1168 |
+
pass
|
| 1169 |
+
|
| 1170 |
+
def _get_norm_grav_vector_from_sol(self, node_idx=1) -> np.ndarray:
|
| 1171 |
+
rhc_q=self._get_root_full_q_from_sol(node_idx=node_idx)[:, 3:7]
|
| 1172 |
+
world2base_frame(v_w=self._norm_grav_vector_w,q_b=rhc_q,v_out=self._norm_grav_vector_base_loc,
|
| 1173 |
+
is_q_wijk=False)
|
| 1174 |
+
return self._norm_grav_vector_base_loc
|
| 1175 |
+
|
| 1176 |
+
def _get_rhc_cost(self):
|
| 1177 |
+
# to be overridden
|
| 1178 |
+
return np.nan
|
| 1179 |
+
|
| 1180 |
+
def _get_rhc_constr_viol(self):
|
| 1181 |
+
# to be overridden
|
| 1182 |
+
return np.nan
|
| 1183 |
+
|
| 1184 |
+
def _get_rhc_nodes_cost(self):
|
| 1185 |
+
# to be overridden
|
| 1186 |
+
return np.zeros((1,self.rhc_status.n_nodes), dtype=self._dtype)
|
| 1187 |
+
|
| 1188 |
+
def _get_rhc_nodes_constr_viol(self):
|
| 1189 |
+
# to be overridden
|
| 1190 |
+
return np.zeros((1,self.rhc_status.n_nodes), dtype=self._dtype)
|
| 1191 |
+
|
| 1192 |
+
def _get_rhc_niter_to_sol(self) -> np.ndarray:
|
| 1193 |
+
# to be overridden
|
| 1194 |
+
return np.nan
|
| 1195 |
+
|
| 1196 |
+
@abstractmethod
|
| 1197 |
+
def _update_open_loop(self):
|
| 1198 |
+
# updates rhc controller
|
| 1199 |
+
# using the internal state
|
| 1200 |
+
pass
|
| 1201 |
+
|
| 1202 |
+
@abstractmethod
|
| 1203 |
+
def _update_closed_loop(self):
|
| 1204 |
+
# uses meas. from robot
|
| 1205 |
+
pass
|
| 1206 |
+
|
| 1207 |
+
@abstractmethod
|
| 1208 |
+
def _solve(self) -> bool:
|
| 1209 |
+
pass
|
| 1210 |
+
|
| 1211 |
+
@abstractmethod
|
| 1212 |
+
def _get_ndofs(self):
|
| 1213 |
+
pass
|
| 1214 |
+
|
| 1215 |
+
abstractmethod
|
| 1216 |
+
def _get_robot_mass(self):
|
| 1217 |
+
pass
|
| 1218 |
+
|
| 1219 |
+
@abstractmethod
|
| 1220 |
+
def _init_problem(self):
|
| 1221 |
+
# initialized horizon's TO problem
|
| 1222 |
+
pass
|
| 1223 |
+
|
| 1224 |
+
@abstractmethod
|
| 1225 |
+
def _post_problem_init(self):
|
| 1226 |
+
pass
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/sac.py
ADDED
|
@@ -0,0 +1,680 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import torch.nn as nn
|
| 3 |
+
from torch.distributions.normal import Normal
|
| 4 |
+
import math
|
| 5 |
+
|
| 6 |
+
from aug_mpc.utils.nn.normalization_utils import RunningNormalizer
|
| 7 |
+
from aug_mpc.utils.nn.layer_utils import llayer_init
|
| 8 |
+
|
| 9 |
+
from typing import List
|
| 10 |
+
|
| 11 |
+
from EigenIPC.PyEigenIPC import LogType
|
| 12 |
+
from EigenIPC.PyEigenIPC import Journal
|
| 13 |
+
from EigenIPC.PyEigenIPC import VLevel
|
| 14 |
+
|
| 15 |
+
class SACAgent(nn.Module):
|
| 16 |
+
def __init__(self,
|
| 17 |
+
obs_dim: int,
|
| 18 |
+
actions_dim: int,
|
| 19 |
+
obs_ub: List[float] = None,
|
| 20 |
+
obs_lb: List[float] = None,
|
| 21 |
+
actions_ub: List[float] = None,
|
| 22 |
+
actions_lb: List[float] = None,
|
| 23 |
+
rescale_obs: bool = False,
|
| 24 |
+
norm_obs: bool = True,
|
| 25 |
+
use_action_rescale_for_critic: bool = True,
|
| 26 |
+
device:str="cuda",
|
| 27 |
+
dtype=torch.float32,
|
| 28 |
+
is_eval:bool=False,
|
| 29 |
+
load_qf:bool=False,
|
| 30 |
+
epsilon:float=1e-8,
|
| 31 |
+
debug:bool=False,
|
| 32 |
+
compression_ratio:float=-1.0, # > 0; if [0, 1] compression, >1 "expansion"
|
| 33 |
+
layer_width_actor:int=256,
|
| 34 |
+
n_hidden_layers_actor:int=2,
|
| 35 |
+
layer_width_critic:int=512,
|
| 36 |
+
n_hidden_layers_critic:int=4,
|
| 37 |
+
torch_compile: bool = False,
|
| 38 |
+
add_weight_norm: bool = False,
|
| 39 |
+
add_layer_norm: bool = False,
|
| 40 |
+
add_batch_norm: bool = False):
|
| 41 |
+
|
| 42 |
+
super().__init__()
|
| 43 |
+
|
| 44 |
+
self._use_torch_compile=torch_compile
|
| 45 |
+
|
| 46 |
+
self._layer_width_actor=layer_width_actor
|
| 47 |
+
self._layer_width_critic=layer_width_critic
|
| 48 |
+
self._n_hidden_layers_actor=n_hidden_layers_actor
|
| 49 |
+
self._n_hidden_layers_critic=n_hidden_layers_critic
|
| 50 |
+
|
| 51 |
+
self._obs_dim=obs_dim
|
| 52 |
+
self._actions_dim=actions_dim
|
| 53 |
+
self._actions_ub=actions_ub
|
| 54 |
+
self._actions_lb=actions_lb
|
| 55 |
+
|
| 56 |
+
self._add_weight_norm=add_weight_norm
|
| 57 |
+
self._add_layer_norm=add_layer_norm
|
| 58 |
+
self._add_batch_norm=add_batch_norm
|
| 59 |
+
|
| 60 |
+
self._is_eval=is_eval
|
| 61 |
+
self._load_qf=load_qf
|
| 62 |
+
|
| 63 |
+
self._epsilon=epsilon
|
| 64 |
+
|
| 65 |
+
if compression_ratio > 0.0:
|
| 66 |
+
self._layer_width_actor=int(compression_ratio*obs_dim)
|
| 67 |
+
self._layer_width_critic=int(compression_ratio*(obs_dim+actions_dim))
|
| 68 |
+
|
| 69 |
+
self._normalize_obs = norm_obs
|
| 70 |
+
self._rescale_obs=rescale_obs
|
| 71 |
+
if self._rescale_obs and self._normalize_obs:
|
| 72 |
+
Journal.log(self.__class__.__name__,
|
| 73 |
+
"__init__",
|
| 74 |
+
f"Both running normalization and obs rescaling is enabled. Was this intentional?",
|
| 75 |
+
LogType.WARN,
|
| 76 |
+
throw_when_excep = True)
|
| 77 |
+
|
| 78 |
+
self._use_action_rescale_for_critic=use_action_rescale_for_critic
|
| 79 |
+
|
| 80 |
+
self._rescaling_epsi=1e-9
|
| 81 |
+
|
| 82 |
+
self._debug = debug
|
| 83 |
+
|
| 84 |
+
self._torch_device = device
|
| 85 |
+
self._torch_dtype = dtype
|
| 86 |
+
|
| 87 |
+
# obs scale and bias
|
| 88 |
+
if obs_ub is None:
|
| 89 |
+
obs_ub = [1] * obs_dim
|
| 90 |
+
if obs_lb is None:
|
| 91 |
+
obs_lb = [-1] * obs_dim
|
| 92 |
+
if (len(obs_ub) != obs_dim):
|
| 93 |
+
Journal.log(self.__class__.__name__,
|
| 94 |
+
"__init__",
|
| 95 |
+
f"Observations ub list length should be equal to {obs_dim}, but got {len(obs_ub)}",
|
| 96 |
+
LogType.EXCEP,
|
| 97 |
+
throw_when_excep = True)
|
| 98 |
+
if (len(obs_lb) != obs_dim):
|
| 99 |
+
Journal.log(self.__class__.__name__,
|
| 100 |
+
"__init__",
|
| 101 |
+
f"Observations lb list length should be equal to {obs_dim}, but got {len(obs_lb)}",
|
| 102 |
+
LogType.EXCEP,
|
| 103 |
+
throw_when_excep = True)
|
| 104 |
+
|
| 105 |
+
self._obs_ub = torch.tensor(obs_ub, dtype=self._torch_dtype,
|
| 106 |
+
device=self._torch_device)
|
| 107 |
+
self._obs_lb = torch.tensor(obs_lb, dtype=self._torch_dtype,
|
| 108 |
+
device=self._torch_device)
|
| 109 |
+
obs_scale = torch.full((obs_dim, ),
|
| 110 |
+
fill_value=0.0,
|
| 111 |
+
dtype=self._torch_dtype,
|
| 112 |
+
device=self._torch_device)
|
| 113 |
+
obs_scale[:] = (self._obs_ub-self._obs_lb)/2.0
|
| 114 |
+
self.register_buffer(
|
| 115 |
+
"obs_scale", obs_scale
|
| 116 |
+
)
|
| 117 |
+
obs_bias = torch.full((obs_dim, ),
|
| 118 |
+
fill_value=0.0,
|
| 119 |
+
dtype=self._torch_dtype,
|
| 120 |
+
device=self._torch_device)
|
| 121 |
+
obs_bias[:] = (self._obs_ub+self._obs_lb)/2.0
|
| 122 |
+
self.register_buffer(
|
| 123 |
+
"obs_bias", obs_bias)
|
| 124 |
+
|
| 125 |
+
self._build_nets()
|
| 126 |
+
|
| 127 |
+
self._init_obs_norm()
|
| 128 |
+
|
| 129 |
+
msg=f"Created SAC agent with actor [{self._layer_width_actor}, {self._n_hidden_layers_actor}]\
|
| 130 |
+
and critic [{self._layer_width_critic}, {self._n_hidden_layers_critic}] sizes.\
|
| 131 |
+
\n Runningobs normalizer: {type(self.obs_running_norm)} \
|
| 132 |
+
\n Batch normalization: {self._add_batch_norm} \
|
| 133 |
+
\n Layer normalization: {self._add_layer_norm} \
|
| 134 |
+
\n Weight normalization: {self._add_weight_norm} \
|
| 135 |
+
\n Critic input actions are descaled: {self._use_action_rescale_for_critic}"
|
| 136 |
+
Journal.log(self.__class__.__name__,
|
| 137 |
+
"__init__",
|
| 138 |
+
msg,
|
| 139 |
+
LogType.INFO)
|
| 140 |
+
|
| 141 |
+
def _init_obs_norm(self):
|
| 142 |
+
|
| 143 |
+
self.obs_running_norm=None
|
| 144 |
+
if self._normalize_obs:
|
| 145 |
+
self.obs_running_norm = RunningNormalizer((self._obs_dim,),
|
| 146 |
+
epsilon=self._epsilon,
|
| 147 |
+
device=self._torch_device, dtype=self._torch_dtype,
|
| 148 |
+
freeze_stats=True, # always start with freezed stats
|
| 149 |
+
debug=self._debug)
|
| 150 |
+
self.obs_running_norm.type(self._torch_dtype) # ensuring correct dtype for whole module
|
| 151 |
+
|
| 152 |
+
def _build_nets(self):
|
| 153 |
+
|
| 154 |
+
if self._add_weight_norm:
|
| 155 |
+
Journal.log(self.__class__.__name__,
|
| 156 |
+
"__init__",
|
| 157 |
+
f"Will use weight normalization reparametrization\n",
|
| 158 |
+
LogType.INFO)
|
| 159 |
+
|
| 160 |
+
self.actor=None
|
| 161 |
+
self.qf1=None
|
| 162 |
+
self.qf2=None
|
| 163 |
+
self.qf1_target=None
|
| 164 |
+
self.qf2_target=None
|
| 165 |
+
|
| 166 |
+
self.actor = Actor(obs_dim=self._obs_dim,
|
| 167 |
+
actions_dim=self._actions_dim,
|
| 168 |
+
actions_ub=self._actions_ub,
|
| 169 |
+
actions_lb=self._actions_lb,
|
| 170 |
+
device=self._torch_device,
|
| 171 |
+
dtype=self._torch_dtype,
|
| 172 |
+
layer_width=self._layer_width_actor,
|
| 173 |
+
n_hidden_layers=self._n_hidden_layers_actor,
|
| 174 |
+
add_weight_norm=self._add_weight_norm,
|
| 175 |
+
add_layer_norm=self._add_layer_norm,
|
| 176 |
+
add_batch_norm=self._add_batch_norm,
|
| 177 |
+
)
|
| 178 |
+
|
| 179 |
+
if (not self._is_eval) or self._load_qf: # just needed for training or during eval
|
| 180 |
+
# for debug, if enabled
|
| 181 |
+
self.qf1 = CriticQ(obs_dim=self._obs_dim,
|
| 182 |
+
actions_dim=self._actions_dim,
|
| 183 |
+
device=self._torch_device,
|
| 184 |
+
dtype=self._torch_dtype,
|
| 185 |
+
layer_width=self._layer_width_critic,
|
| 186 |
+
n_hidden_layers=self._n_hidden_layers_critic,
|
| 187 |
+
add_weight_norm=self._add_weight_norm,
|
| 188 |
+
add_layer_norm=self._add_layer_norm,
|
| 189 |
+
add_batch_norm=self._add_batch_norm)
|
| 190 |
+
self.qf1_target = CriticQ(obs_dim=self._obs_dim,
|
| 191 |
+
actions_dim=self._actions_dim,
|
| 192 |
+
device=self._torch_device,
|
| 193 |
+
dtype=self._torch_dtype,
|
| 194 |
+
layer_width=self._layer_width_critic,
|
| 195 |
+
n_hidden_layers=self._n_hidden_layers_critic,
|
| 196 |
+
add_weight_norm=self._add_weight_norm,
|
| 197 |
+
add_layer_norm=self._add_layer_norm,
|
| 198 |
+
add_batch_norm=self._add_batch_norm)
|
| 199 |
+
|
| 200 |
+
self.qf2 = CriticQ(obs_dim=self._obs_dim,
|
| 201 |
+
actions_dim=self._actions_dim,
|
| 202 |
+
device=self._torch_device,
|
| 203 |
+
dtype=self._torch_dtype,
|
| 204 |
+
layer_width=self._layer_width_critic,
|
| 205 |
+
n_hidden_layers=self._n_hidden_layers_critic,
|
| 206 |
+
add_weight_norm=self._add_weight_norm,
|
| 207 |
+
add_layer_norm=self._add_layer_norm,
|
| 208 |
+
add_batch_norm=self._add_batch_norm)
|
| 209 |
+
self.qf2_target = CriticQ(obs_dim=self._obs_dim,
|
| 210 |
+
actions_dim=self._actions_dim,
|
| 211 |
+
device=self._torch_device,
|
| 212 |
+
dtype=self._torch_dtype,
|
| 213 |
+
layer_width=self._layer_width_critic,
|
| 214 |
+
n_hidden_layers=self._n_hidden_layers_critic,
|
| 215 |
+
add_weight_norm=self._add_weight_norm,
|
| 216 |
+
add_layer_norm=self._add_layer_norm,
|
| 217 |
+
add_batch_norm=self._add_batch_norm)
|
| 218 |
+
|
| 219 |
+
self.qf1_target.load_state_dict(self.qf1.state_dict())
|
| 220 |
+
self.qf2_target.load_state_dict(self.qf2.state_dict())
|
| 221 |
+
|
| 222 |
+
if self._use_torch_compile:
|
| 223 |
+
self.obs_running_norm=torch.compile(self.obs_running_norm)
|
| 224 |
+
self.actor = torch.compile(self.actor)
|
| 225 |
+
if (not self._is_eval) or self._load_qf:
|
| 226 |
+
self.qf1 = torch.compile(self.qf1)
|
| 227 |
+
self.qf2 = torch.compile(self.qf2)
|
| 228 |
+
self.qf1_target = torch.compile(self.qf1_target)
|
| 229 |
+
self.qf2_target = torch.compile(self.qf2_target)
|
| 230 |
+
|
| 231 |
+
def reset(self, reset_stats: bool = False):
|
| 232 |
+
# we should just reinitialize the parameters, but for easiness
|
| 233 |
+
# we recreate the networks
|
| 234 |
+
|
| 235 |
+
# force deallocation of objects
|
| 236 |
+
import gc
|
| 237 |
+
del self.actor
|
| 238 |
+
del self.qf1
|
| 239 |
+
del self.qf2
|
| 240 |
+
del self.qf1_target
|
| 241 |
+
del self.qf2_target
|
| 242 |
+
gc.collect()
|
| 243 |
+
|
| 244 |
+
self._build_nets()
|
| 245 |
+
|
| 246 |
+
if reset_stats: # we also reinitialize obs norm
|
| 247 |
+
self._init_obs_norm()
|
| 248 |
+
|
| 249 |
+
# self.obs_running_norm.reset()
|
| 250 |
+
|
| 251 |
+
def layer_width_actor(self):
|
| 252 |
+
return self._layer_width_actor
|
| 253 |
+
|
| 254 |
+
def n_hidden_layers_actor(self):
|
| 255 |
+
return self._n_hidden_layers_actor
|
| 256 |
+
|
| 257 |
+
def layer_width_critic(self):
|
| 258 |
+
return self._layer_width_critic
|
| 259 |
+
|
| 260 |
+
def n_hidden_layers_critic(self):
|
| 261 |
+
return self._n_hidden_layers_critic
|
| 262 |
+
|
| 263 |
+
def get_impl_path(self):
|
| 264 |
+
import os
|
| 265 |
+
return os.path.abspath(__file__)
|
| 266 |
+
|
| 267 |
+
def update_obs_bnorm(self, x):
|
| 268 |
+
self.obs_running_norm.unfreeze()
|
| 269 |
+
self.obs_running_norm.manual_stat_update(x)
|
| 270 |
+
self.obs_running_norm.freeze()
|
| 271 |
+
|
| 272 |
+
def _obs_scaling_layer(self, x):
|
| 273 |
+
x=(x-self.obs_bias)
|
| 274 |
+
x=x/(self.obs_scale+self._rescaling_epsi)
|
| 275 |
+
return x
|
| 276 |
+
|
| 277 |
+
def _preprocess_obs(self, x):
|
| 278 |
+
if self._rescale_obs:
|
| 279 |
+
x = self._obs_scaling_layer(x)
|
| 280 |
+
if self.obs_running_norm is not None:
|
| 281 |
+
x = self.obs_running_norm(x)
|
| 282 |
+
return x
|
| 283 |
+
|
| 284 |
+
def _preprocess_actions(self, a):
|
| 285 |
+
if self._use_action_rescale_for_critic:
|
| 286 |
+
a=self.actor.remove_scaling(a=a) # rescale to be in range [-1, 1]
|
| 287 |
+
return a
|
| 288 |
+
|
| 289 |
+
def get_action(self, x):
|
| 290 |
+
x = self._preprocess_obs(x)
|
| 291 |
+
return self.actor.get_action(x)
|
| 292 |
+
|
| 293 |
+
def get_qf1_val(self, x, a):
|
| 294 |
+
x = self._preprocess_obs(x)
|
| 295 |
+
a = self._preprocess_actions(a)
|
| 296 |
+
return self.qf1(x, a)
|
| 297 |
+
|
| 298 |
+
def get_qf2_val(self, x, a):
|
| 299 |
+
x = self._preprocess_obs(x)
|
| 300 |
+
a = self._preprocess_actions(a)
|
| 301 |
+
return self.qf2(x, a)
|
| 302 |
+
|
| 303 |
+
def get_qf1t_val(self, x, a):
|
| 304 |
+
x = self._preprocess_obs(x)
|
| 305 |
+
a = self._preprocess_actions(a)
|
| 306 |
+
return self.qf1_target(x, a)
|
| 307 |
+
|
| 308 |
+
def get_qf2t_val(self, x, a):
|
| 309 |
+
x = self._preprocess_obs(x)
|
| 310 |
+
a = self._preprocess_actions(a)
|
| 311 |
+
return self.qf2_target(x, a)
|
| 312 |
+
|
| 313 |
+
def load_state_dict(self, param_dict):
|
| 314 |
+
|
| 315 |
+
missing, unexpected = super().load_state_dict(param_dict,
|
| 316 |
+
strict=False)
|
| 317 |
+
if not len(missing)==0:
|
| 318 |
+
Journal.log(self.__class__.__name__,
|
| 319 |
+
"load_state_dict",
|
| 320 |
+
f"These parameters are missing from the provided state dictionary: {str(missing)}\n",
|
| 321 |
+
LogType.EXCEP,
|
| 322 |
+
throw_when_excep = True)
|
| 323 |
+
if not len(unexpected)==0:
|
| 324 |
+
Journal.log(self.__class__.__name__,
|
| 325 |
+
"load_state_dict",
|
| 326 |
+
f"These parameters present in the provided state dictionary are not needed: {str(unexpected)}\n",
|
| 327 |
+
LogType.WARN)
|
| 328 |
+
|
| 329 |
+
# sanity check on running normalizer
|
| 330 |
+
import re
|
| 331 |
+
running_norm_pattern = r"running_norm"
|
| 332 |
+
error=f"Found some keys in model state dictionary associated with a running normalizer. Are you running the agent with norm_obs=True?\n"
|
| 333 |
+
if any(re.match(running_norm_pattern, key) for key in unexpected):
|
| 334 |
+
Journal.log(self.__class__.__name__,
|
| 335 |
+
"load_state_dict",
|
| 336 |
+
error,
|
| 337 |
+
LogType.EXCEP,
|
| 338 |
+
throw_when_excep=True)
|
| 339 |
+
|
| 340 |
+
class CriticQ(nn.Module):
|
| 341 |
+
def __init__(self,
|
| 342 |
+
obs_dim: int,
|
| 343 |
+
actions_dim: int,
|
| 344 |
+
device: str = "cuda",
|
| 345 |
+
dtype = torch.float32,
|
| 346 |
+
layer_width: int = 512,
|
| 347 |
+
n_hidden_layers: int = 4,
|
| 348 |
+
add_weight_norm: bool = False,
|
| 349 |
+
add_layer_norm: bool = False,
|
| 350 |
+
add_batch_norm: bool = False):
|
| 351 |
+
|
| 352 |
+
super().__init__()
|
| 353 |
+
|
| 354 |
+
self._lrelu_slope=0.01
|
| 355 |
+
|
| 356 |
+
self._torch_device = device
|
| 357 |
+
self._torch_dtype = dtype
|
| 358 |
+
|
| 359 |
+
self._obs_dim = obs_dim
|
| 360 |
+
self._actions_dim = actions_dim
|
| 361 |
+
self._q_net_dim = self._obs_dim + self._actions_dim
|
| 362 |
+
|
| 363 |
+
self._first_hidden_layer_width=self._q_net_dim # fist layer fully connected and of same dim
|
| 364 |
+
# as input
|
| 365 |
+
|
| 366 |
+
init_type="kaiming_uniform" # maintains the variance of activations throughout the network
|
| 367 |
+
nonlinearity="leaky_relu" # suited for kaiming
|
| 368 |
+
|
| 369 |
+
# Input layer
|
| 370 |
+
layers=llayer_init(
|
| 371 |
+
layer=nn.Linear(self._q_net_dim, self._first_hidden_layer_width),
|
| 372 |
+
init_type=init_type,
|
| 373 |
+
nonlinearity=nonlinearity,
|
| 374 |
+
a_leaky_relu=self._lrelu_slope,
|
| 375 |
+
device=self._torch_device,
|
| 376 |
+
dtype=self._torch_dtype,
|
| 377 |
+
add_weight_norm=add_weight_norm,
|
| 378 |
+
add_layer_norm=add_layer_norm,
|
| 379 |
+
add_batch_norm=add_batch_norm,
|
| 380 |
+
uniform_biases=False, # constant bias init
|
| 381 |
+
bias_const=0.0
|
| 382 |
+
)
|
| 383 |
+
layers.extend([nn.LeakyReLU(negative_slope=self._lrelu_slope)])
|
| 384 |
+
|
| 385 |
+
# Hidden layers
|
| 386 |
+
layers.extend(
|
| 387 |
+
llayer_init(
|
| 388 |
+
layer=nn.Linear(self._first_hidden_layer_width, layer_width),
|
| 389 |
+
init_type=init_type,
|
| 390 |
+
nonlinearity=nonlinearity,
|
| 391 |
+
a_leaky_relu=self._lrelu_slope,
|
| 392 |
+
device=self._torch_device,
|
| 393 |
+
dtype=self._torch_dtype,
|
| 394 |
+
add_weight_norm=add_weight_norm,
|
| 395 |
+
add_layer_norm=add_layer_norm,
|
| 396 |
+
add_batch_norm=add_batch_norm,
|
| 397 |
+
uniform_biases=False, # constant bias init
|
| 398 |
+
bias_const=0.0
|
| 399 |
+
)
|
| 400 |
+
)
|
| 401 |
+
layers.extend([nn.LeakyReLU(negative_slope=self._lrelu_slope)])
|
| 402 |
+
|
| 403 |
+
for _ in range(n_hidden_layers - 1):
|
| 404 |
+
layers.extend(
|
| 405 |
+
llayer_init(
|
| 406 |
+
layer=nn.Linear(layer_width, layer_width),
|
| 407 |
+
init_type=init_type,
|
| 408 |
+
nonlinearity=nonlinearity,
|
| 409 |
+
a_leaky_relu=self._lrelu_slope,
|
| 410 |
+
device=self._torch_device,
|
| 411 |
+
dtype=self._torch_dtype,
|
| 412 |
+
add_weight_norm=add_weight_norm,
|
| 413 |
+
add_layer_norm=add_layer_norm,
|
| 414 |
+
add_batch_norm=add_batch_norm,
|
| 415 |
+
uniform_biases=False, # constant bias init
|
| 416 |
+
bias_const=0.0
|
| 417 |
+
)
|
| 418 |
+
)
|
| 419 |
+
layers.extend([nn.LeakyReLU(negative_slope=self._lrelu_slope)])
|
| 420 |
+
|
| 421 |
+
# Output layer
|
| 422 |
+
layers.extend(
|
| 423 |
+
llayer_init(
|
| 424 |
+
layer=nn.Linear(layer_width, 1),
|
| 425 |
+
init_type="uniform",
|
| 426 |
+
uniform_biases=False, # contact biases
|
| 427 |
+
bias_const=-0.1, # negative to prevent overestimation
|
| 428 |
+
scale_weight=1e-2,
|
| 429 |
+
device=self._torch_device,
|
| 430 |
+
dtype=self._torch_dtype,
|
| 431 |
+
add_weight_norm=False,
|
| 432 |
+
add_layer_norm=False,
|
| 433 |
+
add_batch_norm=False
|
| 434 |
+
)
|
| 435 |
+
)
|
| 436 |
+
|
| 437 |
+
# Creating the full sequential network
|
| 438 |
+
self._q_net = nn.Sequential(*layers)
|
| 439 |
+
self._q_net.to(self._torch_device).type(self._torch_dtype)
|
| 440 |
+
|
| 441 |
+
print("Critic architecture")
|
| 442 |
+
print(self._q_net)
|
| 443 |
+
|
| 444 |
+
def get_n_params(self):
|
| 445 |
+
return sum(p.numel() for p in self.parameters())
|
| 446 |
+
|
| 447 |
+
def forward(self, x, a):
|
| 448 |
+
x = torch.cat([x, a], dim=1)
|
| 449 |
+
return self._q_net(x)
|
| 450 |
+
|
| 451 |
+
class Actor(nn.Module):
|
| 452 |
+
def __init__(self,
|
| 453 |
+
obs_dim: int,
|
| 454 |
+
actions_dim: int,
|
| 455 |
+
actions_ub: List[float] = None,
|
| 456 |
+
actions_lb: List[float] = None,
|
| 457 |
+
device: str = "cuda",
|
| 458 |
+
dtype = torch.float32,
|
| 459 |
+
layer_width: int = 256,
|
| 460 |
+
n_hidden_layers: int = 2,
|
| 461 |
+
add_weight_norm: bool = False,
|
| 462 |
+
add_layer_norm: bool = False,
|
| 463 |
+
add_batch_norm: bool = False):
|
| 464 |
+
|
| 465 |
+
super().__init__()
|
| 466 |
+
|
| 467 |
+
self._lrelu_slope=0.01
|
| 468 |
+
|
| 469 |
+
self._torch_device = device
|
| 470 |
+
self._torch_dtype = dtype
|
| 471 |
+
|
| 472 |
+
self._obs_dim = obs_dim
|
| 473 |
+
self._actions_dim = actions_dim
|
| 474 |
+
|
| 475 |
+
self._first_hidden_layer_width=self._obs_dim # fist layer fully connected and of same dim
|
| 476 |
+
|
| 477 |
+
# Action scale and bias
|
| 478 |
+
if actions_ub is None:
|
| 479 |
+
actions_ub = [1] * actions_dim
|
| 480 |
+
if actions_lb is None:
|
| 481 |
+
actions_lb = [-1] * actions_dim
|
| 482 |
+
if (len(actions_ub) != actions_dim):
|
| 483 |
+
Journal.log(self.__class__.__name__,
|
| 484 |
+
"__init__",
|
| 485 |
+
f"Actions ub list length should be equal to {actions_dim}, but got {len(actions_ub)}",
|
| 486 |
+
LogType.EXCEP,
|
| 487 |
+
throw_when_excep = True)
|
| 488 |
+
if (len(actions_lb) != actions_dim):
|
| 489 |
+
Journal.log(self.__class__.__name__,
|
| 490 |
+
"__init__",
|
| 491 |
+
f"Actions lb list length should be equal to {actions_dim}, but got {len(actions_lb)}",
|
| 492 |
+
LogType.EXCEP,
|
| 493 |
+
throw_when_excep = True)
|
| 494 |
+
|
| 495 |
+
self._actions_ub = torch.tensor(actions_ub, dtype=self._torch_dtype,
|
| 496 |
+
device=self._torch_device)
|
| 497 |
+
self._actions_lb = torch.tensor(actions_lb, dtype=self._torch_dtype,
|
| 498 |
+
device=self._torch_device)
|
| 499 |
+
action_scale = torch.full((actions_dim, ),
|
| 500 |
+
fill_value=0.0,
|
| 501 |
+
dtype=self._torch_dtype,
|
| 502 |
+
device=self._torch_device)
|
| 503 |
+
action_scale[:] = (self._actions_ub-self._actions_lb)/2.0
|
| 504 |
+
self.register_buffer(
|
| 505 |
+
"action_scale", action_scale
|
| 506 |
+
)
|
| 507 |
+
actions_bias = torch.full((actions_dim, ),
|
| 508 |
+
fill_value=0.0,
|
| 509 |
+
dtype=self._torch_dtype,
|
| 510 |
+
device=self._torch_device)
|
| 511 |
+
actions_bias[:] = (self._actions_ub+self._actions_lb)/2.0
|
| 512 |
+
self.register_buffer(
|
| 513 |
+
"action_bias", actions_bias)
|
| 514 |
+
|
| 515 |
+
# Network configuration
|
| 516 |
+
self.LOG_STD_MAX = 2
|
| 517 |
+
self.LOG_STD_MIN = -5
|
| 518 |
+
|
| 519 |
+
# Input layer followed by hidden layers
|
| 520 |
+
layers=llayer_init(nn.Linear(self._obs_dim, self._first_hidden_layer_width),
|
| 521 |
+
init_type="kaiming_uniform",
|
| 522 |
+
nonlinearity="leaky_relu",
|
| 523 |
+
a_leaky_relu=self._lrelu_slope,
|
| 524 |
+
device=self._torch_device,
|
| 525 |
+
dtype=self._torch_dtype,
|
| 526 |
+
add_weight_norm=add_weight_norm,
|
| 527 |
+
add_layer_norm=add_layer_norm,
|
| 528 |
+
add_batch_norm=add_batch_norm,
|
| 529 |
+
uniform_biases=False, # constant bias init
|
| 530 |
+
bias_const=0.0
|
| 531 |
+
)
|
| 532 |
+
layers.extend([nn.LeakyReLU(negative_slope=self._lrelu_slope)])
|
| 533 |
+
|
| 534 |
+
# Hidden layers
|
| 535 |
+
layers.extend(
|
| 536 |
+
llayer_init(nn.Linear(self._first_hidden_layer_width, layer_width),
|
| 537 |
+
init_type="kaiming_uniform",
|
| 538 |
+
nonlinearity="leaky_relu",
|
| 539 |
+
a_leaky_relu=self._lrelu_slope,
|
| 540 |
+
device=self._torch_device,
|
| 541 |
+
dtype=self._torch_dtype,
|
| 542 |
+
add_weight_norm=add_weight_norm,
|
| 543 |
+
add_layer_norm=add_layer_norm,
|
| 544 |
+
add_batch_norm=add_batch_norm,
|
| 545 |
+
uniform_biases=False, # constant bias init
|
| 546 |
+
bias_const=0.0)
|
| 547 |
+
)
|
| 548 |
+
layers.extend([nn.LeakyReLU(negative_slope=self._lrelu_slope)])
|
| 549 |
+
|
| 550 |
+
for _ in range(n_hidden_layers - 1):
|
| 551 |
+
layers.extend(
|
| 552 |
+
llayer_init(nn.Linear(layer_width, layer_width),
|
| 553 |
+
init_type="kaiming_uniform",
|
| 554 |
+
nonlinearity="leaky_relu",
|
| 555 |
+
a_leaky_relu=self._lrelu_slope,
|
| 556 |
+
device=self._torch_device,
|
| 557 |
+
dtype=self._torch_dtype,
|
| 558 |
+
add_weight_norm=add_weight_norm,
|
| 559 |
+
add_layer_norm=add_layer_norm,
|
| 560 |
+
add_batch_norm=add_batch_norm,
|
| 561 |
+
uniform_biases=False, # constant bias init
|
| 562 |
+
bias_const=0.0)
|
| 563 |
+
)
|
| 564 |
+
layers.extend([nn.LeakyReLU(negative_slope=self._lrelu_slope)])
|
| 565 |
+
|
| 566 |
+
# Sequential layers for the feature extractor
|
| 567 |
+
self._fc12 = nn.Sequential(*layers)
|
| 568 |
+
|
| 569 |
+
# Mean and log_std layers
|
| 570 |
+
out_fc_mean=llayer_init(nn.Linear(layer_width, self._actions_dim),
|
| 571 |
+
init_type="uniform",
|
| 572 |
+
uniform_biases=False, # constant bias init
|
| 573 |
+
bias_const=0.0,
|
| 574 |
+
scale_weight=1e-3, # scaling (output layer)
|
| 575 |
+
scale_bias=1.0,
|
| 576 |
+
device=self._torch_device,
|
| 577 |
+
dtype=self._torch_dtype,
|
| 578 |
+
add_weight_norm=False,
|
| 579 |
+
add_layer_norm=False,
|
| 580 |
+
add_batch_norm=False
|
| 581 |
+
)
|
| 582 |
+
self.fc_mean = nn.Sequential(*out_fc_mean)
|
| 583 |
+
out_fc_logstd= llayer_init(nn.Linear(layer_width, self._actions_dim),
|
| 584 |
+
init_type="uniform",
|
| 585 |
+
uniform_biases=False,
|
| 586 |
+
bias_const=math.log(0.5),
|
| 587 |
+
scale_weight=1e-3, # scaling (output layer)
|
| 588 |
+
scale_bias=1.0,
|
| 589 |
+
device=self._torch_device,
|
| 590 |
+
dtype=self._torch_dtype,
|
| 591 |
+
add_weight_norm=False,
|
| 592 |
+
add_layer_norm=False,
|
| 593 |
+
add_batch_norm=False,
|
| 594 |
+
)
|
| 595 |
+
self.fc_logstd = nn.Sequential(*out_fc_logstd)
|
| 596 |
+
|
| 597 |
+
# Move all components to the specified device and dtype
|
| 598 |
+
self._fc12.to(device=self._torch_device, dtype=self._torch_dtype)
|
| 599 |
+
self.fc_mean.to(device=self._torch_device, dtype=self._torch_dtype)
|
| 600 |
+
self.fc_logstd.to(device=self._torch_device, dtype=self._torch_dtype)
|
| 601 |
+
|
| 602 |
+
print("Actor architecture")
|
| 603 |
+
print(self._fc12)
|
| 604 |
+
print(self.fc_mean)
|
| 605 |
+
print(self.fc_logstd)
|
| 606 |
+
|
| 607 |
+
def get_n_params(self):
|
| 608 |
+
return sum(p.numel() for p in self.parameters())
|
| 609 |
+
|
| 610 |
+
def forward(self, x):
|
| 611 |
+
x = self._fc12(x)
|
| 612 |
+
mean = self.fc_mean(x)
|
| 613 |
+
log_std = self.fc_logstd(x)
|
| 614 |
+
log_std = torch.tanh(log_std)
|
| 615 |
+
log_std = self.LOG_STD_MIN + 0.5 * (self.LOG_STD_MAX - self.LOG_STD_MIN) * (log_std + 1) # From SpinUp / Denis Yarats
|
| 616 |
+
return mean, log_std
|
| 617 |
+
|
| 618 |
+
def get_action(self, x):
|
| 619 |
+
mean, log_std = self(x)
|
| 620 |
+
std = log_std.exp()
|
| 621 |
+
normal = torch.distributions.Normal(mean, std)
|
| 622 |
+
x_t = normal.rsample() # Reparameterization trick (for SAC we neex action
|
| 623 |
+
# to be differentible since we use Q nets. Using sample() would break the
|
| 624 |
+
# comp. graph and not allow gradients to flow)
|
| 625 |
+
y_t = torch.tanh(x_t)
|
| 626 |
+
action = y_t * self.action_scale + self.action_bias
|
| 627 |
+
log_prob_vec = normal.log_prob(x_t) # per-dimension log prob before tanh
|
| 628 |
+
log_prob_vec = log_prob_vec - torch.log(self.action_scale * (1 - y_t.pow(2)) + 1e-6) # tanh Jacobian + scaling
|
| 629 |
+
log_prob_sum = log_prob_vec.sum(1, keepdim=True)
|
| 630 |
+
mean = torch.tanh(mean) * self.action_scale + self.action_bias
|
| 631 |
+
return action, (log_prob_sum, log_prob_vec), mean
|
| 632 |
+
|
| 633 |
+
def remove_scaling(self, a):
|
| 634 |
+
return (a - self.action_bias)/self.action_scale
|
| 635 |
+
|
| 636 |
+
if __name__ == "__main__":
|
| 637 |
+
device = "cpu" # or "cpu"
|
| 638 |
+
import time
|
| 639 |
+
obs_dim = 273
|
| 640 |
+
agent = SACAgent(
|
| 641 |
+
obs_dim=obs_dim,
|
| 642 |
+
actions_dim=10,
|
| 643 |
+
actions_lb=None,
|
| 644 |
+
actions_ub=None,
|
| 645 |
+
obs_lb=None,
|
| 646 |
+
obs_ub=None,
|
| 647 |
+
rescale_obs=False,
|
| 648 |
+
norm_obs=True,
|
| 649 |
+
use_action_rescale_for_critic=True,
|
| 650 |
+
is_eval=True,
|
| 651 |
+
compression_ratio=0.6,
|
| 652 |
+
layer_width_actor=128,
|
| 653 |
+
layer_width_critic=256,
|
| 654 |
+
n_hidden_layers_actor=3,
|
| 655 |
+
n_hidden_layers_critic=3,
|
| 656 |
+
device=device,
|
| 657 |
+
dtype=torch.float32,
|
| 658 |
+
add_weight_norm=True,
|
| 659 |
+
add_layer_norm=False,
|
| 660 |
+
add_batch_norm=False
|
| 661 |
+
)
|
| 662 |
+
|
| 663 |
+
n_samples = 10000
|
| 664 |
+
random_obs = torch.rand((1, obs_dim), dtype=torch.float32, device=device)
|
| 665 |
+
|
| 666 |
+
if device == "cuda":
|
| 667 |
+
torch.cuda.synchronize()
|
| 668 |
+
start = time.time()
|
| 669 |
+
|
| 670 |
+
for i in range(n_samples):
|
| 671 |
+
actions, _, mean = agent.get_action(x=random_obs)
|
| 672 |
+
actions = actions.detach()
|
| 673 |
+
actions[:, :] = mean.detach()
|
| 674 |
+
|
| 675 |
+
if device == "cuda":
|
| 676 |
+
torch.cuda.synchronize()
|
| 677 |
+
end = time.time()
|
| 678 |
+
|
| 679 |
+
avrg_eval_time = (end - start) / n_samples
|
| 680 |
+
print(f"Average policy evaluation time on {device}: {avrg_eval_time:.6f} s")
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/sactor_critic_algo.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/training_env_base.py
ADDED
|
@@ -0,0 +1,2000 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import math
|
| 3 |
+
from aug_mpc.utils.math_utils import quaternion_to_angular_velocity, quaternion_difference
|
| 4 |
+
|
| 5 |
+
from mpc_hive.utilities.shared_data.rhc_data import RobotState
|
| 6 |
+
from mpc_hive.utilities.shared_data.rhc_data import RhcCmds, RhcPred
|
| 7 |
+
from mpc_hive.utilities.shared_data.rhc_data import RhcRefs
|
| 8 |
+
from mpc_hive.utilities.shared_data.rhc_data import RhcStatus
|
| 9 |
+
from mpc_hive.utilities.shared_data.sim_data import SharedEnvInfo
|
| 10 |
+
|
| 11 |
+
from aug_mpc.utils.shared_data.remote_stepping import RemoteStepperSrvr
|
| 12 |
+
from aug_mpc.utils.shared_data.remote_stepping import RemoteResetSrvr
|
| 13 |
+
from aug_mpc.utils.shared_data.remote_stepping import RemoteResetRequest
|
| 14 |
+
|
| 15 |
+
from aug_mpc.utils.shared_data.agent_refs import AgentRefs
|
| 16 |
+
from aug_mpc.utils.shared_data.training_env import SharedTrainingEnvInfo
|
| 17 |
+
|
| 18 |
+
from aug_mpc.utils.shared_data.training_env import Observations, NextObservations
|
| 19 |
+
from aug_mpc.utils.shared_data.training_env import TotRewards
|
| 20 |
+
from aug_mpc.utils.shared_data.training_env import SubRewards
|
| 21 |
+
from aug_mpc.utils.shared_data.training_env import Actions
|
| 22 |
+
from aug_mpc.utils.shared_data.training_env import Terminations, SubTerminations
|
| 23 |
+
from aug_mpc.utils.shared_data.training_env import Truncations, SubTruncations
|
| 24 |
+
from aug_mpc.utils.shared_data.training_env import EpisodesCounter,TaskRandCounter,SafetyRandResetsCounter,RandomTruncCounter,SubStepAbsCounter
|
| 25 |
+
|
| 26 |
+
from aug_mpc.utils.episodic_rewards import EpisodicRewards
|
| 27 |
+
from aug_mpc.utils.episodic_data import EpisodicData
|
| 28 |
+
from aug_mpc.utils.episodic_data import MemBuffer
|
| 29 |
+
from aug_mpc.utils.signal_smoother import ExponentialSignalSmoother
|
| 30 |
+
from aug_mpc.utils.math_utils import check_capsize
|
| 31 |
+
|
| 32 |
+
from mpc_hive.utilities.math_utils_torch import world2base_frame
|
| 33 |
+
|
| 34 |
+
from EigenIPC.PyEigenIPC import VLevel
|
| 35 |
+
from EigenIPC.PyEigenIPC import LogType
|
| 36 |
+
from EigenIPC.PyEigenIPC import Journal
|
| 37 |
+
from EigenIPC.PyEigenIPC import StringTensorClient
|
| 38 |
+
|
| 39 |
+
from perf_sleep.pyperfsleep import PerfSleep
|
| 40 |
+
|
| 41 |
+
from abc import abstractmethod, ABC
|
| 42 |
+
|
| 43 |
+
import os
|
| 44 |
+
from typing import List, Dict
|
| 45 |
+
|
| 46 |
+
class AugMPCTrainingEnvBase(ABC):
|
| 47 |
+
|
| 48 |
+
"""Base class for a remote training environment tailored to Learning-based Receding Horizon Control"""
|
| 49 |
+
|
| 50 |
+
def __init__(self,
|
| 51 |
+
namespace: str,
|
| 52 |
+
obs_dim: int,
|
| 53 |
+
actions_dim: int,
|
| 54 |
+
env_name: str = "",
|
| 55 |
+
verbose: bool = False,
|
| 56 |
+
vlevel: VLevel = VLevel.V1,
|
| 57 |
+
debug: bool = True,
|
| 58 |
+
use_gpu: bool = True,
|
| 59 |
+
dtype: torch.dtype = torch.float32,
|
| 60 |
+
override_agent_refs: bool = False,
|
| 61 |
+
timeout_ms: int = 60000,
|
| 62 |
+
env_opts: Dict = {}):
|
| 63 |
+
|
| 64 |
+
self._this_path = os.path.abspath(__file__)
|
| 65 |
+
|
| 66 |
+
self.custom_db_data = None
|
| 67 |
+
|
| 68 |
+
self._random_reset_active=False
|
| 69 |
+
|
| 70 |
+
self._action_smoother_continuous=None
|
| 71 |
+
self._action_smoother_discrete=None
|
| 72 |
+
|
| 73 |
+
self._closed = False
|
| 74 |
+
self._ready=False
|
| 75 |
+
|
| 76 |
+
self._namespace = namespace
|
| 77 |
+
self._with_gpu_mirror = True
|
| 78 |
+
self._safe_shared_mem = False
|
| 79 |
+
|
| 80 |
+
self._obs_dim = obs_dim
|
| 81 |
+
self._actions_dim = actions_dim
|
| 82 |
+
|
| 83 |
+
self._use_gpu = use_gpu
|
| 84 |
+
if self._use_gpu:
|
| 85 |
+
self._device="cuda"
|
| 86 |
+
else:
|
| 87 |
+
self._device="cpu"
|
| 88 |
+
|
| 89 |
+
self._dtype = dtype
|
| 90 |
+
|
| 91 |
+
self._verbose = verbose
|
| 92 |
+
self._vlevel = vlevel
|
| 93 |
+
|
| 94 |
+
self._is_debug = debug
|
| 95 |
+
|
| 96 |
+
self._env_name = env_name
|
| 97 |
+
|
| 98 |
+
self._override_agent_refs = override_agent_refs
|
| 99 |
+
|
| 100 |
+
self._substep_dt=1.0 # dt [s] between each substep
|
| 101 |
+
|
| 102 |
+
self._env_opts={}
|
| 103 |
+
self._env_opts.update(env_opts)
|
| 104 |
+
self._process_env_opts()
|
| 105 |
+
|
| 106 |
+
self._robot_state = None
|
| 107 |
+
self._rhc_cmds = None
|
| 108 |
+
self._rhc_pred = None
|
| 109 |
+
self._rhc_refs = None
|
| 110 |
+
self._rhc_status = None
|
| 111 |
+
|
| 112 |
+
self._remote_stepper = None
|
| 113 |
+
self._remote_resetter = None
|
| 114 |
+
self._remote_reset_req = None
|
| 115 |
+
|
| 116 |
+
self._agent_refs = None
|
| 117 |
+
|
| 118 |
+
self._n_envs = 0
|
| 119 |
+
|
| 120 |
+
self._ep_timeout_counter = None
|
| 121 |
+
self._task_rand_counter = None
|
| 122 |
+
self._rand_safety_reset_counter = None
|
| 123 |
+
self._rand_trunc_counter = None
|
| 124 |
+
|
| 125 |
+
self._actions_map={} # to be used to hold info like action idxs
|
| 126 |
+
self._obs_map={}
|
| 127 |
+
|
| 128 |
+
self._obs = None
|
| 129 |
+
self._obs_ub = None
|
| 130 |
+
self._obs_lb = None
|
| 131 |
+
self._next_obs = None
|
| 132 |
+
self._actions = None
|
| 133 |
+
self._actual_actions = None
|
| 134 |
+
self._actions_ub = None
|
| 135 |
+
self._actions_lb = None
|
| 136 |
+
self._tot_rewards = None
|
| 137 |
+
self._sub_rewards = None
|
| 138 |
+
self._sub_terminations = None
|
| 139 |
+
self._sub_truncations = None
|
| 140 |
+
self._terminations = None
|
| 141 |
+
self._truncations = None
|
| 142 |
+
self._act_mem_buffer = None
|
| 143 |
+
|
| 144 |
+
self._episodic_rewards_metrics = None
|
| 145 |
+
|
| 146 |
+
self._timeout = timeout_ms
|
| 147 |
+
|
| 148 |
+
self._height_grid_size = None
|
| 149 |
+
self._height_flat_dim = 0
|
| 150 |
+
|
| 151 |
+
self._attach_to_shared_mem()
|
| 152 |
+
|
| 153 |
+
self._init_obs(obs_dim)
|
| 154 |
+
self._init_actions(actions_dim)
|
| 155 |
+
self._init_rewards()
|
| 156 |
+
self._init_terminations()
|
| 157 |
+
self._init_truncations()
|
| 158 |
+
self._init_custom_db_data()
|
| 159 |
+
|
| 160 |
+
self._demo_setup() # setup for demo envs
|
| 161 |
+
|
| 162 |
+
# to ensure maps are properly initialized
|
| 163 |
+
_ = self._get_action_names()
|
| 164 |
+
_ = self._get_obs_names()
|
| 165 |
+
_ = self._get_sub_trunc_names()
|
| 166 |
+
_ = self._get_sub_term_names()
|
| 167 |
+
|
| 168 |
+
self._set_substep_rew()
|
| 169 |
+
self._set_substep_obs()
|
| 170 |
+
|
| 171 |
+
self._custom_post_init()
|
| 172 |
+
|
| 173 |
+
# update actions scale and offset in case it was modified in _custom_post_init
|
| 174 |
+
self._actions_scale = (self._actions_ub - self._actions_lb)/2.0
|
| 175 |
+
self._actions_offset = (self._actions_ub + self._actions_lb)/2.0
|
| 176 |
+
|
| 177 |
+
if self._env_opts["use_action_smoothing"]:
|
| 178 |
+
self._init_action_smoothing()
|
| 179 |
+
|
| 180 |
+
self._ready=self._init_step()
|
| 181 |
+
|
| 182 |
+
def _add_env_opt(self,
|
| 183 |
+
opts: Dict,
|
| 184 |
+
name: str,
|
| 185 |
+
default):
|
| 186 |
+
|
| 187 |
+
if not name in opts:
|
| 188 |
+
opts[name]=default
|
| 189 |
+
|
| 190 |
+
def _process_env_opts(self, ):
|
| 191 |
+
|
| 192 |
+
self._check_for_env_opts("episode_timeout_lb", int)
|
| 193 |
+
self._check_for_env_opts("episode_timeout_ub", int)
|
| 194 |
+
self._check_for_env_opts("n_steps_task_rand_lb", int)
|
| 195 |
+
self._check_for_env_opts("n_steps_task_rand_ub", int)
|
| 196 |
+
self._check_for_env_opts("use_random_trunc", bool)
|
| 197 |
+
self._check_for_env_opts("random_trunc_freq", int)
|
| 198 |
+
self._check_for_env_opts("random_trunc_freq_delta", int)
|
| 199 |
+
self._check_for_env_opts("use_random_safety_reset", bool)
|
| 200 |
+
self._check_for_env_opts("random_reset_freq", int)
|
| 201 |
+
|
| 202 |
+
self._check_for_env_opts("action_repeat", int)
|
| 203 |
+
|
| 204 |
+
self._check_for_env_opts("n_preinit_steps", int)
|
| 205 |
+
|
| 206 |
+
self._check_for_env_opts("demo_envs_perc", float)
|
| 207 |
+
|
| 208 |
+
self._check_for_env_opts("vec_ep_freq_metrics_db", int)
|
| 209 |
+
|
| 210 |
+
self._check_for_env_opts("srew_drescaling", bool)
|
| 211 |
+
|
| 212 |
+
self._check_for_env_opts("use_action_history", bool)
|
| 213 |
+
self._check_for_env_opts("actions_history_size", int)
|
| 214 |
+
|
| 215 |
+
self._check_for_env_opts("use_action_smoothing", bool)
|
| 216 |
+
self._check_for_env_opts("smoothing_horizon_c", float)
|
| 217 |
+
self._check_for_env_opts("smoothing_horizon_d", float)
|
| 218 |
+
|
| 219 |
+
self._check_for_env_opts("add_heightmap_obs", bool)
|
| 220 |
+
|
| 221 |
+
# parse action repeat opt + get some sim information
|
| 222 |
+
if self._env_opts["action_repeat"] <=0:
|
| 223 |
+
self._env_opts["action_repeat"] = 1
|
| 224 |
+
self._action_repeat=self._env_opts["action_repeat"]
|
| 225 |
+
# parse remote sim info
|
| 226 |
+
sim_info = {}
|
| 227 |
+
sim_info_shared = SharedEnvInfo(namespace=self._namespace,
|
| 228 |
+
is_server=False,
|
| 229 |
+
safe=False,
|
| 230 |
+
verbose=self._verbose,
|
| 231 |
+
vlevel=self._vlevel)
|
| 232 |
+
sim_info_shared.run()
|
| 233 |
+
sim_info_keys = sim_info_shared.param_keys
|
| 234 |
+
sim_info_data = sim_info_shared.get().flatten()
|
| 235 |
+
for i in range(len(sim_info_keys)):
|
| 236 |
+
sim_info[sim_info_keys[i]] = sim_info_data[i]
|
| 237 |
+
if "substepping_dt" in sim_info_keys:
|
| 238 |
+
self._substep_dt=sim_info["substepping_dt"]
|
| 239 |
+
self._env_opts.update(sim_info)
|
| 240 |
+
|
| 241 |
+
self._env_opts["substep_dt"]=self._substep_dt
|
| 242 |
+
|
| 243 |
+
self._env_opts["override_agent_refs"]=self._override_agent_refs
|
| 244 |
+
|
| 245 |
+
self._env_opts["episode_timeout_lb"] = round(self._env_opts["episode_timeout_lb"]/self._action_repeat)
|
| 246 |
+
self._env_opts["episode_timeout_ub"] = round(self._env_opts["episode_timeout_ub"]/self._action_repeat)
|
| 247 |
+
|
| 248 |
+
self._env_opts["n_steps_task_rand_lb"] = round(self._env_opts["n_steps_task_rand_lb"]/self._action_repeat)
|
| 249 |
+
self._env_opts["n_steps_task_rand_ub"] = round(self._env_opts["n_steps_task_rand_ub"]/self._action_repeat)
|
| 250 |
+
|
| 251 |
+
if self._env_opts["random_reset_freq"] <=0:
|
| 252 |
+
self._env_opts["use_random_safety_reset"]=False
|
| 253 |
+
self._env_opts["random_reset_freq"]=-1
|
| 254 |
+
self._random_reset_active=self._env_opts["use_random_safety_reset"]
|
| 255 |
+
|
| 256 |
+
self._env_opts["random_trunc_freq"] = round(self._env_opts["random_trunc_freq"]/self._action_repeat)
|
| 257 |
+
self._env_opts["random_trunc_freq_delta"] = round(self._env_opts["random_trunc_freq_delta"]/self._action_repeat)
|
| 258 |
+
|
| 259 |
+
if self._env_opts["random_trunc_freq"] <=0:
|
| 260 |
+
self._env_opts["use_random_trunc"]=False
|
| 261 |
+
self._env_opts["random_trunc_freq"]=-1
|
| 262 |
+
|
| 263 |
+
self._full_db=False
|
| 264 |
+
if "full_env_db" in self._env_opts:
|
| 265 |
+
self._full_db=self._env_opts["full_env_db"]
|
| 266 |
+
|
| 267 |
+
def _check_for_env_opts(self,
|
| 268 |
+
name: str,
|
| 269 |
+
expected_type):
|
| 270 |
+
if not (name in self._env_opts):
|
| 271 |
+
Journal.log(self.__class__.__name__,
|
| 272 |
+
"_check_for_env_opts",
|
| 273 |
+
f"Required option {name} missing for env opts!",
|
| 274 |
+
LogType.EXCEP,
|
| 275 |
+
throw_when_excep=True)
|
| 276 |
+
if not isinstance(self._env_opts[name], expected_type):
|
| 277 |
+
Journal.log(self.__class__.__name__,
|
| 278 |
+
"_check_for_env_opts",
|
| 279 |
+
f"Option {name} in env opts is not of type {expected_type} (got {type(self._env_opts[name])})!",
|
| 280 |
+
LogType.EXCEP,
|
| 281 |
+
throw_when_excep=True)
|
| 282 |
+
|
| 283 |
+
def __del__(self):
|
| 284 |
+
|
| 285 |
+
self.close()
|
| 286 |
+
|
| 287 |
+
def _demo_setup(self):
|
| 288 |
+
|
| 289 |
+
self._demo_envs_idxs=None
|
| 290 |
+
self._demo_envs_idxs_bool=None
|
| 291 |
+
self._n_demo_envs=round(self._env_opts["demo_envs_perc"]*self._n_envs)
|
| 292 |
+
self._add_demos=False
|
| 293 |
+
if not self._n_demo_envs >0:
|
| 294 |
+
Journal.log(self.__class__.__name__,
|
| 295 |
+
"__init__",
|
| 296 |
+
"will not use demo environments",
|
| 297 |
+
LogType.INFO,
|
| 298 |
+
throw_when_excep=False)
|
| 299 |
+
else:
|
| 300 |
+
Journal.log(self.__class__.__name__,
|
| 301 |
+
"__init__",
|
| 302 |
+
f"Will run with {self._n_demo_envs} demonstration envs.",
|
| 303 |
+
LogType.INFO)
|
| 304 |
+
self._demo_envs_idxs = torch.randperm(self._n_envs, device=self._device)[:self._n_demo_envs]
|
| 305 |
+
self._demo_envs_idxs_bool=torch.full((self._n_envs, ), dtype=torch.bool, device=self._device,
|
| 306 |
+
fill_value=False)
|
| 307 |
+
self._demo_envs_idxs_bool[self._demo_envs_idxs]=True
|
| 308 |
+
|
| 309 |
+
self._init_demo_envs() # custom logic
|
| 310 |
+
|
| 311 |
+
demo_idxs_str=", ".join(map(str, self._demo_envs_idxs.tolist()))
|
| 312 |
+
Journal.log(self.__class__.__name__,
|
| 313 |
+
"__init__",
|
| 314 |
+
f"Demo env. indexes are [{demo_idxs_str}]",
|
| 315 |
+
LogType.INFO)
|
| 316 |
+
|
| 317 |
+
def env_opts(self):
|
| 318 |
+
return self._env_opts
|
| 319 |
+
|
| 320 |
+
def demo_env_idxs(self, get_bool: bool=False):
|
| 321 |
+
if get_bool:
|
| 322 |
+
return self._demo_envs_idxs_bool
|
| 323 |
+
else:
|
| 324 |
+
return self._demo_envs_idxs
|
| 325 |
+
|
| 326 |
+
def _init_demo_envs(self):
|
| 327 |
+
pass
|
| 328 |
+
|
| 329 |
+
def n_demo_envs(self):
|
| 330 |
+
return self._n_demo_envs
|
| 331 |
+
|
| 332 |
+
def demo_active(self):
|
| 333 |
+
return self._add_demos
|
| 334 |
+
|
| 335 |
+
def switch_demo(self, active: bool = False):
|
| 336 |
+
if self._demo_envs_idxs is not None:
|
| 337 |
+
self._add_demos=active
|
| 338 |
+
else:
|
| 339 |
+
Journal.log(self.__class__.__name__,
|
| 340 |
+
"switch_demo",
|
| 341 |
+
f"Cannot switch demostrations on. No demo envs available!",
|
| 342 |
+
LogType.EXCEP,
|
| 343 |
+
throw_when_excep=True)
|
| 344 |
+
|
| 345 |
+
def _get_this_file_path(self):
|
| 346 |
+
return self._this_path
|
| 347 |
+
|
| 348 |
+
def episode_timeout_bounds(self):
|
| 349 |
+
return self._env_opts["episode_timeout_lb"], self._env_opts["episode_timeout_ub"]
|
| 350 |
+
|
| 351 |
+
def task_rand_timeout_bounds(self):
|
| 352 |
+
return self._env_opts["n_steps_task_rand_lb"], self._env_opts["n_steps_task_rand_ub"]
|
| 353 |
+
|
| 354 |
+
def n_action_reps(self):
|
| 355 |
+
return self._action_repeat
|
| 356 |
+
|
| 357 |
+
def get_file_paths(self):
|
| 358 |
+
from aug_mpc.utils.sys_utils import PathsGetter
|
| 359 |
+
path_getter = PathsGetter()
|
| 360 |
+
base_paths = []
|
| 361 |
+
base_paths.append(self._get_this_file_path())
|
| 362 |
+
base_paths.append(path_getter.REMOTENVPATH)
|
| 363 |
+
for script_path in path_getter.SCRIPTSPATHS:
|
| 364 |
+
base_paths.append(script_path)
|
| 365 |
+
|
| 366 |
+
# rhc files
|
| 367 |
+
from EigenIPC.PyEigenIPC import StringTensorClient
|
| 368 |
+
from perf_sleep.pyperfsleep import PerfSleep
|
| 369 |
+
shared_rhc_shared_files = StringTensorClient(
|
| 370 |
+
basename="SharedRhcFilesDropDir",
|
| 371 |
+
name_space=self._namespace,
|
| 372 |
+
verbose=self._verbose,
|
| 373 |
+
vlevel=VLevel.V2)
|
| 374 |
+
shared_rhc_shared_files.run()
|
| 375 |
+
shared_rhc_files_vals=[""]*shared_rhc_shared_files.length()
|
| 376 |
+
while not shared_rhc_shared_files.read_vec(shared_rhc_files_vals, 0):
|
| 377 |
+
nsecs = 1000000000 # 1 sec
|
| 378 |
+
PerfSleep.thread_sleep(nsecs) # we just keep it alive
|
| 379 |
+
rhc_list=[]
|
| 380 |
+
for rhc_files in shared_rhc_files_vals:
|
| 381 |
+
file_list = rhc_files.split(", ")
|
| 382 |
+
rhc_list.extend(file_list)
|
| 383 |
+
rhc_list = list(set(rhc_list)) # removing duplicates
|
| 384 |
+
base_paths.extend(rhc_list)
|
| 385 |
+
|
| 386 |
+
# world interface files
|
| 387 |
+
get_world_interface_paths = self.get_world_interface_paths()
|
| 388 |
+
base_paths.extend(get_world_interface_paths)
|
| 389 |
+
return base_paths
|
| 390 |
+
|
| 391 |
+
def get_world_interface_paths(self):
|
| 392 |
+
paths = []
|
| 393 |
+
shared_world_iface_files = StringTensorClient(
|
| 394 |
+
basename="SharedWorldInterfaceFilesDropDir",
|
| 395 |
+
name_space=self._namespace,
|
| 396 |
+
verbose=self._verbose,
|
| 397 |
+
vlevel=VLevel.V2)
|
| 398 |
+
shared_world_iface_files.run()
|
| 399 |
+
world_iface_vals=[""]*shared_world_iface_files.length()
|
| 400 |
+
while not shared_world_iface_files.read_vec(world_iface_vals, 0):
|
| 401 |
+
nsecs = 1000000000 # 1 sec
|
| 402 |
+
PerfSleep.thread_sleep(nsecs) # keep alive while waiting
|
| 403 |
+
shared_world_iface_files.close()
|
| 404 |
+
for files in world_iface_vals:
|
| 405 |
+
if files == "":
|
| 406 |
+
continue
|
| 407 |
+
file_list = files.split(", ")
|
| 408 |
+
for f in file_list:
|
| 409 |
+
if f not in paths:
|
| 410 |
+
paths.append(f)
|
| 411 |
+
return paths
|
| 412 |
+
|
| 413 |
+
def get_aux_dir(self):
|
| 414 |
+
empty_list = []
|
| 415 |
+
return empty_list
|
| 416 |
+
|
| 417 |
+
def _init_step(self):
|
| 418 |
+
|
| 419 |
+
self._check_controllers_registered(retry=True)
|
| 420 |
+
self._activate_rhc_controllers()
|
| 421 |
+
|
| 422 |
+
# just an auxiliary tensor
|
| 423 |
+
initial_reset_aux = self._terminations.get_torch_mirror(gpu=self._use_gpu).clone()
|
| 424 |
+
initial_reset_aux[:, :] = True # we reset all sim envs first
|
| 425 |
+
init_step_ok=True
|
| 426 |
+
init_step_ok=self._remote_sim_step() and init_step_ok
|
| 427 |
+
if not init_step_ok:
|
| 428 |
+
return False
|
| 429 |
+
init_step_ok=self._remote_reset(reset_mask=initial_reset_aux) and init_step_ok
|
| 430 |
+
if not init_step_ok:
|
| 431 |
+
return False
|
| 432 |
+
|
| 433 |
+
for i in range(self._env_opts["n_preinit_steps"]): # perform some
|
| 434 |
+
# dummy remote env stepping to make sure to have meaningful
|
| 435 |
+
# initializations (doesn't increment step counter)
|
| 436 |
+
init_step_ok=self._remote_sim_step() and init_step_ok # 1 remote sim. step
|
| 437 |
+
if not init_step_ok:
|
| 438 |
+
return False
|
| 439 |
+
init_step_ok=self._send_remote_reset_req() and init_step_ok # fake reset request
|
| 440 |
+
if not init_step_ok:
|
| 441 |
+
return False
|
| 442 |
+
|
| 443 |
+
self.reset()
|
| 444 |
+
|
| 445 |
+
return init_step_ok
|
| 446 |
+
|
| 447 |
+
def _debug(self):
|
| 448 |
+
|
| 449 |
+
if self._use_gpu:
|
| 450 |
+
# using non_blocking which is not safe when GPU->CPU
|
| 451 |
+
self._obs.synch_mirror(from_gpu=True,non_blocking=True) # copy data from gpu to cpu view
|
| 452 |
+
self._next_obs.synch_mirror(from_gpu=True,non_blocking=True)
|
| 453 |
+
self._actions.synch_mirror(from_gpu=True,non_blocking=True)
|
| 454 |
+
self._truncations.synch_mirror(from_gpu=True,non_blocking=True)
|
| 455 |
+
self._sub_truncations.synch_mirror(from_gpu=True,non_blocking=True)
|
| 456 |
+
self._terminations.synch_mirror(from_gpu=True,non_blocking=True)
|
| 457 |
+
self._sub_terminations.synch_mirror(from_gpu=True,non_blocking=True)
|
| 458 |
+
self._tot_rewards.synch_mirror(from_gpu=True,non_blocking=True)
|
| 459 |
+
self._sub_rewards.synch_mirror(from_gpu=True,non_blocking=True)
|
| 460 |
+
# if we want reliable db data then we should synchronize data streams
|
| 461 |
+
torch.cuda.synchronize()
|
| 462 |
+
|
| 463 |
+
# copy CPU view on shared memory
|
| 464 |
+
self._obs.synch_all(read=False, retry=True)
|
| 465 |
+
self._next_obs.synch_all(read=False, retry=True)
|
| 466 |
+
self._actions.synch_all(read=False, retry=True)
|
| 467 |
+
self._tot_rewards.synch_all(read=False, retry=True)
|
| 468 |
+
self._sub_rewards.synch_all(read=False, retry=True)
|
| 469 |
+
self._truncations.synch_all(read=False, retry = True)
|
| 470 |
+
self._sub_truncations.synch_all(read=False, retry = True)
|
| 471 |
+
self._terminations.synch_all(read=False, retry = True)
|
| 472 |
+
self._sub_terminations.synch_all(read=False, retry = True)
|
| 473 |
+
|
| 474 |
+
self._debug_agent_refs()
|
| 475 |
+
|
| 476 |
+
def _debug_agent_refs(self):
|
| 477 |
+
if self._use_gpu:
|
| 478 |
+
if not self._override_agent_refs:
|
| 479 |
+
self._agent_refs.rob_refs.root_state.synch_mirror(from_gpu=True,non_blocking=False)
|
| 480 |
+
if not self._override_agent_refs:
|
| 481 |
+
self._agent_refs.rob_refs.root_state.synch_all(read=False, retry = True)
|
| 482 |
+
|
| 483 |
+
def _remote_sim_step(self):
|
| 484 |
+
|
| 485 |
+
self._remote_stepper.trigger() # triggers simulation + RHC
|
| 486 |
+
if not self._remote_stepper.wait_ack_from(1, self._timeout):
|
| 487 |
+
Journal.log(self.__class__.__name__,
|
| 488 |
+
"_remote_sim_step",
|
| 489 |
+
"Remote sim. env step ack not received within timeout",
|
| 490 |
+
LogType.EXCEP,
|
| 491 |
+
throw_when_excep = False)
|
| 492 |
+
return False
|
| 493 |
+
return True
|
| 494 |
+
|
| 495 |
+
def _remote_reset(self,
|
| 496 |
+
reset_mask: torch.Tensor = None):
|
| 497 |
+
|
| 498 |
+
reset_reqs = self._remote_reset_req.get_torch_mirror()
|
| 499 |
+
if reset_mask is None: # just send the signal to allow stepping, but do not reset any of
|
| 500 |
+
# the remote envs
|
| 501 |
+
reset_reqs[:, :] = False
|
| 502 |
+
else:
|
| 503 |
+
reset_reqs[:, :] = reset_mask # remotely reset envs corresponding to
|
| 504 |
+
# the mask (True--> to be reset)
|
| 505 |
+
self._remote_reset_req.synch_all(read=False, retry=True) # write on shared buffer
|
| 506 |
+
remote_reset_ok = self._send_remote_reset_req() # process remote request
|
| 507 |
+
|
| 508 |
+
if reset_mask is not None:
|
| 509 |
+
self._synch_state(gpu=self._use_gpu) # if some env was reset, we use _obs
|
| 510 |
+
# to hold the states, including resets, while _next_obs will always hold the
|
| 511 |
+
# state right after stepping the sim env
|
| 512 |
+
# (could be a bit more efficient, since in theory we only need to read the envs
|
| 513 |
+
# corresponding to the reset_mask)
|
| 514 |
+
|
| 515 |
+
|
| 516 |
+
return remote_reset_ok
|
| 517 |
+
|
| 518 |
+
def _send_remote_reset_req(self):
|
| 519 |
+
|
| 520 |
+
self._remote_resetter.trigger()
|
| 521 |
+
if not self._remote_resetter.wait_ack_from(1, self._timeout): # remote reset completed
|
| 522 |
+
Journal.log(self.__class__.__name__,
|
| 523 |
+
"_post_step",
|
| 524 |
+
"Remote reset did not complete within the prescribed timeout!",
|
| 525 |
+
LogType.EXCEP,
|
| 526 |
+
throw_when_excep = False)
|
| 527 |
+
return False
|
| 528 |
+
return True
|
| 529 |
+
|
| 530 |
+
def step(self,
|
| 531 |
+
action):
|
| 532 |
+
|
| 533 |
+
actions_norm = action.detach() # IMPORTANT: assumes actions are already normalized in [-1, 1]
|
| 534 |
+
|
| 535 |
+
actions = self._actions.get_torch_mirror(gpu=self._use_gpu) # will hold agent actions (real range)
|
| 536 |
+
|
| 537 |
+
# scale normalized actions to physical space before interfacing with controllers
|
| 538 |
+
actions[:, :] = actions_norm*self._actions_scale + self._actions_offset
|
| 539 |
+
|
| 540 |
+
self._override_actions_with_demo() # if necessary override some actions with expert demonstrations
|
| 541 |
+
# (getting actions with get_actions will return the modified actions tensor)
|
| 542 |
+
|
| 543 |
+
actions.clamp_(self._actions_lb, self._actions_ub) # just to be safe
|
| 544 |
+
|
| 545 |
+
if self._act_mem_buffer is not None: # store norm actions in memory buffer
|
| 546 |
+
self._act_mem_buffer.update(new_data=actions_norm)
|
| 547 |
+
|
| 548 |
+
if self._env_opts["use_action_smoothing"]:
|
| 549 |
+
self._apply_actions_smoothing() # smooth actions if enabled (the tensor returned by
|
| 550 |
+
# get_actions does not contain smoothing and can be safely employed for experience collection)
|
| 551 |
+
|
| 552 |
+
self._apply_actions_to_rhc() # apply last agent actions to rhc controller
|
| 553 |
+
|
| 554 |
+
stepping_ok = True
|
| 555 |
+
tot_rewards = self._tot_rewards.get_torch_mirror(gpu=self._use_gpu)
|
| 556 |
+
sub_rewards = self._sub_rewards.get_torch_mirror(gpu=self._use_gpu)
|
| 557 |
+
next_obs = self._next_obs.get_torch_mirror(gpu=self._use_gpu)
|
| 558 |
+
tot_rewards.zero_()
|
| 559 |
+
sub_rewards.zero_()
|
| 560 |
+
self._substep_rewards.zero_()
|
| 561 |
+
next_obs.zero_() # necessary for substep obs
|
| 562 |
+
|
| 563 |
+
for i in range(0, self._action_repeat):
|
| 564 |
+
|
| 565 |
+
self._pre_substep() # custom logic @ substep freq
|
| 566 |
+
|
| 567 |
+
stepping_ok = stepping_ok and self._check_controllers_registered(retry=False) # does not make sense to run training
|
| 568 |
+
# if we lost some controllers
|
| 569 |
+
stepping_ok = stepping_ok and self._remote_sim_step() # blocking,
|
| 570 |
+
|
| 571 |
+
# no sim substepping is allowed to fail
|
| 572 |
+
self._synch_state(gpu=self._use_gpu) # read state from shared mem (done in substeps also,
|
| 573 |
+
# since substeps rewards will need updated substep obs)
|
| 574 |
+
|
| 575 |
+
self._custom_post_substp_pre_rew() # custom substepping logic
|
| 576 |
+
self._compute_substep_rewards()
|
| 577 |
+
self._assemble_substep_rewards() # includes rewards clipping
|
| 578 |
+
self._custom_post_substp_post_rew() # custom substepping logic
|
| 579 |
+
|
| 580 |
+
# fill substep obs
|
| 581 |
+
self._fill_substep_obs(self._substep_obs)
|
| 582 |
+
self._assemble_substep_obs()
|
| 583 |
+
if not i==(self._action_repeat-1):
|
| 584 |
+
# sends reset signal to complete remote step sequence,
|
| 585 |
+
# but does not reset any remote env
|
| 586 |
+
stepping_ok = stepping_ok and self._remote_reset(reset_mask=None)
|
| 587 |
+
else: # last substep
|
| 588 |
+
|
| 589 |
+
self._fill_step_obs(next_obs) # update next obs
|
| 590 |
+
self._clamp_obs(next_obs) # good practice
|
| 591 |
+
obs = self._obs.get_torch_mirror(gpu=self._use_gpu)
|
| 592 |
+
obs[:, :] = next_obs # start from next observation, unless reset (handled in post_step())
|
| 593 |
+
|
| 594 |
+
self._compute_step_rewards() # implemented by child
|
| 595 |
+
|
| 596 |
+
tot_rewards = self._tot_rewards.get_torch_mirror(gpu=self._use_gpu)
|
| 597 |
+
sub_rewards = self._sub_rewards.get_torch_mirror(gpu=self._use_gpu)
|
| 598 |
+
self._clamp_rewards(sub_rewards) # clamp all sub rewards
|
| 599 |
+
|
| 600 |
+
tot_rewards[:, :] = torch.sum(sub_rewards, dim=1, keepdim=True)
|
| 601 |
+
|
| 602 |
+
scale=1 # scale tot rew by the number of action repeats
|
| 603 |
+
if self._env_opts["srew_drescaling"]: # scale rewards depending on the n of subrewards
|
| 604 |
+
scale*=sub_rewards.shape[1] # n. dims rescaling
|
| 605 |
+
tot_rewards.mul_(1/scale)
|
| 606 |
+
|
| 607 |
+
self._substep_abs_counter.increment() # @ substep freq
|
| 608 |
+
|
| 609 |
+
if not stepping_ok:
|
| 610 |
+
return False
|
| 611 |
+
|
| 612 |
+
stepping_ok = stepping_ok and self._post_step() # post sub-stepping operations
|
| 613 |
+
# (if action_repeat > 1, then just the db data at the last substep is logged)
|
| 614 |
+
# also, if a reset of an env occurs, obs will hold the reset state
|
| 615 |
+
|
| 616 |
+
return stepping_ok
|
| 617 |
+
|
| 618 |
+
def _post_step(self):
|
| 619 |
+
|
| 620 |
+
# first increment counters
|
| 621 |
+
self._ep_timeout_counter.increment() # episode timeout
|
| 622 |
+
self._task_rand_counter.increment() # task randomization
|
| 623 |
+
if self._rand_trunc_counter is not None: # random truncations (for removing temp. correlations)
|
| 624 |
+
self._rand_trunc_counter.increment()
|
| 625 |
+
|
| 626 |
+
# check truncation and termination conditions
|
| 627 |
+
self._check_truncations() # defined in child env
|
| 628 |
+
self._check_terminations()
|
| 629 |
+
terminated = self._terminations.get_torch_mirror(gpu=self._use_gpu)
|
| 630 |
+
truncated = self._truncations.get_torch_mirror(gpu=self._use_gpu)
|
| 631 |
+
ignore_ep_end=None
|
| 632 |
+
if self._rand_trunc_counter is not None:
|
| 633 |
+
ignore_ep_end=self._rand_trunc_counter.time_limits_reached()
|
| 634 |
+
if self._use_gpu:
|
| 635 |
+
ignore_ep_end=ignore_ep_end.cuda()
|
| 636 |
+
|
| 637 |
+
truncated = torch.logical_or(truncated,
|
| 638 |
+
ignore_ep_end) # add truncation (sub truncations defined in child env
|
| 639 |
+
# remain untouched)
|
| 640 |
+
|
| 641 |
+
episode_finished = torch.logical_or(terminated,
|
| 642 |
+
truncated)
|
| 643 |
+
episode_finished_cpu = episode_finished.cpu()
|
| 644 |
+
|
| 645 |
+
if self._rand_safety_reset_counter is not None and self._random_reset_active:
|
| 646 |
+
self._rand_safety_reset_counter.increment(to_be_incremented=episode_finished_cpu.flatten())
|
| 647 |
+
# truncated[:,:] = torch.logical_or(truncated,
|
| 648 |
+
# self._rand_safety_reset_counter.time_limits_reached().cuda())
|
| 649 |
+
|
| 650 |
+
if self._act_mem_buffer is not None:
|
| 651 |
+
self._act_mem_buffer.reset(to_be_reset=episode_finished.flatten(),
|
| 652 |
+
init_data=self._normalize_actions(self.default_action))
|
| 653 |
+
|
| 654 |
+
if self._action_smoother_continuous is not None:
|
| 655 |
+
self._action_smoother_continuous.reset(to_be_reset=episode_finished.flatten(),
|
| 656 |
+
reset_val=self.default_action[:, self._is_continuous_actions])
|
| 657 |
+
if self._action_smoother_discrete is not None:
|
| 658 |
+
self._action_smoother_discrete.reset(to_be_reset=episode_finished.flatten(),
|
| 659 |
+
reset_val=self.default_action[:, ~self._is_continuous_actions])
|
| 660 |
+
|
| 661 |
+
# debug step if required (IMPORTANT: must be before remote reset so that we always db
|
| 662 |
+
# actual data from the step and not after reset)
|
| 663 |
+
if self._is_debug:
|
| 664 |
+
self._debug() # copies db data on shared memory
|
| 665 |
+
ignore_ep_end_cpu=ignore_ep_end if not self._use_gpu else ignore_ep_end.cpu()
|
| 666 |
+
self._update_custom_db_data(episode_finished=episode_finished_cpu,
|
| 667 |
+
ignore_ep_end=ignore_ep_end_cpu # ignore data if random trunc
|
| 668 |
+
)
|
| 669 |
+
self._episodic_rewards_metrics.update(rewards = self._sub_rewards.get_torch_mirror(gpu=False),
|
| 670 |
+
ep_finished=episode_finished_cpu,
|
| 671 |
+
ignore_ep_end=ignore_ep_end_cpu # ignore data if random trunc
|
| 672 |
+
)
|
| 673 |
+
|
| 674 |
+
# remotely reset envs
|
| 675 |
+
to_be_reset=self._to_be_reset()
|
| 676 |
+
to_be_reset_custom=self._custom_reset()
|
| 677 |
+
if to_be_reset_custom is not None:
|
| 678 |
+
to_be_reset[:, :] = torch.logical_or(to_be_reset,to_be_reset_custom)
|
| 679 |
+
rm_reset_ok = self._remote_reset(reset_mask=to_be_reset)
|
| 680 |
+
|
| 681 |
+
self._custom_post_step(episode_finished=episode_finished) # any additional logic from child env
|
| 682 |
+
# here, before actual reset taskes place (at this point the state is the reset one)
|
| 683 |
+
|
| 684 |
+
# updating also prev pos and orientation in case some env was reset
|
| 685 |
+
self._prev_root_p_substep[:, :]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)
|
| 686 |
+
self._prev_root_q_substep[:, :]=self._robot_state.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 687 |
+
|
| 688 |
+
obs = self._obs.get_torch_mirror(gpu=self._use_gpu)
|
| 689 |
+
self._fill_step_obs(obs)
|
| 690 |
+
self._clamp_obs(obs)
|
| 691 |
+
|
| 692 |
+
# updating prev step quantities
|
| 693 |
+
self._prev_root_p_step[:, :]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)
|
| 694 |
+
self._prev_root_q_step[:, :]=self._robot_state.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 695 |
+
|
| 696 |
+
# synchronize and reset counters for finished episodes
|
| 697 |
+
self._ep_timeout_counter.reset(to_be_reset=episode_finished)
|
| 698 |
+
self._task_rand_counter.reset(to_be_reset=episode_finished)
|
| 699 |
+
self._substep_abs_counter.reset(to_be_reset=torch.logical_or(terminated,to_be_reset),
|
| 700 |
+
randomize_offsets=True # otherwise timers across envs would be strongly correlated
|
| 701 |
+
) # reset only if resetting environment or if terminal
|
| 702 |
+
|
| 703 |
+
if self._rand_trunc_counter is not None:
|
| 704 |
+
# only reset when safety truncation was is triggered
|
| 705 |
+
self._rand_trunc_counter.reset(to_be_reset=self._rand_trunc_counter.time_limits_reached(),
|
| 706 |
+
randomize_limits=True, # we need to randomize otherwise the other counters will synchronize
|
| 707 |
+
# with the episode counters
|
| 708 |
+
randomize_offsets=False # always restart at 0
|
| 709 |
+
)
|
| 710 |
+
# safety reset counter is only when it reches its reset interval (just to keep
|
| 711 |
+
# the counter bounded)
|
| 712 |
+
if self._rand_safety_reset_counter is not None and self._random_reset_active:
|
| 713 |
+
self._rand_safety_reset_counter.reset(to_be_reset=self._rand_safety_reset_counter.time_limits_reached())
|
| 714 |
+
|
| 715 |
+
return rm_reset_ok
|
| 716 |
+
|
| 717 |
+
def _to_be_reset(self):
|
| 718 |
+
# always reset if a termination occurred or if there's a random safety reset
|
| 719 |
+
# request
|
| 720 |
+
terminated = self._terminations.get_torch_mirror(gpu=self._use_gpu)
|
| 721 |
+
to_be_reset=terminated.clone()
|
| 722 |
+
if (self._rand_safety_reset_counter is not None) and self._random_reset_active:
|
| 723 |
+
to_be_reset=torch.logical_or(to_be_reset,
|
| 724 |
+
self._rand_safety_reset_counter.time_limits_reached())
|
| 725 |
+
|
| 726 |
+
return to_be_reset
|
| 727 |
+
|
| 728 |
+
def _custom_reset(self):
|
| 729 |
+
# can be overridden by child
|
| 730 |
+
return None
|
| 731 |
+
|
| 732 |
+
def _apply_actions_smoothing(self):
|
| 733 |
+
|
| 734 |
+
actions = self._actions.get_torch_mirror(gpu=self._use_gpu)
|
| 735 |
+
actual_actions=self.get_actual_actions() # will write smoothed actions here
|
| 736 |
+
if self._action_smoother_continuous is not None:
|
| 737 |
+
self._action_smoother_continuous.update(new_signal=
|
| 738 |
+
actions[:, self._is_continuous_actions])
|
| 739 |
+
actual_actions[:, self._is_continuous_actions]=self._action_smoother_continuous.get()
|
| 740 |
+
if self._action_smoother_discrete is not None:
|
| 741 |
+
self._action_smoother_discrete.update(new_signal=
|
| 742 |
+
actions[:, ~self._is_continuous_actions])
|
| 743 |
+
actual_actions[:, ~self._is_continuous_actions]=self._action_smoother_discrete.get()
|
| 744 |
+
|
| 745 |
+
def _update_custom_db_data(self,
|
| 746 |
+
episode_finished,
|
| 747 |
+
ignore_ep_end):
|
| 748 |
+
|
| 749 |
+
# update defaults
|
| 750 |
+
self.custom_db_data["RhcRefsFlag"].update(new_data=self._rhc_refs.contact_flags.get_torch_mirror(gpu=False),
|
| 751 |
+
ep_finished=episode_finished,
|
| 752 |
+
ignore_ep_end=ignore_ep_end) # before potentially resetting the flags, get data
|
| 753 |
+
self.custom_db_data["Actions"].update(new_data=self._actions.get_torch_mirror(gpu=False),
|
| 754 |
+
ep_finished=episode_finished,
|
| 755 |
+
ignore_ep_end=ignore_ep_end)
|
| 756 |
+
self.custom_db_data["Obs"].update(new_data=self._obs.get_torch_mirror(gpu=False),
|
| 757 |
+
ep_finished=episode_finished,
|
| 758 |
+
ignore_ep_end=ignore_ep_end)
|
| 759 |
+
|
| 760 |
+
self.custom_db_data["SubTerminations"].update(new_data=self._sub_terminations.get_torch_mirror(gpu=False),
|
| 761 |
+
ep_finished=episode_finished,
|
| 762 |
+
ignore_ep_end=ignore_ep_end)
|
| 763 |
+
self.custom_db_data["SubTruncations"].update(new_data=self._sub_truncations.get_torch_mirror(gpu=False),
|
| 764 |
+
ep_finished=episode_finished,
|
| 765 |
+
ignore_ep_end=ignore_ep_end)
|
| 766 |
+
|
| 767 |
+
self.custom_db_data["Terminations"].update(new_data=self._terminations.get_torch_mirror(gpu=False),
|
| 768 |
+
ep_finished=episode_finished,
|
| 769 |
+
ignore_ep_end=ignore_ep_end)
|
| 770 |
+
self.custom_db_data["Truncations"].update(new_data=self._truncations.get_torch_mirror(gpu=False),
|
| 771 |
+
ep_finished=episode_finished,
|
| 772 |
+
ignore_ep_end=ignore_ep_end)
|
| 773 |
+
|
| 774 |
+
|
| 775 |
+
self._get_custom_db_data(episode_finished=episode_finished, ignore_ep_end=ignore_ep_end)
|
| 776 |
+
|
| 777 |
+
def reset_custom_db_data(self, keep_track: bool = False):
|
| 778 |
+
# to be called periodically to reset custom db data stat. collection
|
| 779 |
+
for custom_db_data in self.custom_db_data.values():
|
| 780 |
+
custom_db_data.reset(keep_track=keep_track)
|
| 781 |
+
|
| 782 |
+
def _assemble_substep_rewards(self):
|
| 783 |
+
# by default assemble substep rewards by averaging
|
| 784 |
+
sub_rewards = self._sub_rewards.get_torch_mirror(gpu=self._use_gpu)
|
| 785 |
+
|
| 786 |
+
# average over substeps depending on scale
|
| 787 |
+
# sub_rewards[:, self._is_substep_rew] = sub_rewards[:, self._is_substep_rew] + \
|
| 788 |
+
# self._substep_rewards[:, self._is_substep_rew]/self._action_repeat
|
| 789 |
+
sub_rewards[:, self._is_substep_rew] += self._substep_rewards[:, self._is_substep_rew]/self._action_repeat
|
| 790 |
+
|
| 791 |
+
def _assemble_substep_obs(self):
|
| 792 |
+
next_obs = self._next_obs.get_torch_mirror(gpu=self._use_gpu)
|
| 793 |
+
next_obs[:, self._is_substep_obs] += self._substep_obs[:, self._is_substep_obs]/self._action_repeat
|
| 794 |
+
|
| 795 |
+
def randomize_task_refs(self,
|
| 796 |
+
env_indxs: torch.Tensor = None):
|
| 797 |
+
|
| 798 |
+
if self._override_agent_refs:
|
| 799 |
+
self._override_refs(env_indxs=env_indxs)
|
| 800 |
+
else:
|
| 801 |
+
self._randomize_task_refs(env_indxs=env_indxs)
|
| 802 |
+
|
| 803 |
+
def reset(self):
|
| 804 |
+
|
| 805 |
+
self.randomize_task_refs(env_indxs=None) # randomize all refs across envs
|
| 806 |
+
|
| 807 |
+
self._obs.reset()
|
| 808 |
+
self._actions.reset()
|
| 809 |
+
self._next_obs.reset()
|
| 810 |
+
self._sub_rewards.reset()
|
| 811 |
+
self._tot_rewards.reset()
|
| 812 |
+
self._terminations.reset()
|
| 813 |
+
self._sub_terminations.reset()
|
| 814 |
+
self._truncations.reset()
|
| 815 |
+
self._sub_truncations.reset()
|
| 816 |
+
|
| 817 |
+
self._ep_timeout_counter.reset(randomize_offsets=True)
|
| 818 |
+
self._task_rand_counter.reset()
|
| 819 |
+
self._task_rand_counter.sync_counters(other_counter=self._ep_timeout_counter)
|
| 820 |
+
if self._rand_safety_reset_counter is not None:
|
| 821 |
+
self._rand_safety_reset_counter.reset()
|
| 822 |
+
self._substep_abs_counter.reset()
|
| 823 |
+
|
| 824 |
+
if self._act_mem_buffer is not None:
|
| 825 |
+
self._act_mem_buffer.reset_all(init_data=self._normalize_actions(self.default_action))
|
| 826 |
+
|
| 827 |
+
if self._action_smoother_continuous is not None:
|
| 828 |
+
self._action_smoother_continuous.reset(reset_val=self.default_action[:, self._is_continuous_actions])
|
| 829 |
+
if self._action_smoother_discrete is not None:
|
| 830 |
+
self._action_smoother_discrete.reset(reset_val=self.default_action[:, ~self._is_continuous_actions])
|
| 831 |
+
|
| 832 |
+
self._synch_state(gpu=self._use_gpu) # read obs from shared mem
|
| 833 |
+
|
| 834 |
+
# just calling custom post step to ensure tak refs are updated
|
| 835 |
+
terminated = self._terminations.get_torch_mirror(gpu=self._use_gpu)
|
| 836 |
+
truncated = self._truncations.get_torch_mirror(gpu=self._use_gpu)
|
| 837 |
+
episode_finished = torch.logical_or(terminated,
|
| 838 |
+
truncated)
|
| 839 |
+
self._custom_post_step(episode_finished=episode_finished)
|
| 840 |
+
|
| 841 |
+
obs = self._obs.get_torch_mirror(gpu=self._use_gpu)
|
| 842 |
+
next_obs = self._next_obs.get_torch_mirror(gpu=self._use_gpu)
|
| 843 |
+
self._fill_step_obs(obs) # initialize observations
|
| 844 |
+
self._clamp_obs(obs) # to avoid bad things
|
| 845 |
+
self._fill_step_obs(next_obs) # and next obs
|
| 846 |
+
self._clamp_obs(next_obs)
|
| 847 |
+
|
| 848 |
+
self.reset_custom_db_data(keep_track=False)
|
| 849 |
+
self._episodic_rewards_metrics.reset(keep_track=False)
|
| 850 |
+
|
| 851 |
+
self._prev_root_p_step[:, :]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)
|
| 852 |
+
self._prev_root_q_step[:, :]=self._robot_state.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 853 |
+
self._prev_root_p_substep[:, :]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)
|
| 854 |
+
self._prev_root_q_substep[:, :]=self._robot_state.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 855 |
+
|
| 856 |
+
def is_ready(self):
|
| 857 |
+
return self._ready
|
| 858 |
+
|
| 859 |
+
def close(self):
|
| 860 |
+
|
| 861 |
+
if not self._closed:
|
| 862 |
+
|
| 863 |
+
# close all shared mem. clients
|
| 864 |
+
self._robot_state.close()
|
| 865 |
+
self._rhc_cmds.close()
|
| 866 |
+
self._rhc_pred.close()
|
| 867 |
+
self._rhc_refs.close()
|
| 868 |
+
self._rhc_status.close()
|
| 869 |
+
|
| 870 |
+
self._remote_stepper.close()
|
| 871 |
+
|
| 872 |
+
self._ep_timeout_counter.close()
|
| 873 |
+
self._task_rand_counter.close()
|
| 874 |
+
if self._rand_safety_reset_counter is not None:
|
| 875 |
+
self._rand_safety_reset_counter.close()
|
| 876 |
+
|
| 877 |
+
# closing env.-specific shared data
|
| 878 |
+
self._obs.close()
|
| 879 |
+
self._next_obs.close()
|
| 880 |
+
self._actions.close()
|
| 881 |
+
if self._actual_actions is not None:
|
| 882 |
+
self._actual_actions.close()
|
| 883 |
+
self._sub_rewards.close()
|
| 884 |
+
self._tot_rewards.close()
|
| 885 |
+
|
| 886 |
+
self._terminations.close()
|
| 887 |
+
self._sub_terminations.close()
|
| 888 |
+
self._truncations.close()
|
| 889 |
+
self._sub_truncations.close()
|
| 890 |
+
|
| 891 |
+
self._closed = True
|
| 892 |
+
|
| 893 |
+
def get_obs(self, clone:bool=False):
|
| 894 |
+
if clone:
|
| 895 |
+
return self._obs.get_torch_mirror(gpu=self._use_gpu).detach().clone()
|
| 896 |
+
else:
|
| 897 |
+
return self._obs.get_torch_mirror(gpu=self._use_gpu).detach()
|
| 898 |
+
|
| 899 |
+
def get_next_obs(self, clone:bool=False):
|
| 900 |
+
if clone:
|
| 901 |
+
return self._next_obs.get_torch_mirror(gpu=self._use_gpu).detach().clone()
|
| 902 |
+
else:
|
| 903 |
+
return self._next_obs.get_torch_mirror(gpu=self._use_gpu).detach()
|
| 904 |
+
|
| 905 |
+
def get_actions(self, clone:bool=False, normalized: bool = False):
|
| 906 |
+
actions = self._actions.get_torch_mirror(gpu=self._use_gpu).detach()
|
| 907 |
+
if normalized:
|
| 908 |
+
normalized_actions = self._normalize_actions(actions)
|
| 909 |
+
return normalized_actions.clone() if clone else normalized_actions
|
| 910 |
+
return actions.clone() if clone else actions
|
| 911 |
+
|
| 912 |
+
def get_actual_actions(self, clone:bool=False, normalized: bool = False):
|
| 913 |
+
if self._env_opts["use_action_smoothing"]:
|
| 914 |
+
actions = self._actual_actions.get_torch_mirror(gpu=self._use_gpu).detach()
|
| 915 |
+
else: # actual action coincides with the one from the agent + possible modif.
|
| 916 |
+
actions = self.get_actions(clone=False, normalized=False)
|
| 917 |
+
if normalized:
|
| 918 |
+
normalized_actions = self._normalize_actions(actions)
|
| 919 |
+
return normalized_actions.clone() if clone else normalized_actions
|
| 920 |
+
return actions.clone() if clone else actions
|
| 921 |
+
|
| 922 |
+
def _normalize_actions(self, actions: torch.Tensor):
|
| 923 |
+
scale = torch.where(self._actions_scale == 0.0,
|
| 924 |
+
torch.ones_like(self._actions_scale),
|
| 925 |
+
self._actions_scale)
|
| 926 |
+
normalized = (actions - self._actions_offset)/scale
|
| 927 |
+
zero_scale_mask = torch.eq(self._actions_scale, 0.0).squeeze(0)
|
| 928 |
+
if torch.any(zero_scale_mask):
|
| 929 |
+
normalized[:, zero_scale_mask] = 0.0
|
| 930 |
+
return normalized
|
| 931 |
+
|
| 932 |
+
def get_rewards(self, clone:bool=False):
|
| 933 |
+
if clone:
|
| 934 |
+
return self._tot_rewards.get_torch_mirror(gpu=self._use_gpu).detach().clone()
|
| 935 |
+
else:
|
| 936 |
+
return self._tot_rewards.get_torch_mirror(gpu=self._use_gpu).detach()
|
| 937 |
+
|
| 938 |
+
def get_terminations(self, clone:bool=False):
|
| 939 |
+
if clone:
|
| 940 |
+
return self._terminations.get_torch_mirror(gpu=self._use_gpu).detach().clone()
|
| 941 |
+
else:
|
| 942 |
+
return self._terminations.get_torch_mirror(gpu=self._use_gpu).detach()
|
| 943 |
+
|
| 944 |
+
def get_truncations(self, clone:bool=False):
|
| 945 |
+
if clone:
|
| 946 |
+
return self._truncations.get_torch_mirror(gpu=self._use_gpu).detach().clone()
|
| 947 |
+
else:
|
| 948 |
+
return self._truncations.get_torch_mirror(gpu=self._use_gpu).detach()
|
| 949 |
+
|
| 950 |
+
def obs_dim(self):
|
| 951 |
+
|
| 952 |
+
return self._obs_dim
|
| 953 |
+
|
| 954 |
+
def actions_dim(self):
|
| 955 |
+
|
| 956 |
+
return self._actions_dim
|
| 957 |
+
|
| 958 |
+
def ep_rewards_metrics(self):
|
| 959 |
+
|
| 960 |
+
return self._episodic_rewards_metrics
|
| 961 |
+
|
| 962 |
+
def using_gpu(self):
|
| 963 |
+
|
| 964 |
+
return self._use_gpu
|
| 965 |
+
|
| 966 |
+
def name(self):
|
| 967 |
+
|
| 968 |
+
return self._env_name
|
| 969 |
+
|
| 970 |
+
def n_envs(self):
|
| 971 |
+
|
| 972 |
+
return self._n_envs
|
| 973 |
+
|
| 974 |
+
def dtype(self):
|
| 975 |
+
|
| 976 |
+
return self._dtype
|
| 977 |
+
|
| 978 |
+
def obs_names(self):
|
| 979 |
+
return self._get_obs_names()
|
| 980 |
+
|
| 981 |
+
def action_names(self):
|
| 982 |
+
return self._get_action_names()
|
| 983 |
+
|
| 984 |
+
def sub_rew_names(self):
|
| 985 |
+
return self._get_rewards_names()
|
| 986 |
+
|
| 987 |
+
def sub_term_names(self):
|
| 988 |
+
return self._get_sub_term_names()
|
| 989 |
+
|
| 990 |
+
def sub_trunc_names(self):
|
| 991 |
+
return self._get_sub_trunc_names()
|
| 992 |
+
|
| 993 |
+
def _get_obs_names(self):
|
| 994 |
+
# to be overridden by child class
|
| 995 |
+
return None
|
| 996 |
+
|
| 997 |
+
def get_robot_jnt_names(self):
|
| 998 |
+
return self._robot_state.jnt_names()
|
| 999 |
+
|
| 1000 |
+
def _get_action_names(self):
|
| 1001 |
+
# to be overridden by child class
|
| 1002 |
+
return None
|
| 1003 |
+
|
| 1004 |
+
def _get_rewards_names(self):
|
| 1005 |
+
# to be overridden by child class
|
| 1006 |
+
return None
|
| 1007 |
+
|
| 1008 |
+
def _get_sub_term_names(self):
|
| 1009 |
+
# to be overridden by child class
|
| 1010 |
+
sub_term_names = []
|
| 1011 |
+
sub_term_names.append("rhc_failure")
|
| 1012 |
+
sub_term_names.append("robot_capsize")
|
| 1013 |
+
sub_term_names.append("rhc_capsize")
|
| 1014 |
+
|
| 1015 |
+
return sub_term_names
|
| 1016 |
+
|
| 1017 |
+
def _get_sub_trunc_names(self):
|
| 1018 |
+
# to be overridden by child class
|
| 1019 |
+
sub_trunc_names = []
|
| 1020 |
+
sub_trunc_names.append("ep_timeout")
|
| 1021 |
+
|
| 1022 |
+
return sub_trunc_names
|
| 1023 |
+
|
| 1024 |
+
def _get_custom_db_data(self, episode_finished):
|
| 1025 |
+
# to be overridden by child class
|
| 1026 |
+
pass
|
| 1027 |
+
|
| 1028 |
+
def set_observed_joints(self):
|
| 1029 |
+
# ny default observe all joints available
|
| 1030 |
+
return self._robot_state.jnt_names()
|
| 1031 |
+
|
| 1032 |
+
def _set_jnts_blacklist_pattern(self):
|
| 1033 |
+
self._jnt_q_blacklist_patterns=[]
|
| 1034 |
+
|
| 1035 |
+
def get_observed_joints(self):
|
| 1036 |
+
return self._observed_jnt_names
|
| 1037 |
+
|
| 1038 |
+
def _init_obs(self, obs_dim: int):
|
| 1039 |
+
|
| 1040 |
+
device = "cuda" if self._use_gpu else "cpu"
|
| 1041 |
+
|
| 1042 |
+
obs_threshold_default = 1e3
|
| 1043 |
+
self._obs_threshold_lb = -obs_threshold_default # used for clipping observations
|
| 1044 |
+
self._obs_threshold_ub = obs_threshold_default
|
| 1045 |
+
|
| 1046 |
+
self._obs_ub = torch.full((1, obs_dim), dtype=self._dtype, device=device,
|
| 1047 |
+
fill_value=1.0)
|
| 1048 |
+
self._obs_lb = torch.full((1, obs_dim), dtype=self._dtype, device=device,
|
| 1049 |
+
fill_value=-1.0)
|
| 1050 |
+
self._obs_scale = (self._obs_ub - self._obs_lb)/2.0
|
| 1051 |
+
self._obs_offset = (self._obs_ub + self._obs_lb)/2.0
|
| 1052 |
+
|
| 1053 |
+
if not self._obs_dim==len(self._get_obs_names()):
|
| 1054 |
+
error=f"obs dim {self._obs_dim} does not match obs names length {len(self._get_obs_names())}!!"
|
| 1055 |
+
Journal.log(self.__class__.__name__,
|
| 1056 |
+
"_init_obs",
|
| 1057 |
+
error,
|
| 1058 |
+
LogType.EXCEP,
|
| 1059 |
+
throw_when_excep = True)
|
| 1060 |
+
|
| 1061 |
+
self._obs = Observations(namespace=self._namespace,
|
| 1062 |
+
n_envs=self._n_envs,
|
| 1063 |
+
obs_dim=self._obs_dim,
|
| 1064 |
+
obs_names=self._get_obs_names(),
|
| 1065 |
+
env_names=None,
|
| 1066 |
+
is_server=True,
|
| 1067 |
+
verbose=self._verbose,
|
| 1068 |
+
vlevel=self._vlevel,
|
| 1069 |
+
safe=True,
|
| 1070 |
+
force_reconnection=True,
|
| 1071 |
+
with_gpu_mirror=self._use_gpu,
|
| 1072 |
+
fill_value=0.0)
|
| 1073 |
+
|
| 1074 |
+
self._next_obs = NextObservations(namespace=self._namespace,
|
| 1075 |
+
n_envs=self._n_envs,
|
| 1076 |
+
obs_dim=self._obs_dim,
|
| 1077 |
+
obs_names=self._get_obs_names(),
|
| 1078 |
+
env_names=None,
|
| 1079 |
+
is_server=True,
|
| 1080 |
+
verbose=self._verbose,
|
| 1081 |
+
vlevel=self._vlevel,
|
| 1082 |
+
safe=True,
|
| 1083 |
+
force_reconnection=True,
|
| 1084 |
+
with_gpu_mirror=self._use_gpu,
|
| 1085 |
+
fill_value=0.0)
|
| 1086 |
+
|
| 1087 |
+
self._obs.run()
|
| 1088 |
+
self._next_obs.run()
|
| 1089 |
+
|
| 1090 |
+
self._is_substep_obs = torch.zeros((self.obs_dim(),), dtype=torch.bool, device=device)
|
| 1091 |
+
self._is_substep_obs.fill_(False) # default to all step obs
|
| 1092 |
+
|
| 1093 |
+
# not super memory efficient
|
| 1094 |
+
self._substep_obs=torch.full_like(self._obs.get_torch_mirror(gpu=self._use_gpu), fill_value=0.0)
|
| 1095 |
+
|
| 1096 |
+
def _init_actions(self, actions_dim: int):
|
| 1097 |
+
|
| 1098 |
+
device = "cuda" if self._use_gpu else "cpu"
|
| 1099 |
+
# action scalings to be applied to agent's output
|
| 1100 |
+
self._actions_ub = torch.full((1, actions_dim), dtype=self._dtype, device=device,
|
| 1101 |
+
fill_value=1.0)
|
| 1102 |
+
self._actions_lb = torch.full((1, actions_dim), dtype=self._dtype, device=device,
|
| 1103 |
+
fill_value=-1.0)
|
| 1104 |
+
self._actions_scale = (self._actions_ub - self._actions_lb)/2.0
|
| 1105 |
+
self._actions_offset = (self._actions_ub + self._actions_lb)/2.0
|
| 1106 |
+
|
| 1107 |
+
if not self._actions_dim==len(self._get_action_names()):
|
| 1108 |
+
error=f"action dim {self._actions_dim} does not match action names length {len(self._get_action_names())}!!"
|
| 1109 |
+
Journal.log(self.__class__.__name__,
|
| 1110 |
+
"_init_actions",
|
| 1111 |
+
error,
|
| 1112 |
+
LogType.EXCEP,
|
| 1113 |
+
throw_when_excep = True)
|
| 1114 |
+
self._actions = Actions(namespace=self._namespace,
|
| 1115 |
+
n_envs=self._n_envs,
|
| 1116 |
+
action_dim=self._actions_dim,
|
| 1117 |
+
action_names=self._get_action_names(),
|
| 1118 |
+
env_names=None,
|
| 1119 |
+
is_server=True,
|
| 1120 |
+
verbose=self._verbose,
|
| 1121 |
+
vlevel=self._vlevel,
|
| 1122 |
+
safe=True,
|
| 1123 |
+
force_reconnection=True,
|
| 1124 |
+
with_gpu_mirror=self._use_gpu,
|
| 1125 |
+
fill_value=0.0)
|
| 1126 |
+
|
| 1127 |
+
self._actions.run()
|
| 1128 |
+
|
| 1129 |
+
self.default_action = torch.full_like(input=self.get_actions(),fill_value=0.0)
|
| 1130 |
+
self.safe_action = torch.full_like(input=self.get_actions(),fill_value=0.0)
|
| 1131 |
+
|
| 1132 |
+
if self._env_opts["use_action_history"]:
|
| 1133 |
+
self._act_mem_buffer=MemBuffer(name="ActionMemBuf",
|
| 1134 |
+
data_tensor=self._actions.get_torch_mirror(),
|
| 1135 |
+
data_names=self._get_action_names(),
|
| 1136 |
+
debug=self._debug,
|
| 1137 |
+
horizon=self._env_opts["actions_history_size"],
|
| 1138 |
+
dtype=self._dtype,
|
| 1139 |
+
use_gpu=self._use_gpu)
|
| 1140 |
+
|
| 1141 |
+
# default to all continuous actions (changes the way noise is added)
|
| 1142 |
+
self._is_continuous_actions=torch.full((actions_dim, ),
|
| 1143 |
+
dtype=torch.bool, device=device,
|
| 1144 |
+
fill_value=True)
|
| 1145 |
+
|
| 1146 |
+
def _init_action_smoothing(self):
|
| 1147 |
+
|
| 1148 |
+
continuous_actions=self.get_actions()[:, self._is_continuous_actions]
|
| 1149 |
+
discrete_actions=self.get_actions()[:, ~self._is_continuous_actions]
|
| 1150 |
+
self._action_smoother_continuous=ExponentialSignalSmoother(signal=continuous_actions,
|
| 1151 |
+
update_dt=self._substep_dt*self._action_repeat, # rate at which actions are decided by agent
|
| 1152 |
+
smoothing_horizon=self._env_opts["smoothing_horizon_c"],
|
| 1153 |
+
target_smoothing=0.5,
|
| 1154 |
+
debug=self._debug,
|
| 1155 |
+
dtype=self._dtype,
|
| 1156 |
+
use_gpu=self._use_gpu,
|
| 1157 |
+
name="ActionSmootherContinuous")
|
| 1158 |
+
self._action_smoother_discrete=ExponentialSignalSmoother(signal=discrete_actions,
|
| 1159 |
+
update_dt=self._substep_dt*self._action_repeat, # rate at which actions are decided by agent
|
| 1160 |
+
smoothing_horizon=self._env_opts["smoothing_horizon_d"],
|
| 1161 |
+
target_smoothing=0.5,
|
| 1162 |
+
debug=self._debug,
|
| 1163 |
+
dtype=self._dtype,
|
| 1164 |
+
use_gpu=self._use_gpu,
|
| 1165 |
+
name="ActionSmootherDiscrete")
|
| 1166 |
+
|
| 1167 |
+
# we also need somewhere to keep the actual actions after smoothing
|
| 1168 |
+
self._actual_actions = Actions(namespace=self._namespace+"_actual",
|
| 1169 |
+
n_envs=self._n_envs,
|
| 1170 |
+
action_dim=self._actions_dim,
|
| 1171 |
+
action_names=self._get_action_names(),
|
| 1172 |
+
env_names=None,
|
| 1173 |
+
is_server=True,
|
| 1174 |
+
verbose=self._verbose,
|
| 1175 |
+
vlevel=self._vlevel,
|
| 1176 |
+
safe=True,
|
| 1177 |
+
force_reconnection=True,
|
| 1178 |
+
with_gpu_mirror=self._use_gpu,
|
| 1179 |
+
fill_value=0.0)
|
| 1180 |
+
self._actual_actions.run()
|
| 1181 |
+
|
| 1182 |
+
def _init_rewards(self):
|
| 1183 |
+
|
| 1184 |
+
reward_thresh_default = 1.0
|
| 1185 |
+
n_sub_rewards = len(self._get_rewards_names())
|
| 1186 |
+
device = "cuda" if self._use_gpu else "cpu"
|
| 1187 |
+
self._reward_thresh_lb = torch.full((1, n_sub_rewards), dtype=self._dtype, fill_value=-reward_thresh_default, device=device) # used for clipping rewards
|
| 1188 |
+
self._reward_thresh_ub = torch.full((1, n_sub_rewards), dtype=self._dtype, fill_value=reward_thresh_default, device=device)
|
| 1189 |
+
|
| 1190 |
+
self._sub_rewards = SubRewards(namespace=self._namespace,
|
| 1191 |
+
n_envs=self._n_envs,
|
| 1192 |
+
n_rewards=n_sub_rewards,
|
| 1193 |
+
reward_names=self._get_rewards_names(),
|
| 1194 |
+
env_names=None,
|
| 1195 |
+
is_server=True,
|
| 1196 |
+
verbose=self._verbose,
|
| 1197 |
+
vlevel=self._vlevel,
|
| 1198 |
+
safe=True,
|
| 1199 |
+
force_reconnection=True,
|
| 1200 |
+
with_gpu_mirror=self._use_gpu,
|
| 1201 |
+
fill_value=0.0)
|
| 1202 |
+
|
| 1203 |
+
self._tot_rewards = TotRewards(namespace=self._namespace,
|
| 1204 |
+
n_envs=self._n_envs,
|
| 1205 |
+
reward_names=["total_reward"],
|
| 1206 |
+
env_names=None,
|
| 1207 |
+
is_server=True,
|
| 1208 |
+
verbose=self._verbose,
|
| 1209 |
+
vlevel=self._vlevel,
|
| 1210 |
+
safe=True,
|
| 1211 |
+
force_reconnection=True,
|
| 1212 |
+
with_gpu_mirror=self._use_gpu,
|
| 1213 |
+
fill_value=0.0)
|
| 1214 |
+
|
| 1215 |
+
self._sub_rewards.run()
|
| 1216 |
+
self._tot_rewards.run()
|
| 1217 |
+
|
| 1218 |
+
self._substep_rewards = self._sub_rewards.get_torch_mirror(gpu=self._use_gpu).detach().clone()
|
| 1219 |
+
# used to hold substep rewards (not super mem. efficient)
|
| 1220 |
+
self._is_substep_rew = torch.zeros((self._substep_rewards.shape[1],),dtype=torch.bool,device=device)
|
| 1221 |
+
self._is_substep_rew.fill_(True) # default to all substep rewards
|
| 1222 |
+
|
| 1223 |
+
self._episodic_rewards_metrics = EpisodicRewards(reward_tensor=self._sub_rewards.get_torch_mirror(),
|
| 1224 |
+
reward_names=self._get_rewards_names(),
|
| 1225 |
+
ep_vec_freq=self._env_opts["vec_ep_freq_metrics_db"],
|
| 1226 |
+
store_transitions=self._full_db,
|
| 1227 |
+
max_ep_duration=self._max_ep_length())
|
| 1228 |
+
self._episodic_rewards_metrics.set_constant_data_scaling(scaling=self._get_reward_scaling())
|
| 1229 |
+
|
| 1230 |
+
def _get_reward_scaling(self):
|
| 1231 |
+
# to be overridden by child (default to no scaling)
|
| 1232 |
+
return 1
|
| 1233 |
+
|
| 1234 |
+
def _max_ep_length(self):
|
| 1235 |
+
#.should be overriden by child
|
| 1236 |
+
return self._env_opts["episode_timeout_ub"]
|
| 1237 |
+
|
| 1238 |
+
def _init_custom_db_data(self):
|
| 1239 |
+
|
| 1240 |
+
self.custom_db_data = {}
|
| 1241 |
+
# by default always log this contact data
|
| 1242 |
+
rhc_latest_contact_ref = self._rhc_refs.contact_flags.get_torch_mirror()
|
| 1243 |
+
contact_names = self._rhc_refs.rob_refs.contact_names()
|
| 1244 |
+
stepping_data = EpisodicData("RhcRefsFlag", rhc_latest_contact_ref, contact_names,
|
| 1245 |
+
ep_vec_freq=self._env_opts["vec_ep_freq_metrics_db"],
|
| 1246 |
+
store_transitions=self._full_db,
|
| 1247 |
+
max_ep_duration=self._max_ep_length())
|
| 1248 |
+
self._add_custom_db_data(db_data=stepping_data)
|
| 1249 |
+
|
| 1250 |
+
# log also action data
|
| 1251 |
+
actions = self._actions.get_torch_mirror()
|
| 1252 |
+
action_names = self._get_action_names()
|
| 1253 |
+
action_data = EpisodicData("Actions", actions, action_names,
|
| 1254 |
+
ep_vec_freq=self._env_opts["vec_ep_freq_metrics_db"],
|
| 1255 |
+
store_transitions=self._full_db,
|
| 1256 |
+
max_ep_duration=self._max_ep_length())
|
| 1257 |
+
self._add_custom_db_data(db_data=action_data)
|
| 1258 |
+
|
| 1259 |
+
# and observations
|
| 1260 |
+
observations = self._obs.get_torch_mirror()
|
| 1261 |
+
observations_names = self._get_obs_names()
|
| 1262 |
+
obs_data = EpisodicData("Obs", observations, observations_names,
|
| 1263 |
+
ep_vec_freq=self._env_opts["vec_ep_freq_metrics_db"],
|
| 1264 |
+
store_transitions=self._full_db,
|
| 1265 |
+
max_ep_duration=self._max_ep_length())
|
| 1266 |
+
self._add_custom_db_data(db_data=obs_data)
|
| 1267 |
+
|
| 1268 |
+
# log sub-term and sub-truncations data
|
| 1269 |
+
t_scaling=1 # 1 so that we log an interpretable data in terms of why the episode finished
|
| 1270 |
+
data_scaling = torch.full((self._n_envs, 1),
|
| 1271 |
+
fill_value=t_scaling,
|
| 1272 |
+
dtype=torch.int32,device="cpu")
|
| 1273 |
+
sub_term = self._sub_terminations.get_torch_mirror()
|
| 1274 |
+
term = self._terminations.get_torch_mirror()
|
| 1275 |
+
sub_termination_names = self.sub_term_names()
|
| 1276 |
+
|
| 1277 |
+
sub_term_data = EpisodicData("SubTerminations", sub_term, sub_termination_names,
|
| 1278 |
+
ep_vec_freq=self._env_opts["vec_ep_freq_metrics_db"],
|
| 1279 |
+
store_transitions=self._full_db,
|
| 1280 |
+
max_ep_duration=self._max_ep_length())
|
| 1281 |
+
sub_term_data.set_constant_data_scaling(enable=True,scaling=data_scaling)
|
| 1282 |
+
self._add_custom_db_data(db_data=sub_term_data)
|
| 1283 |
+
term_data = EpisodicData("Terminations", term, ["terminations"],
|
| 1284 |
+
ep_vec_freq=self._env_opts["vec_ep_freq_metrics_db"],
|
| 1285 |
+
store_transitions=self._full_db,
|
| 1286 |
+
max_ep_duration=self._max_ep_length())
|
| 1287 |
+
term_data.set_constant_data_scaling(enable=True,scaling=data_scaling)
|
| 1288 |
+
self._add_custom_db_data(db_data=term_data)
|
| 1289 |
+
|
| 1290 |
+
sub_trunc = self._sub_truncations.get_torch_mirror()
|
| 1291 |
+
trunc = self._truncations.get_torch_mirror()
|
| 1292 |
+
sub_truncations_names = self.sub_trunc_names()
|
| 1293 |
+
sub_trunc_data = EpisodicData("SubTruncations", sub_trunc, sub_truncations_names,
|
| 1294 |
+
ep_vec_freq=self._env_opts["vec_ep_freq_metrics_db"],
|
| 1295 |
+
store_transitions=self._full_db,
|
| 1296 |
+
max_ep_duration=self._max_ep_length())
|
| 1297 |
+
sub_trunc_data.set_constant_data_scaling(enable=True,scaling=data_scaling)
|
| 1298 |
+
self._add_custom_db_data(db_data=sub_trunc_data)
|
| 1299 |
+
trunc_data = EpisodicData("Truncations", trunc, ["truncations"],
|
| 1300 |
+
ep_vec_freq=self._env_opts["vec_ep_freq_metrics_db"],
|
| 1301 |
+
store_transitions=self._full_db,
|
| 1302 |
+
max_ep_duration=self._max_ep_length())
|
| 1303 |
+
trunc_data.set_constant_data_scaling(enable=True,scaling=data_scaling)
|
| 1304 |
+
self._add_custom_db_data(db_data=trunc_data)
|
| 1305 |
+
|
| 1306 |
+
def _add_custom_db_data(self, db_data: EpisodicData):
|
| 1307 |
+
self.custom_db_data[db_data.name()] = db_data
|
| 1308 |
+
|
| 1309 |
+
def _init_terminations(self):
|
| 1310 |
+
|
| 1311 |
+
# Boolean array indicating whether each environment episode has terminated after
|
| 1312 |
+
# the current step. An episode termination could occur based on predefined conditions
|
| 1313 |
+
# in the environment, such as reaching a goal or exceeding a time limit.
|
| 1314 |
+
|
| 1315 |
+
self._terminations = Terminations(namespace=self._namespace,
|
| 1316 |
+
n_envs=self._n_envs,
|
| 1317 |
+
is_server=True,
|
| 1318 |
+
verbose=self._verbose,
|
| 1319 |
+
vlevel=self._vlevel,
|
| 1320 |
+
safe=True,
|
| 1321 |
+
force_reconnection=True,
|
| 1322 |
+
with_gpu_mirror=self._use_gpu,
|
| 1323 |
+
fill_value=False)
|
| 1324 |
+
self._terminations.run()
|
| 1325 |
+
|
| 1326 |
+
sub_t_names = self.sub_term_names()
|
| 1327 |
+
self._sub_terminations = SubTerminations(namespace=self._namespace,
|
| 1328 |
+
n_envs=self._n_envs,
|
| 1329 |
+
n_term=len(sub_t_names),
|
| 1330 |
+
term_names=sub_t_names,
|
| 1331 |
+
is_server=True,
|
| 1332 |
+
verbose=self._verbose,
|
| 1333 |
+
vlevel=self._vlevel,
|
| 1334 |
+
safe=True,
|
| 1335 |
+
force_reconnection=True,
|
| 1336 |
+
with_gpu_mirror=self._use_gpu,
|
| 1337 |
+
fill_value=False)
|
| 1338 |
+
self._sub_terminations.run()
|
| 1339 |
+
|
| 1340 |
+
device = "cuda" if self._use_gpu else "cpu"
|
| 1341 |
+
self._is_capsized=torch.zeros((self._n_envs,1),
|
| 1342 |
+
dtype=torch.bool, device=device)
|
| 1343 |
+
self._is_rhc_capsized=torch.zeros((self._n_envs,1),
|
| 1344 |
+
dtype=torch.bool, device=device)
|
| 1345 |
+
self._max_pitch_angle=60.0*math.pi/180.0
|
| 1346 |
+
|
| 1347 |
+
def _init_truncations(self):
|
| 1348 |
+
|
| 1349 |
+
self._truncations = Truncations(namespace=self._namespace,
|
| 1350 |
+
n_envs=self._n_envs,
|
| 1351 |
+
is_server=True,
|
| 1352 |
+
verbose=self._verbose,
|
| 1353 |
+
vlevel=self._vlevel,
|
| 1354 |
+
safe=True,
|
| 1355 |
+
force_reconnection=True,
|
| 1356 |
+
with_gpu_mirror=self._use_gpu,
|
| 1357 |
+
fill_value=False)
|
| 1358 |
+
|
| 1359 |
+
self._truncations.run()
|
| 1360 |
+
|
| 1361 |
+
sub_trc_names = self.sub_trunc_names()
|
| 1362 |
+
self._sub_truncations = SubTruncations(namespace=self._namespace,
|
| 1363 |
+
n_envs=self._n_envs,
|
| 1364 |
+
n_trunc=len(sub_trc_names),
|
| 1365 |
+
truc_names=sub_trc_names,
|
| 1366 |
+
is_server=True,
|
| 1367 |
+
verbose=self._verbose,
|
| 1368 |
+
vlevel=self._vlevel,
|
| 1369 |
+
safe=True,
|
| 1370 |
+
force_reconnection=True,
|
| 1371 |
+
with_gpu_mirror=self._use_gpu,
|
| 1372 |
+
fill_value=False)
|
| 1373 |
+
self._sub_truncations.run()
|
| 1374 |
+
|
| 1375 |
+
def _update_jnt_blacklist(self):
|
| 1376 |
+
device = "cuda" if self._use_gpu else "cpu"
|
| 1377 |
+
all_available_jnts=self.get_observed_joints()
|
| 1378 |
+
blacklist=[]
|
| 1379 |
+
for i in range(len(all_available_jnts)):
|
| 1380 |
+
for pattern in self._jnt_q_blacklist_patterns:
|
| 1381 |
+
if pattern in all_available_jnts[i]:
|
| 1382 |
+
# stop at first pattern match
|
| 1383 |
+
blacklist.append(i)
|
| 1384 |
+
break
|
| 1385 |
+
if not len(blacklist)==0:
|
| 1386 |
+
self._jnt_q_blacklist_idxs=torch.tensor(blacklist, dtype=torch.int, device=device)
|
| 1387 |
+
|
| 1388 |
+
def _attach_to_shared_mem(self):
|
| 1389 |
+
|
| 1390 |
+
# runs shared mem clients for getting observation and setting RHC commands
|
| 1391 |
+
|
| 1392 |
+
# remote stepping data
|
| 1393 |
+
self._remote_stepper = RemoteStepperSrvr(namespace=self._namespace,
|
| 1394 |
+
verbose=self._verbose,
|
| 1395 |
+
vlevel=self._vlevel,
|
| 1396 |
+
force_reconnection=True)
|
| 1397 |
+
self._remote_stepper.run()
|
| 1398 |
+
self._remote_resetter = RemoteResetSrvr(namespace=self._namespace,
|
| 1399 |
+
verbose=self._verbose,
|
| 1400 |
+
vlevel=self._vlevel,
|
| 1401 |
+
force_reconnection=True)
|
| 1402 |
+
self._remote_resetter.run()
|
| 1403 |
+
self._remote_reset_req = RemoteResetRequest(namespace=self._namespace,
|
| 1404 |
+
is_server=False,
|
| 1405 |
+
verbose=self._verbose,
|
| 1406 |
+
vlevel=self._vlevel,
|
| 1407 |
+
safe=True)
|
| 1408 |
+
self._remote_reset_req.run()
|
| 1409 |
+
|
| 1410 |
+
self._jnts_remapping=None
|
| 1411 |
+
self._jnt_q_blacklist_idxs=None
|
| 1412 |
+
|
| 1413 |
+
self._robot_state = RobotState(namespace=self._namespace,
|
| 1414 |
+
is_server=False,
|
| 1415 |
+
safe=self._safe_shared_mem,
|
| 1416 |
+
verbose=self._verbose,
|
| 1417 |
+
vlevel=self._vlevel,
|
| 1418 |
+
with_gpu_mirror=self._use_gpu,
|
| 1419 |
+
with_torch_view=True,
|
| 1420 |
+
enable_height_sensor=self._env_opts["add_heightmap_obs"])
|
| 1421 |
+
|
| 1422 |
+
self._rhc_cmds = RhcCmds(namespace=self._namespace,
|
| 1423 |
+
is_server=False,
|
| 1424 |
+
safe=self._safe_shared_mem,
|
| 1425 |
+
verbose=self._verbose,
|
| 1426 |
+
vlevel=self._vlevel,
|
| 1427 |
+
with_gpu_mirror=self._use_gpu,
|
| 1428 |
+
with_torch_view=True)
|
| 1429 |
+
|
| 1430 |
+
self._rhc_pred = RhcPred(namespace=self._namespace,
|
| 1431 |
+
is_server=False,
|
| 1432 |
+
safe=self._safe_shared_mem,
|
| 1433 |
+
verbose=self._verbose,
|
| 1434 |
+
vlevel=self._vlevel,
|
| 1435 |
+
with_gpu_mirror=self._use_gpu,
|
| 1436 |
+
with_torch_view=True)
|
| 1437 |
+
|
| 1438 |
+
self._rhc_refs = RhcRefs(namespace=self._namespace,
|
| 1439 |
+
is_server=False,
|
| 1440 |
+
safe=self._safe_shared_mem,
|
| 1441 |
+
verbose=self._verbose,
|
| 1442 |
+
vlevel=self._vlevel,
|
| 1443 |
+
with_gpu_mirror=self._use_gpu,
|
| 1444 |
+
with_torch_view=True)
|
| 1445 |
+
|
| 1446 |
+
self._rhc_status = RhcStatus(namespace=self._namespace,
|
| 1447 |
+
is_server=False,
|
| 1448 |
+
verbose=self._verbose,
|
| 1449 |
+
vlevel=self._vlevel,
|
| 1450 |
+
with_gpu_mirror=self._use_gpu,
|
| 1451 |
+
with_torch_view=True)
|
| 1452 |
+
|
| 1453 |
+
self._robot_state.run()
|
| 1454 |
+
self._n_envs = self._robot_state.n_robots()
|
| 1455 |
+
self._n_jnts = self._robot_state.n_jnts()
|
| 1456 |
+
self._n_contacts = self._robot_state.n_contacts() # we assume same n contacts for all rhcs for now
|
| 1457 |
+
|
| 1458 |
+
self._rhc_cmds.run()
|
| 1459 |
+
self._rhc_pred.run()
|
| 1460 |
+
self._rhc_refs.run()
|
| 1461 |
+
self._rhc_status.run()
|
| 1462 |
+
# we read rhc info now and just this time, since it's assumed to be static
|
| 1463 |
+
self._check_controllers_registered(retry=True) # blocking
|
| 1464 |
+
# (we need controllers to be connected to read meaningful data)
|
| 1465 |
+
|
| 1466 |
+
self._rhc_status.rhc_static_info.synch_all(read=True,retry=True)
|
| 1467 |
+
if self._use_gpu:
|
| 1468 |
+
self._rhc_status.rhc_static_info.synch_mirror(from_gpu=False,non_blocking=False)
|
| 1469 |
+
rhc_horizons=self._rhc_status.rhc_static_info.get("horizons",gpu=self._use_gpu)
|
| 1470 |
+
rhc_nnodes=self._rhc_status.rhc_static_info.get("nnodes",gpu=self._use_gpu)
|
| 1471 |
+
rhc_dts=self._rhc_status.rhc_static_info.get("dts",gpu=self._use_gpu)
|
| 1472 |
+
|
| 1473 |
+
# height sensor metadata (client side)
|
| 1474 |
+
if self._env_opts["add_heightmap_obs"]:
|
| 1475 |
+
self._height_grid_size = self._robot_state.height_sensor.grid_size
|
| 1476 |
+
self._height_flat_dim = self._robot_state.height_sensor.n_cols
|
| 1477 |
+
rhc_ncontacts=self._rhc_status.rhc_static_info.get("ncontacts",gpu=self._use_gpu)
|
| 1478 |
+
robot_mass=self._rhc_status.rhc_static_info.get("robot_mass",gpu=self._use_gpu)
|
| 1479 |
+
pred_node_idxs_rhc=self._rhc_status.rhc_static_info.get("pred_node_idx",gpu=self._use_gpu)
|
| 1480 |
+
|
| 1481 |
+
self._n_nodes_rhc=torch.round(rhc_nnodes) # we assume nodes are static during an env lifetime
|
| 1482 |
+
self._rhc_horizons=rhc_horizons
|
| 1483 |
+
self._rhc_dts=rhc_dts
|
| 1484 |
+
self._n_contacts_rhc=rhc_ncontacts
|
| 1485 |
+
self._rhc_robot_masses=robot_mass
|
| 1486 |
+
if (self._rhc_robot_masses == 0).any():
|
| 1487 |
+
zero_indices = torch.nonzero(self._rhc_robot_masses == 0, as_tuple=True)
|
| 1488 |
+
print(zero_indices) # This will print the indices of zero elements
|
| 1489 |
+
Journal.log(self.__class__.__name__,
|
| 1490 |
+
"_attach_to_shared_mem",
|
| 1491 |
+
"Found at least one robot with 0 mass from RHC static info!!",
|
| 1492 |
+
LogType.EXCEP,
|
| 1493 |
+
throw_when_excep=True)
|
| 1494 |
+
|
| 1495 |
+
self._rhc_robot_weight=robot_mass*9.81
|
| 1496 |
+
self._pred_node_idxs_rhc=pred_node_idxs_rhc
|
| 1497 |
+
self._pred_horizon_rhc=self._pred_node_idxs_rhc*self._rhc_dts
|
| 1498 |
+
|
| 1499 |
+
# run server for agent commands
|
| 1500 |
+
self._agent_refs = AgentRefs(namespace=self._namespace,
|
| 1501 |
+
is_server=True,
|
| 1502 |
+
n_robots=self._n_envs,
|
| 1503 |
+
n_jnts=self._robot_state.n_jnts(),
|
| 1504 |
+
n_contacts=self._robot_state.n_contacts(),
|
| 1505 |
+
contact_names=self._robot_state.contact_names(),
|
| 1506 |
+
q_remapping=None,
|
| 1507 |
+
with_gpu_mirror=self._use_gpu,
|
| 1508 |
+
force_reconnection=True,
|
| 1509 |
+
safe=False,
|
| 1510 |
+
verbose=self._verbose,
|
| 1511 |
+
vlevel=self._vlevel,
|
| 1512 |
+
fill_value=0)
|
| 1513 |
+
self._agent_refs.run()
|
| 1514 |
+
q_init_agent_refs=torch.full_like(self._robot_state.root_state.get(data_type="q", gpu=self._use_gpu),fill_value=0.0)
|
| 1515 |
+
q_init_agent_refs[:, 0]=1.0
|
| 1516 |
+
self._agent_refs.rob_refs.root_state.set(data_type="q", data=q_init_agent_refs,
|
| 1517 |
+
gpu=self._use_gpu)
|
| 1518 |
+
if self._use_gpu:
|
| 1519 |
+
self._agent_refs.rob_refs.root_state.synch_mirror(from_gpu=True,non_blocking=True)
|
| 1520 |
+
self._agent_refs.rob_refs.root_state.synch_all(read=False, retry=True)
|
| 1521 |
+
# episode steps counters (for detecting episode truncations for
|
| 1522 |
+
# time limits)
|
| 1523 |
+
self._ep_timeout_counter = EpisodesCounter(namespace=self._namespace,
|
| 1524 |
+
n_envs=self._n_envs,
|
| 1525 |
+
n_steps_lb=self._env_opts["episode_timeout_lb"],
|
| 1526 |
+
n_steps_ub=self._env_opts["episode_timeout_ub"],
|
| 1527 |
+
randomize_offsets_at_startup=True, # this has to be randomized
|
| 1528 |
+
is_server=True,
|
| 1529 |
+
verbose=self._verbose,
|
| 1530 |
+
vlevel=self._vlevel,
|
| 1531 |
+
safe=True,
|
| 1532 |
+
force_reconnection=True,
|
| 1533 |
+
with_gpu_mirror=self._use_gpu,
|
| 1534 |
+
debug=self._debug) # handles step counter through episodes and through envs
|
| 1535 |
+
self._ep_timeout_counter.run()
|
| 1536 |
+
self._task_rand_counter = TaskRandCounter(namespace=self._namespace,
|
| 1537 |
+
n_envs=self._n_envs,
|
| 1538 |
+
n_steps_lb=self._env_opts["n_steps_task_rand_lb"],
|
| 1539 |
+
n_steps_ub=self._env_opts["n_steps_task_rand_ub"],
|
| 1540 |
+
randomize_offsets_at_startup=False, # not necessary since it will be synched with the timeout counter
|
| 1541 |
+
is_server=True,
|
| 1542 |
+
verbose=self._verbose,
|
| 1543 |
+
vlevel=self._vlevel,
|
| 1544 |
+
safe=True,
|
| 1545 |
+
force_reconnection=True,
|
| 1546 |
+
with_gpu_mirror=self._use_gpu,
|
| 1547 |
+
debug=self._debug) # handles step counter through episodes and through envs
|
| 1548 |
+
self._task_rand_counter.run()
|
| 1549 |
+
self._task_rand_counter.sync_counters(other_counter=self._ep_timeout_counter)
|
| 1550 |
+
if self._env_opts["use_random_trunc"]:
|
| 1551 |
+
self._rand_trunc_counter=RandomTruncCounter(namespace=self._namespace,
|
| 1552 |
+
n_envs=self._n_envs,
|
| 1553 |
+
n_steps_lb=self._env_opts["random_trunc_freq"]-self._env_opts["random_trunc_freq_delta"],
|
| 1554 |
+
n_steps_ub=self._env_opts["random_trunc_freq"],
|
| 1555 |
+
randomize_offsets_at_startup=True,
|
| 1556 |
+
is_server=True,
|
| 1557 |
+
verbose=self._verbose,
|
| 1558 |
+
vlevel=self._vlevel,
|
| 1559 |
+
safe=True,
|
| 1560 |
+
force_reconnection=True,
|
| 1561 |
+
with_gpu_mirror=self._use_gpu,
|
| 1562 |
+
debug=False)
|
| 1563 |
+
self._rand_trunc_counter.run()
|
| 1564 |
+
# self._rand_trunc_counter.sync_counters(other_counter=self._ep_timeout_counter)
|
| 1565 |
+
if self._env_opts["use_random_safety_reset"]:
|
| 1566 |
+
self._rand_safety_reset_counter=SafetyRandResetsCounter(namespace=self._namespace,
|
| 1567 |
+
n_envs=self._n_envs,
|
| 1568 |
+
n_steps_lb=self._env_opts["random_reset_freq"],
|
| 1569 |
+
n_steps_ub=self._env_opts["random_reset_freq"],
|
| 1570 |
+
randomize_offsets_at_startup=True,
|
| 1571 |
+
is_server=True,
|
| 1572 |
+
verbose=self._verbose,
|
| 1573 |
+
vlevel=self._vlevel,
|
| 1574 |
+
safe=True,
|
| 1575 |
+
force_reconnection=True,
|
| 1576 |
+
with_gpu_mirror=self._use_gpu,
|
| 1577 |
+
debug=False)
|
| 1578 |
+
self._rand_safety_reset_counter.run()
|
| 1579 |
+
# self._rand_safety_reset_counter.sync_counters(other_counter=self._ep_timeout_counter)
|
| 1580 |
+
|
| 1581 |
+
# timer to track abs time in each env (reset logic to be implemented in child)
|
| 1582 |
+
self._substep_abs_counter = SubStepAbsCounter(namespace=self._namespace,
|
| 1583 |
+
n_envs=self._n_envs,
|
| 1584 |
+
n_steps_lb=1e9,
|
| 1585 |
+
n_steps_ub=1e9,
|
| 1586 |
+
randomize_offsets_at_startup=True, # randomizing startup offsets
|
| 1587 |
+
is_server=True,
|
| 1588 |
+
verbose=self._verbose,
|
| 1589 |
+
vlevel=self._vlevel,
|
| 1590 |
+
safe=True,
|
| 1591 |
+
force_reconnection=True,
|
| 1592 |
+
with_gpu_mirror=self._use_gpu,
|
| 1593 |
+
debug=self._debug)
|
| 1594 |
+
self._substep_abs_counter.run()
|
| 1595 |
+
|
| 1596 |
+
# debug data servers
|
| 1597 |
+
traing_env_param_dict = {}
|
| 1598 |
+
traing_env_param_dict["use_gpu"] = self._use_gpu
|
| 1599 |
+
traing_env_param_dict["debug"] = self._is_debug
|
| 1600 |
+
traing_env_param_dict["n_preinit_steps"] = self._env_opts["n_preinit_steps"]
|
| 1601 |
+
traing_env_param_dict["n_preinit_steps"] = self._n_envs
|
| 1602 |
+
|
| 1603 |
+
self._training_sim_info = SharedTrainingEnvInfo(namespace=self._namespace,
|
| 1604 |
+
is_server=True,
|
| 1605 |
+
training_env_params_dict=traing_env_param_dict,
|
| 1606 |
+
safe=False,
|
| 1607 |
+
force_reconnection=True,
|
| 1608 |
+
verbose=self._verbose,
|
| 1609 |
+
vlevel=self._vlevel)
|
| 1610 |
+
self._training_sim_info.run()
|
| 1611 |
+
|
| 1612 |
+
self._observed_jnt_names=self.set_observed_joints()
|
| 1613 |
+
self._set_jnts_blacklist_pattern()
|
| 1614 |
+
self._update_jnt_blacklist()
|
| 1615 |
+
|
| 1616 |
+
self._prev_root_p_substep=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu).clone()
|
| 1617 |
+
self._prev_root_q_substep=self._robot_state.root_state.get(data_type="q",gpu=self._use_gpu).clone()
|
| 1618 |
+
self._prev_root_p_step=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu).clone()
|
| 1619 |
+
self._prev_root_q_step=self._robot_state.root_state.get(data_type="q",gpu=self._use_gpu).clone()
|
| 1620 |
+
|
| 1621 |
+
def _activate_rhc_controllers(self):
|
| 1622 |
+
self._rhc_status.activation_state.get_torch_mirror()[:, :] = True
|
| 1623 |
+
self._rhc_status.activation_state.synch_all(read=False, retry=True) # activates all controllers
|
| 1624 |
+
|
| 1625 |
+
def _synch_state(self,
|
| 1626 |
+
gpu: bool = True):
|
| 1627 |
+
|
| 1628 |
+
# read from shared memory on CPU
|
| 1629 |
+
# robot state
|
| 1630 |
+
self._robot_state.root_state.synch_all(read = True, retry = True)
|
| 1631 |
+
self._robot_state.jnts_state.synch_all(read = True, retry = True)
|
| 1632 |
+
# rhc cmds
|
| 1633 |
+
self._rhc_cmds.root_state.synch_all(read = True, retry = True)
|
| 1634 |
+
self._rhc_cmds.jnts_state.synch_all(read = True, retry = True)
|
| 1635 |
+
self._rhc_cmds.contact_wrenches.synch_all(read = True, retry = True)
|
| 1636 |
+
# rhc pred
|
| 1637 |
+
self._rhc_pred.root_state.synch_all(read = True, retry = True)
|
| 1638 |
+
# self._rhc_pred.jnts_state.synch_all(read = True, retry = True)
|
| 1639 |
+
# self._rhc_pred.contact_wrenches.synch_all(read = True, retry = True)
|
| 1640 |
+
# refs for root link and contacts
|
| 1641 |
+
self._rhc_refs.rob_refs.root_state.synch_all(read = True, retry = True)
|
| 1642 |
+
self._rhc_refs.contact_flags.synch_all(read = True, retry = True)
|
| 1643 |
+
self._rhc_refs.flight_info.synch_all(read = True, retry = True)
|
| 1644 |
+
self._rhc_refs.flight_settings_req.synch_all(read = True, retry = True)
|
| 1645 |
+
self._rhc_refs.rob_refs.contact_pos.synch_all(read = True, retry = True)
|
| 1646 |
+
# rhc cost
|
| 1647 |
+
self._rhc_status.rhc_cost.synch_all(read = True, retry = True)
|
| 1648 |
+
# rhc constr. violations
|
| 1649 |
+
self._rhc_status.rhc_constr_viol.synch_all(read = True, retry = True)
|
| 1650 |
+
# failure states
|
| 1651 |
+
self._rhc_status.fails.synch_all(read = True, retry = True)
|
| 1652 |
+
# tot cost and cnstr viol on nodes + step variable
|
| 1653 |
+
self._rhc_status.rhc_nodes_cost.synch_all(read = True, retry = True)
|
| 1654 |
+
self._rhc_status.rhc_nodes_constr_viol.synch_all(read = True, retry = True)
|
| 1655 |
+
self._rhc_status.rhc_fcn.synch_all(read = True, retry = True)
|
| 1656 |
+
self._rhc_status.rhc_fail_idx.synch_all(read = True, retry = True)
|
| 1657 |
+
if self._env_opts["add_heightmap_obs"]:
|
| 1658 |
+
self._robot_state.height_sensor.synch_all(read=True, retry=True)
|
| 1659 |
+
if gpu:
|
| 1660 |
+
# copies data to "mirror" on GPU --> we can do it non-blocking since
|
| 1661 |
+
# in this direction it should be safe
|
| 1662 |
+
self._robot_state.root_state.synch_mirror(from_gpu=False,non_blocking=True) # copies shared data on GPU
|
| 1663 |
+
self._robot_state.jnts_state.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1664 |
+
self._rhc_cmds.root_state.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1665 |
+
self._rhc_cmds.jnts_state.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1666 |
+
self._rhc_cmds.contact_wrenches.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1667 |
+
self._rhc_pred.root_state.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1668 |
+
# self._rhc_pred.jnts_state.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1669 |
+
# self._rhc_pred.contact_wrenches.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1670 |
+
self._rhc_refs.rob_refs.root_state.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1671 |
+
self._rhc_refs.contact_flags.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1672 |
+
self._rhc_refs.rob_refs.contact_pos.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1673 |
+
self._rhc_refs.flight_info.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1674 |
+
self._rhc_refs.flight_settings_req.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1675 |
+
self._rhc_status.rhc_cost.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1676 |
+
self._rhc_status.rhc_constr_viol.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1677 |
+
self._rhc_status.fails.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1678 |
+
self._rhc_status.rhc_nodes_cost.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1679 |
+
self._rhc_status.rhc_nodes_constr_viol.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1680 |
+
self._rhc_status.rhc_fcn.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1681 |
+
self._rhc_status.rhc_fail_idx.synch_mirror(from_gpu=False,non_blocking=True)
|
| 1682 |
+
if self._env_opts["add_heightmap_obs"]:
|
| 1683 |
+
self._robot_state.height_sensor.synch_mirror(from_gpu=False, non_blocking=True)
|
| 1684 |
+
torch.cuda.synchronize() # ensuring that all the streams on the GPU are completed \
|
| 1685 |
+
# before the CPU continues execution
|
| 1686 |
+
|
| 1687 |
+
def _override_refs(self,
|
| 1688 |
+
env_indxs: torch.Tensor = None):
|
| 1689 |
+
|
| 1690 |
+
# just used for setting agent refs externally (i.e. from shared mem on CPU)
|
| 1691 |
+
self._agent_refs.rob_refs.root_state.synch_all(read=True,retry=True) # first read from mem
|
| 1692 |
+
if self._use_gpu:
|
| 1693 |
+
# copies latest refs to GPU
|
| 1694 |
+
self._agent_refs.rob_refs.root_state.synch_mirror(from_gpu=False,non_blocking=False)
|
| 1695 |
+
|
| 1696 |
+
def _clamp_obs(self,
|
| 1697 |
+
obs: torch.Tensor):
|
| 1698 |
+
if self._is_debug:
|
| 1699 |
+
self._check_finite(obs, "observations", False)
|
| 1700 |
+
torch.nan_to_num(input=obs, out=obs, nan=self._obs_threshold_ub,
|
| 1701 |
+
posinf=self._obs_threshold_ub,
|
| 1702 |
+
neginf=self._obs_threshold_lb) # prevent nans
|
| 1703 |
+
|
| 1704 |
+
obs.clamp_(self._obs_threshold_lb, self._obs_threshold_ub)
|
| 1705 |
+
|
| 1706 |
+
def _clamp_rewards(self,
|
| 1707 |
+
rewards: torch.Tensor):
|
| 1708 |
+
if self._is_debug:
|
| 1709 |
+
self._check_finite(rewards, "rewards", False)
|
| 1710 |
+
torch.nan_to_num(input=rewards, out=rewards, nan=0.0,
|
| 1711 |
+
posinf=None,
|
| 1712 |
+
neginf=None) # prevent nans
|
| 1713 |
+
rewards.clamp_(self._reward_thresh_lb, self._reward_thresh_ub)
|
| 1714 |
+
|
| 1715 |
+
def get_actions_lb(self):
|
| 1716 |
+
return self._actions_lb
|
| 1717 |
+
|
| 1718 |
+
def get_actions_ub(self):
|
| 1719 |
+
return self._actions_ub
|
| 1720 |
+
|
| 1721 |
+
def get_actions_scale(self):
|
| 1722 |
+
return self._actions_scale
|
| 1723 |
+
|
| 1724 |
+
def get_actions_offset(self):
|
| 1725 |
+
return self._actions_offset
|
| 1726 |
+
|
| 1727 |
+
def get_obs_lb(self):
|
| 1728 |
+
return self._obs_lb
|
| 1729 |
+
|
| 1730 |
+
def get_obs_ub(self):
|
| 1731 |
+
return self._obs_ub
|
| 1732 |
+
|
| 1733 |
+
def get_obs_scale(self):
|
| 1734 |
+
self._obs_scale = (self._obs_ub - self._obs_lb)/2.0
|
| 1735 |
+
return self._obs_scale
|
| 1736 |
+
|
| 1737 |
+
def get_obs_offset(self):
|
| 1738 |
+
self._obs_offset = (self._obs_ub + self._obs_lb)/2.0
|
| 1739 |
+
return self._obs_offset
|
| 1740 |
+
|
| 1741 |
+
def switch_random_reset(self, on: bool = True):
|
| 1742 |
+
self._random_reset_active=on
|
| 1743 |
+
|
| 1744 |
+
def set_jnts_remapping(self,
|
| 1745 |
+
remapping: List = None):
|
| 1746 |
+
|
| 1747 |
+
self._jnts_remapping=remapping
|
| 1748 |
+
if self._jnts_remapping is not None:
|
| 1749 |
+
self._robot_state.set_jnts_remapping(jnts_remapping=self._jnts_remapping)
|
| 1750 |
+
self._rhc_cmds.set_jnts_remapping(jnts_remapping=self._jnts_remapping)
|
| 1751 |
+
self._rhc_pred.set_jnts_remapping(jnts_remapping=self._jnts_remapping)
|
| 1752 |
+
# we need to also update the list of observed joints to match
|
| 1753 |
+
available_joints=self._robot_state.jnt_names()
|
| 1754 |
+
# the remapping ordering
|
| 1755 |
+
self._observed_jnt_names=[]
|
| 1756 |
+
for i in range(len(available_joints)):
|
| 1757 |
+
self._observed_jnt_names.append(available_joints[self._jnts_remapping[i]])
|
| 1758 |
+
|
| 1759 |
+
self._update_jnt_blacklist()
|
| 1760 |
+
|
| 1761 |
+
updated_obs_names=self._get_obs_names() # get updated obs names (should use get_observed_joints
|
| 1762 |
+
# internally, so that jnt names are updated)
|
| 1763 |
+
|
| 1764 |
+
# also update jnt obs names on shared memory
|
| 1765 |
+
names_old=self._obs.get_obs_names()
|
| 1766 |
+
names_old_next=self._next_obs.get_obs_names()
|
| 1767 |
+
names_old[:]=updated_obs_names
|
| 1768 |
+
names_old_next[:]=updated_obs_names
|
| 1769 |
+
self._obs.update_names()
|
| 1770 |
+
self._next_obs.update_names()
|
| 1771 |
+
|
| 1772 |
+
# also update
|
| 1773 |
+
if "Obs" in self.custom_db_data:
|
| 1774 |
+
db_obs_names=self.custom_db_data["Obs"].data_names()
|
| 1775 |
+
db_obs_names[:]=updated_obs_names
|
| 1776 |
+
|
| 1777 |
+
def _check_finite(self,
|
| 1778 |
+
tensor: torch.Tensor,
|
| 1779 |
+
name: str,
|
| 1780 |
+
throw: bool = False):
|
| 1781 |
+
if not torch.isfinite(tensor).all().item():
|
| 1782 |
+
exception = f"Found nonfinite elements in {name} tensor!!"
|
| 1783 |
+
non_finite_idxs=torch.nonzero(~torch.isfinite(tensor))
|
| 1784 |
+
n_nonf_elems=non_finite_idxs.shape[0]
|
| 1785 |
+
|
| 1786 |
+
if name=="observations":
|
| 1787 |
+
for i in range(n_nonf_elems):
|
| 1788 |
+
db_msg=f"{self.obs_names()[non_finite_idxs[i,1]]} (env. {non_finite_idxs[i,0]}):" + \
|
| 1789 |
+
f" {tensor[non_finite_idxs[i,0],non_finite_idxs[i,1]].item()}"
|
| 1790 |
+
print(db_msg)
|
| 1791 |
+
if name=="rewards":
|
| 1792 |
+
for i in range(n_nonf_elems):
|
| 1793 |
+
db_msg=f"{self.sub_rew_names()[non_finite_idxs[i,1]]} (env. {non_finite_idxs[i,0]}):" + \
|
| 1794 |
+
f" {tensor[non_finite_idxs[i,0],non_finite_idxs[i,1]].item()}"
|
| 1795 |
+
print(db_msg)
|
| 1796 |
+
print(tensor)
|
| 1797 |
+
Journal.log(self.__class__.__name__,
|
| 1798 |
+
"_check_finite",
|
| 1799 |
+
exception,
|
| 1800 |
+
LogType.EXCEP,
|
| 1801 |
+
throw_when_excep = throw)
|
| 1802 |
+
|
| 1803 |
+
def _check_controllers_registered(self,
|
| 1804 |
+
retry: bool = False):
|
| 1805 |
+
|
| 1806 |
+
if retry:
|
| 1807 |
+
self._rhc_status.controllers_counter.synch_all(read=True, retry=True)
|
| 1808 |
+
n_connected_controllers = self._rhc_status.controllers_counter.get_torch_mirror()[0, 0].item()
|
| 1809 |
+
while not (n_connected_controllers == self._n_envs):
|
| 1810 |
+
warn = f"Expected {self._n_envs} controllers to be connected during training, " + \
|
| 1811 |
+
f"but got {n_connected_controllers}. Will wait for all to be connected..."
|
| 1812 |
+
Journal.log(self.__class__.__name__,
|
| 1813 |
+
"_check_controllers_registered",
|
| 1814 |
+
warn,
|
| 1815 |
+
LogType.WARN,
|
| 1816 |
+
throw_when_excep = False)
|
| 1817 |
+
nsecs = int(2 * 1000000000)
|
| 1818 |
+
PerfSleep.thread_sleep(nsecs)
|
| 1819 |
+
self._rhc_status.controllers_counter.synch_all(read=True, retry=True)
|
| 1820 |
+
n_connected_controllers = self._rhc_status.controllers_counter.get_torch_mirror()[0, 0].item()
|
| 1821 |
+
info = f"All {n_connected_controllers} controllers connected!"
|
| 1822 |
+
Journal.log(self.__class__.__name__,
|
| 1823 |
+
"_check_controllers_registered",
|
| 1824 |
+
info,
|
| 1825 |
+
LogType.INFO,
|
| 1826 |
+
throw_when_excep = False)
|
| 1827 |
+
return True
|
| 1828 |
+
else:
|
| 1829 |
+
self._rhc_status.controllers_counter.synch_all(read=True, retry=True)
|
| 1830 |
+
n_connected_controllers = self._rhc_status.controllers_counter.get_torch_mirror()[0, 0].item()
|
| 1831 |
+
if not (n_connected_controllers == self._n_envs):
|
| 1832 |
+
exception = f"Expected {self._n_envs} controllers to be connected during training, " + \
|
| 1833 |
+
f"but got {n_connected_controllers}. Aborting..."
|
| 1834 |
+
Journal.log(self.__class__.__name__,
|
| 1835 |
+
"_check_controllers_registered",
|
| 1836 |
+
exception,
|
| 1837 |
+
LogType.EXCEP,
|
| 1838 |
+
throw_when_excep = False)
|
| 1839 |
+
return False
|
| 1840 |
+
return True
|
| 1841 |
+
|
| 1842 |
+
def _check_truncations(self):
|
| 1843 |
+
|
| 1844 |
+
self._check_sub_truncations()
|
| 1845 |
+
sub_truncations = self._sub_truncations.get_torch_mirror(gpu=self._use_gpu)
|
| 1846 |
+
truncations = self._truncations.get_torch_mirror(gpu=self._use_gpu)
|
| 1847 |
+
truncations[:, :] = torch.any(sub_truncations,dim=1,keepdim=True)
|
| 1848 |
+
|
| 1849 |
+
def _check_terminations(self):
|
| 1850 |
+
|
| 1851 |
+
self._check_sub_terminations()
|
| 1852 |
+
sub_terminations = self._sub_terminations.get_torch_mirror(gpu=self._use_gpu)
|
| 1853 |
+
terminations = self._terminations.get_torch_mirror(gpu=self._use_gpu)
|
| 1854 |
+
terminations[:, :] = torch.any(sub_terminations,dim=1,keepdim=True)
|
| 1855 |
+
|
| 1856 |
+
def _check_sub_truncations(self):
|
| 1857 |
+
# default behaviour-> to be overriden by child
|
| 1858 |
+
sub_truncations = self._sub_truncations.get_torch_mirror(gpu=self._use_gpu)
|
| 1859 |
+
sub_truncations[:, 0:1]=self._ep_timeout_counter.time_limits_reached()
|
| 1860 |
+
|
| 1861 |
+
def _check_sub_terminations(self):
|
| 1862 |
+
# default behaviour-> to be overriden by child
|
| 1863 |
+
sub_terminations = self._sub_terminations.get_torch_mirror(gpu=self._use_gpu)
|
| 1864 |
+
robot_q_meas = self._robot_state.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 1865 |
+
robot_q_pred = self._rhc_cmds.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 1866 |
+
|
| 1867 |
+
# terminate when either the real robot or the prediction from the MPC are capsized
|
| 1868 |
+
check_capsize(quat=robot_q_meas,max_angle=self._max_pitch_angle,
|
| 1869 |
+
output_t=self._is_capsized)
|
| 1870 |
+
check_capsize(quat=robot_q_pred,max_angle=self._max_pitch_angle,
|
| 1871 |
+
output_t=self._is_rhc_capsized)
|
| 1872 |
+
|
| 1873 |
+
sub_terminations[:, 0:1] = self._rhc_status.fails.get_torch_mirror(gpu=self._use_gpu)
|
| 1874 |
+
sub_terminations[:, 1:2] = self._is_capsized
|
| 1875 |
+
sub_terminations[:, 2:3] = self._is_rhc_capsized
|
| 1876 |
+
|
| 1877 |
+
def is_action_continuous(self):
|
| 1878 |
+
return self._is_continuous_actions
|
| 1879 |
+
|
| 1880 |
+
def is_action_discrete(self):
|
| 1881 |
+
return ~self._is_continuous_actions
|
| 1882 |
+
|
| 1883 |
+
@abstractmethod
|
| 1884 |
+
def _pre_substep(self):
|
| 1885 |
+
pass
|
| 1886 |
+
|
| 1887 |
+
@abstractmethod
|
| 1888 |
+
def _custom_post_step(self,episode_finished):
|
| 1889 |
+
pass
|
| 1890 |
+
|
| 1891 |
+
@abstractmethod
|
| 1892 |
+
def _custom_post_substp_post_rew(self):
|
| 1893 |
+
pass
|
| 1894 |
+
|
| 1895 |
+
@abstractmethod
|
| 1896 |
+
def _custom_post_substp_pre_rew(self):
|
| 1897 |
+
pass
|
| 1898 |
+
|
| 1899 |
+
@abstractmethod
|
| 1900 |
+
def _apply_actions_to_rhc(self):
|
| 1901 |
+
pass
|
| 1902 |
+
|
| 1903 |
+
def _override_actions_with_demo(self):
|
| 1904 |
+
pass
|
| 1905 |
+
|
| 1906 |
+
@abstractmethod
|
| 1907 |
+
def _compute_substep_rewards(self):
|
| 1908 |
+
pass
|
| 1909 |
+
|
| 1910 |
+
@abstractmethod
|
| 1911 |
+
def _set_substep_rew(self):
|
| 1912 |
+
pass
|
| 1913 |
+
|
| 1914 |
+
@abstractmethod
|
| 1915 |
+
def _set_substep_obs(self):
|
| 1916 |
+
pass
|
| 1917 |
+
|
| 1918 |
+
@abstractmethod
|
| 1919 |
+
def _compute_step_rewards(self):
|
| 1920 |
+
pass
|
| 1921 |
+
|
| 1922 |
+
@abstractmethod
|
| 1923 |
+
def _fill_substep_obs(self,
|
| 1924 |
+
obs: torch.Tensor):
|
| 1925 |
+
pass
|
| 1926 |
+
|
| 1927 |
+
@abstractmethod
|
| 1928 |
+
def _fill_step_obs(self,
|
| 1929 |
+
obs: torch.Tensor):
|
| 1930 |
+
pass
|
| 1931 |
+
|
| 1932 |
+
@abstractmethod
|
| 1933 |
+
def _randomize_task_refs(self,
|
| 1934 |
+
env_indxs: torch.Tensor = None):
|
| 1935 |
+
pass
|
| 1936 |
+
|
| 1937 |
+
def _custom_post_init(self):
|
| 1938 |
+
pass
|
| 1939 |
+
|
| 1940 |
+
def _get_avrg_substep_root_twist(self,
|
| 1941 |
+
out: torch.Tensor,
|
| 1942 |
+
base_loc: bool = True):
|
| 1943 |
+
# to be called at each substep
|
| 1944 |
+
robot_p_meas = self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)
|
| 1945 |
+
robot_q_meas = self._robot_state.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 1946 |
+
|
| 1947 |
+
root_v_avrg_w=(robot_p_meas-self._prev_root_p_substep)/self._substep_dt
|
| 1948 |
+
root_omega_avrg_w=quaternion_to_angular_velocity(q_diff=quaternion_difference(self._prev_root_q_substep,robot_q_meas),\
|
| 1949 |
+
dt=self._substep_dt)
|
| 1950 |
+
twist_w=torch.cat((root_v_avrg_w,
|
| 1951 |
+
root_omega_avrg_w),
|
| 1952 |
+
dim=1)
|
| 1953 |
+
if not base_loc:
|
| 1954 |
+
self._prev_root_p_substep[:, :]=robot_p_meas
|
| 1955 |
+
self._prev_root_q_substep[:, :]=robot_q_meas
|
| 1956 |
+
out[:, :]=twist_w
|
| 1957 |
+
# rotate using the current (end-of-substep) orientation for consistency with other signals
|
| 1958 |
+
world2base_frame(t_w=twist_w, q_b=robot_q_meas, t_out=out)
|
| 1959 |
+
self._prev_root_p_substep[:, :]=robot_p_meas
|
| 1960 |
+
self._prev_root_q_substep[:, :]=robot_q_meas
|
| 1961 |
+
|
| 1962 |
+
def _get_avrg_step_root_twist(self,
|
| 1963 |
+
out: torch.Tensor,
|
| 1964 |
+
base_loc: bool = True):
|
| 1965 |
+
# to be called after substeps of actions repeats
|
| 1966 |
+
robot_p_meas = self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)
|
| 1967 |
+
robot_q_meas = self._robot_state.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 1968 |
+
|
| 1969 |
+
dt=self._substep_dt*self._action_repeat # accounting for frame skipping
|
| 1970 |
+
root_v_avrg_w=(robot_p_meas-self._prev_root_p_step)/(dt)
|
| 1971 |
+
root_omega_avrg_w=quaternion_to_angular_velocity(q_diff=quaternion_difference(self._prev_root_q_step,robot_q_meas),\
|
| 1972 |
+
dt=dt)
|
| 1973 |
+
twist_w=torch.cat((root_v_avrg_w,
|
| 1974 |
+
root_omega_avrg_w),
|
| 1975 |
+
dim=1)
|
| 1976 |
+
if not base_loc:
|
| 1977 |
+
out[:, :]=twist_w
|
| 1978 |
+
# rotate using the current (end-of-step) orientation for consistency with other signals
|
| 1979 |
+
world2base_frame(t_w=twist_w, q_b=robot_q_meas, t_out=out)
|
| 1980 |
+
|
| 1981 |
+
def _get_avrg_rhc_root_twist(self,
|
| 1982 |
+
out: torch.Tensor,
|
| 1983 |
+
base_loc: bool = True):
|
| 1984 |
+
|
| 1985 |
+
rhc_root_p =self._rhc_cmds.root_state.get(data_type="p",gpu=self._use_gpu)
|
| 1986 |
+
rhc_root_q =self._rhc_cmds.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 1987 |
+
rhc_root_p_pred =self._rhc_pred.root_state.get(data_type="p",gpu=self._use_gpu)
|
| 1988 |
+
rhc_root_q_pred =self._rhc_pred.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 1989 |
+
|
| 1990 |
+
rhc_root_v_avrg_rhc_w=(rhc_root_p_pred-rhc_root_p)/self._pred_horizon_rhc
|
| 1991 |
+
rhc_root_omega_avrg_rhc_w=quaternion_to_angular_velocity(q_diff=quaternion_difference(rhc_root_q,rhc_root_q_pred),\
|
| 1992 |
+
dt=self._pred_horizon_rhc)
|
| 1993 |
+
|
| 1994 |
+
rhc_pred_avrg_twist_rhc_w = torch.cat((rhc_root_v_avrg_rhc_w,
|
| 1995 |
+
rhc_root_omega_avrg_rhc_w),
|
| 1996 |
+
dim=1)
|
| 1997 |
+
if not base_loc:
|
| 1998 |
+
out[:, :]=rhc_pred_avrg_twist_rhc_w
|
| 1999 |
+
# to rhc base frame (using first node as reference)
|
| 2000 |
+
world2base_frame(t_w=rhc_pred_avrg_twist_rhc_w, q_b=rhc_root_q, t_out=out)
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/twist_tracking_env.py
ADDED
|
@@ -0,0 +1,1396 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Dict
|
| 2 |
+
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
import torch
|
| 6 |
+
|
| 7 |
+
from EigenIPC.PyEigenIPC import VLevel, LogType, Journal
|
| 8 |
+
|
| 9 |
+
from mpc_hive.utilities.shared_data.rhc_data import RobotState, RhcStatus, RhcRefs
|
| 10 |
+
from mpc_hive.utilities.math_utils_torch import world2base_frame, base2world_frame, w2hor_frame
|
| 11 |
+
|
| 12 |
+
from aug_mpc.utils.sys_utils import PathsGetter
|
| 13 |
+
from aug_mpc.utils.timers import PeriodicTimer
|
| 14 |
+
from aug_mpc.utils.episodic_data import EpisodicData
|
| 15 |
+
from aug_mpc.utils.signal_smoother import ExponentialSignalSmoother
|
| 16 |
+
from aug_mpc.utils.math_utils import check_capsize
|
| 17 |
+
from aug_mpc.training_envs.training_env_base import AugMPCTrainingEnvBase
|
| 18 |
+
|
| 19 |
+
class TwistTrackingEnv(AugMPCTrainingEnvBase):
|
| 20 |
+
"""Base AugMPC training env that tracks commanded twists by pushing velocity and contact targets into the RHC controller while handling locomotion rewards/resets."""
|
| 21 |
+
|
| 22 |
+
def __init__(self,
|
| 23 |
+
namespace: str,
|
| 24 |
+
actions_dim: int = 10,
|
| 25 |
+
verbose: bool = False,
|
| 26 |
+
vlevel: VLevel = VLevel.V1,
|
| 27 |
+
use_gpu: bool = True,
|
| 28 |
+
dtype: torch.dtype = torch.float32,
|
| 29 |
+
debug: bool = True,
|
| 30 |
+
override_agent_refs: bool = False,
|
| 31 |
+
timeout_ms: int = 60000,
|
| 32 |
+
env_opts: Dict = {}):
|
| 33 |
+
|
| 34 |
+
env_name = "LinVelTrack"
|
| 35 |
+
device = "cuda" if use_gpu else "cpu"
|
| 36 |
+
|
| 37 |
+
self._add_env_opt(env_opts, "srew_drescaling",
|
| 38 |
+
False)
|
| 39 |
+
|
| 40 |
+
self._add_env_opt(env_opts, "step_thresh", 0.) # when step action < thresh, a step is requested
|
| 41 |
+
|
| 42 |
+
# counters settings
|
| 43 |
+
self._add_env_opt(env_opts, "single_task_ref_per_episode",
|
| 44 |
+
True # if True, the task ref is constant over the episode (ie
|
| 45 |
+
# episodes are truncated when task is changed)
|
| 46 |
+
)
|
| 47 |
+
self._add_env_opt(env_opts, "add_angvel_ref_rand", default=True) # randomize also agular vel ref (just z component)
|
| 48 |
+
|
| 49 |
+
self._add_env_opt(env_opts, "episode_timeout_lb",
|
| 50 |
+
1024)
|
| 51 |
+
self._add_env_opt(env_opts, "episode_timeout_ub",
|
| 52 |
+
1024)
|
| 53 |
+
self._add_env_opt(env_opts, "n_steps_task_rand_lb",
|
| 54 |
+
512)
|
| 55 |
+
self._add_env_opt(env_opts, "n_steps_task_rand_ub",
|
| 56 |
+
512)
|
| 57 |
+
self._add_env_opt(env_opts, "use_random_safety_reset",
|
| 58 |
+
True)
|
| 59 |
+
self._add_env_opt(env_opts, "random_reset_freq",
|
| 60 |
+
10) # a random reset once every n-episodes (per env)
|
| 61 |
+
self._add_env_opt(env_opts, "use_random_trunc",
|
| 62 |
+
True)
|
| 63 |
+
self._add_env_opt(env_opts, "random_trunc_freq",
|
| 64 |
+
env_opts["episode_timeout_ub"]*5) # to remove temporal correlations between envs
|
| 65 |
+
self._add_env_opt(env_opts, "random_trunc_freq_delta",
|
| 66 |
+
env_opts["episode_timeout_ub"]*2) # to randomize trunc frequency between envs
|
| 67 |
+
|
| 68 |
+
if not env_opts["single_task_ref_per_episode"]:
|
| 69 |
+
env_opts["random_reset_freq"]=int(env_opts["random_reset_freq"]/\
|
| 70 |
+
(env_opts["episode_timeout_lb"]/float(env_opts["n_steps_task_rand_lb"])))
|
| 71 |
+
|
| 72 |
+
self._add_env_opt(env_opts, "action_repeat", 1) # frame skipping (different agent action every action_repeat
|
| 73 |
+
# env substeps)
|
| 74 |
+
|
| 75 |
+
self._add_env_opt(env_opts, "n_preinit_steps", 1) # n steps of the controllers to properly initialize everything
|
| 76 |
+
|
| 77 |
+
self._add_env_opt(env_opts, "vec_ep_freq_metrics_db", 1) # n eps over which debug metrics are reported
|
| 78 |
+
self._add_env_opt(env_opts, "demo_envs_perc", 0.0)
|
| 79 |
+
self._add_env_opt(env_opts, "max_cmd_v", 1.5) # maximum cmd v for lin v actions (single component)
|
| 80 |
+
self._add_env_opt(env_opts, "max_cmd_omega", 1.0) # maximum cmd v for omega v actions (single component)
|
| 81 |
+
|
| 82 |
+
# action smoothing
|
| 83 |
+
self._add_env_opt(env_opts, "use_action_smoothing", False)
|
| 84 |
+
self._add_env_opt(env_opts, "smoothing_horizon_c", 0.01)
|
| 85 |
+
self._add_env_opt(env_opts, "smoothing_horizon_d", 0.03)
|
| 86 |
+
|
| 87 |
+
# whether to smooth vel error signal
|
| 88 |
+
self._add_env_opt(env_opts, "use_track_reward_smoother", False)
|
| 89 |
+
self._add_env_opt(env_opts, "smoothing_horizon_vel_err", 0.08)
|
| 90 |
+
self._add_env_opt(env_opts, "track_rew_smoother", None)
|
| 91 |
+
|
| 92 |
+
# rewards
|
| 93 |
+
self._reward_map={}
|
| 94 |
+
self._reward_lb_map={}
|
| 95 |
+
|
| 96 |
+
self._add_env_opt(env_opts, "reward_lb_default", -0.5)
|
| 97 |
+
self._add_env_opt(env_opts, "reward_ub_default", 1e6)
|
| 98 |
+
|
| 99 |
+
self._add_env_opt(env_opts, "task_error_reward_lb", -0.5)
|
| 100 |
+
self._add_env_opt(env_opts, "CoT_reward_lb", -0.5)
|
| 101 |
+
self._add_env_opt(env_opts, "power_reward_lb", -0.5)
|
| 102 |
+
self._add_env_opt(env_opts, "action_rate_reward_lb", -0.5)
|
| 103 |
+
self._add_env_opt(env_opts, "jnt_vel_reward_lb", -0.5)
|
| 104 |
+
self._add_env_opt(env_opts, "rhc_avrg_vel_reward_lb", -0.5)
|
| 105 |
+
|
| 106 |
+
self._add_env_opt(env_opts, "add_power_reward", False)
|
| 107 |
+
self._add_env_opt(env_opts, "add_CoT_reward", True)
|
| 108 |
+
self._add_env_opt(env_opts, "use_CoT_wrt_ref", False)
|
| 109 |
+
self._add_env_opt(env_opts, "add_action_rate_reward", True)
|
| 110 |
+
self._add_env_opt(env_opts, "add_jnt_v_reward", False)
|
| 111 |
+
|
| 112 |
+
self._add_env_opt(env_opts, "use_rhc_avrg_vel_tracking", False)
|
| 113 |
+
|
| 114 |
+
# task tracking
|
| 115 |
+
self._add_env_opt(env_opts, "use_relative_error", default=False) # use relative vel error (wrt current task norm)
|
| 116 |
+
self._add_env_opt(env_opts, "directional_tracking", default=True) # whether to compute tracking error based on reference direction
|
| 117 |
+
# if env_opts["add_angvel_ref_rand"]:
|
| 118 |
+
# env_opts["directional_tracking"]=False
|
| 119 |
+
|
| 120 |
+
self._add_env_opt(env_opts, "use_L1_norm", default=True) # whether to use L1 norm for the error (otherwise L2)
|
| 121 |
+
self._add_env_opt(env_opts, "use_exp_track_rew", default=True) # whether to use a reward of the form A*e^(B*x),
|
| 122 |
+
# otherwise A*(1-B*x)
|
| 123 |
+
|
| 124 |
+
self._add_env_opt(env_opts, "use_fail_idx_weight", default=False)
|
| 125 |
+
self._add_env_opt(env_opts, "task_track_offset_exp", default=1.0)
|
| 126 |
+
self._add_env_opt(env_opts, "task_track_scale_exp", default=5.0)
|
| 127 |
+
self._add_env_opt(env_opts, "task_track_offset", default=1.0)
|
| 128 |
+
self._add_env_opt(env_opts, "task_track_scale", default=1.5)
|
| 129 |
+
self._add_env_opt(env_opts, "task_track_front_weight", default=1.0)
|
| 130 |
+
self._add_env_opt(env_opts, "task_track_lat_weight", default=0.05)
|
| 131 |
+
self._add_env_opt(env_opts, "task_track_vert_weight", default=0.05)
|
| 132 |
+
self._add_env_opt(env_opts, "task_track_omega_z_weight", default=0.2)
|
| 133 |
+
self._add_env_opt(env_opts, "task_track_omega_x_weight", default=0.05)
|
| 134 |
+
self._add_env_opt(env_opts, "task_track_omega_y_weight", default=0.05)
|
| 135 |
+
# if env_opts["add_angvel_ref_rand"]:
|
| 136 |
+
# env_opts["task_track_omega_x_weight"]=0.0
|
| 137 |
+
# env_opts["task_track_omega_y_weight"]=0.0
|
| 138 |
+
# env_opts["task_track_omega_z_weight"]=1.0
|
| 139 |
+
|
| 140 |
+
# task pred tracking
|
| 141 |
+
self._add_env_opt(env_opts, "task_pred_track_offset", default=1.0)
|
| 142 |
+
self._add_env_opt(env_opts, "task_pred_track_scale", default=3.0)
|
| 143 |
+
|
| 144 |
+
# energy penalties
|
| 145 |
+
self._add_env_opt(env_opts, "CoT_offset", default=0.3)
|
| 146 |
+
self._add_env_opt(env_opts, "CoT_scale", default=0.3)
|
| 147 |
+
self._add_env_opt(env_opts, "power_offset", default=0.1)
|
| 148 |
+
self._add_env_opt(env_opts, "power_scale", default=8e-4)
|
| 149 |
+
|
| 150 |
+
# action rate penalty
|
| 151 |
+
self._add_env_opt(env_opts, "action_rate_offset", default=0.1)
|
| 152 |
+
self._add_env_opt(env_opts, "action_rate_scale", default=2.0)
|
| 153 |
+
self._add_env_opt(env_opts, "action_rate_rew_d_weight", default=0.1)
|
| 154 |
+
self._add_env_opt(env_opts, "action_rate_rew_c_weight", default=1.0)
|
| 155 |
+
|
| 156 |
+
# jnt vel penalty
|
| 157 |
+
self._add_env_opt(env_opts, "jnt_vel_offset", default=0.1)
|
| 158 |
+
self._add_env_opt(env_opts, "jnt_vel_scale", default=2.0)
|
| 159 |
+
|
| 160 |
+
# terminations
|
| 161 |
+
self._add_env_opt(env_opts, "add_term_mpc_capsize", default=False) # add termination based on mpc capsizing prediction
|
| 162 |
+
|
| 163 |
+
# observations
|
| 164 |
+
self._add_env_opt(env_opts, "rhc_fail_idx_scale", default=1.0)
|
| 165 |
+
self._add_env_opt(env_opts, "use_action_history", default=True) # whether to add information on past actions to obs
|
| 166 |
+
self._add_env_opt(env_opts, "add_prev_actions_stats_to_obs", default=False) # add actions std, mean + last action over a horizon to obs (if self._use_action_history True)
|
| 167 |
+
self._add_env_opt(env_opts, "actions_history_size", default=3)
|
| 168 |
+
|
| 169 |
+
self._add_env_opt(env_opts, "add_mpc_contact_f_to_obs", default=True) # add estimate vertical contact f to obs
|
| 170 |
+
self._add_env_opt(env_opts, "add_fail_idx_to_obs", default=True) # we need to obserse mpc failure idx to correlate it with terminations
|
| 171 |
+
|
| 172 |
+
self._add_env_opt(env_opts, "use_linvel_from_rhc", default=True) # no lin vel meas available, we use est. from mpc
|
| 173 |
+
self._add_env_opt(env_opts, "add_flight_info", default=True) # add feedback info on pos, remamining duration, length,
|
| 174 |
+
# apex and landing height of flight phases
|
| 175 |
+
self._add_env_opt(env_opts, "add_flight_settings", default=False) # add feedback info on current flight requests for mpc
|
| 176 |
+
|
| 177 |
+
self._add_env_opt(env_opts, "use_prob_based_stepping", default=False) # interpret actions as stepping prob (never worked)
|
| 178 |
+
|
| 179 |
+
self._add_env_opt(env_opts, "add_rhc_cmds_to_obs", default=True) # add the rhc cmds which are being applied now to the robot
|
| 180 |
+
|
| 181 |
+
if not "add_periodic_clock_to_obs" in env_opts:
|
| 182 |
+
# add a sin/cos clock to obs (useful if task is explicitly
|
| 183 |
+
# time-dependent)
|
| 184 |
+
self._add_env_opt(env_opts, "add_periodic_clock_to_obs", default=False)
|
| 185 |
+
|
| 186 |
+
self._add_env_opt(env_opts, "add_heightmap_obs", default=True)
|
| 187 |
+
|
| 188 |
+
# temporarily creating robot state client to get some data
|
| 189 |
+
robot_state_tmp = RobotState(namespace=namespace,
|
| 190 |
+
is_server=False,
|
| 191 |
+
safe=False,
|
| 192 |
+
verbose=verbose,
|
| 193 |
+
vlevel=vlevel,
|
| 194 |
+
with_gpu_mirror=False,
|
| 195 |
+
with_torch_view=False,
|
| 196 |
+
enable_height_sensor=env_opts["add_heightmap_obs"])
|
| 197 |
+
robot_state_tmp.run()
|
| 198 |
+
rhc_status_tmp = RhcStatus(is_server=False,
|
| 199 |
+
namespace=namespace,
|
| 200 |
+
verbose=verbose,
|
| 201 |
+
vlevel=vlevel,
|
| 202 |
+
with_torch_view=False,
|
| 203 |
+
with_gpu_mirror=False)
|
| 204 |
+
rhc_status_tmp.run()
|
| 205 |
+
rhc_refs_tmp = RhcRefs(namespace=namespace,
|
| 206 |
+
is_server=False,
|
| 207 |
+
safe=False,
|
| 208 |
+
verbose=verbose,
|
| 209 |
+
vlevel=vlevel,
|
| 210 |
+
with_gpu_mirror=False,
|
| 211 |
+
with_torch_view=False)
|
| 212 |
+
rhc_refs_tmp.run()
|
| 213 |
+
n_jnts = robot_state_tmp.n_jnts()
|
| 214 |
+
self._contact_names = robot_state_tmp.contact_names()
|
| 215 |
+
self._n_contacts = len(self._contact_names)
|
| 216 |
+
self._flight_info_size=rhc_refs_tmp.flight_info.n_cols
|
| 217 |
+
self._flight_setting_size=rhc_refs_tmp.flight_settings_req.n_cols
|
| 218 |
+
# height sensor metadata (if present)
|
| 219 |
+
self._height_grid_size = None
|
| 220 |
+
self._height_flat_dim = 0
|
| 221 |
+
if env_opts["add_heightmap_obs"]:
|
| 222 |
+
self._height_grid_size = robot_state_tmp.height_sensor.grid_size
|
| 223 |
+
self._height_flat_dim = robot_state_tmp.height_sensor.n_cols
|
| 224 |
+
|
| 225 |
+
robot_state_tmp.close()
|
| 226 |
+
rhc_status_tmp.close()
|
| 227 |
+
rhc_refs_tmp.close()
|
| 228 |
+
|
| 229 |
+
# defining obs dimension
|
| 230 |
+
obs_dim=3 # normalized gravity vector in base frame
|
| 231 |
+
obs_dim+=6 # meas twist in base frame
|
| 232 |
+
obs_dim+=2*n_jnts # joint pos + vel
|
| 233 |
+
if env_opts["add_mpc_contact_f_to_obs"]:
|
| 234 |
+
obs_dim+=3*self._n_contacts
|
| 235 |
+
obs_dim+=6 # twist reference in base frame frame
|
| 236 |
+
if env_opts["add_fail_idx_to_obs"]:
|
| 237 |
+
obs_dim+=1 # rhc controller failure index
|
| 238 |
+
if env_opts["add_term_mpc_capsize"]:
|
| 239 |
+
obs_dim+=3 # gravity vec from mpc
|
| 240 |
+
if env_opts["use_rhc_avrg_vel_tracking"]:
|
| 241 |
+
obs_dim+=6 # mpc avrg twist
|
| 242 |
+
if env_opts["add_flight_info"]: # contact pos, remaining duration, length, apex, landing height, landing dx, dy
|
| 243 |
+
obs_dim+=self._flight_info_size
|
| 244 |
+
if env_opts["add_flight_settings"]:
|
| 245 |
+
obs_dim+=self._flight_setting_size
|
| 246 |
+
if env_opts["add_rhc_cmds_to_obs"]:
|
| 247 |
+
obs_dim+=3*n_jnts
|
| 248 |
+
if env_opts["use_action_history"]:
|
| 249 |
+
if env_opts["add_prev_actions_stats_to_obs"]:
|
| 250 |
+
obs_dim+=3*actions_dim # previous agent actions statistics (mean, std + last action)
|
| 251 |
+
else: # full action history
|
| 252 |
+
obs_dim+=env_opts["actions_history_size"]*actions_dim
|
| 253 |
+
if env_opts["use_action_smoothing"]:
|
| 254 |
+
obs_dim+=actions_dim # it's better to also add the smoothed actions as obs
|
| 255 |
+
if env_opts["add_periodic_clock_to_obs"]:
|
| 256 |
+
obs_dim+=2
|
| 257 |
+
if env_opts["add_heightmap_obs"]:
|
| 258 |
+
obs_dim+=self._height_flat_dim
|
| 259 |
+
# Agent task reference
|
| 260 |
+
self._add_env_opt(env_opts, "use_pof0", default=True) # with some prob, references will be null
|
| 261 |
+
self._add_env_opt(env_opts, "pof0_linvel", default=0.3) # [0, 1] prob of both linvel and omega refs being null(from bernoulli distr)
|
| 262 |
+
self._add_env_opt(env_opts, "pof0_omega", default=0.3) # [0, 1] prob of both linvel and omega refs being null(from bernoulli distr)
|
| 263 |
+
self._add_env_opt(env_opts, "max_linvel_ref", default=0.3) # m/s
|
| 264 |
+
self._add_env_opt(env_opts, "max_angvel_ref", default=0.0) # rad/s
|
| 265 |
+
if env_opts["add_angvel_ref_rand"]:
|
| 266 |
+
env_opts["max_angvel_ref"]=0.4
|
| 267 |
+
|
| 268 |
+
# ready to init base class
|
| 269 |
+
self._this_child_path = os.path.abspath(__file__)
|
| 270 |
+
AugMPCTrainingEnvBase.__init__(self,
|
| 271 |
+
namespace=namespace,
|
| 272 |
+
obs_dim=obs_dim,
|
| 273 |
+
actions_dim=actions_dim,
|
| 274 |
+
env_name=env_name,
|
| 275 |
+
verbose=verbose,
|
| 276 |
+
vlevel=vlevel,
|
| 277 |
+
use_gpu=use_gpu,
|
| 278 |
+
dtype=dtype,
|
| 279 |
+
debug=debug,
|
| 280 |
+
override_agent_refs=override_agent_refs,
|
| 281 |
+
timeout_ms=timeout_ms,
|
| 282 |
+
env_opts=env_opts)
|
| 283 |
+
|
| 284 |
+
def _custom_post_init(self):
|
| 285 |
+
|
| 286 |
+
device = "cuda" if self._use_gpu else "cpu"
|
| 287 |
+
|
| 288 |
+
self._update_jnt_blacklist() # update blacklist for joints
|
| 289 |
+
|
| 290 |
+
# constant base-frame unit vectors (reuse to avoid per-call allocations)
|
| 291 |
+
self._base_x_dir = torch.zeros((self._n_envs, 3), dtype=self._dtype, device=device)
|
| 292 |
+
self._base_x_dir[:, 0] = 1.0
|
| 293 |
+
self._base_y_dir = torch.zeros((self._n_envs, 3), dtype=self._dtype, device=device)
|
| 294 |
+
self._base_y_dir[:, 1] = 1.0
|
| 295 |
+
|
| 296 |
+
self._twist_ref_lb = torch.full((1, 6), dtype=self._dtype, device=device,
|
| 297 |
+
fill_value=-1.5)
|
| 298 |
+
self._twist_ref_ub = torch.full((1, 6), dtype=self._dtype, device=device,
|
| 299 |
+
fill_value=1.5)
|
| 300 |
+
|
| 301 |
+
# task reference parameters (world frame)
|
| 302 |
+
# lin vel
|
| 303 |
+
self._twist_ref_lb[0, 0] = -self._env_opts["max_linvel_ref"]
|
| 304 |
+
self._twist_ref_lb[0, 1] = -self._env_opts["max_linvel_ref"]
|
| 305 |
+
self._twist_ref_lb[0, 2] = 0.0
|
| 306 |
+
self._twist_ref_ub[0, 0] = self._env_opts["max_linvel_ref"]
|
| 307 |
+
self._twist_ref_ub[0, 1] = self._env_opts["max_linvel_ref"]
|
| 308 |
+
self._twist_ref_ub[0, 2] = 0.0
|
| 309 |
+
# angular vel
|
| 310 |
+
self._twist_ref_lb[0, 3] = 0.0
|
| 311 |
+
self._twist_ref_lb[0, 4] = 0.0
|
| 312 |
+
self._twist_ref_lb[0, 5] = -self._env_opts["max_angvel_ref"]
|
| 313 |
+
self._twist_ref_ub[0, 3] = 0.0
|
| 314 |
+
self._twist_ref_ub[0, 4] = 0.0
|
| 315 |
+
self._twist_ref_ub[0, 5] = self._env_opts["max_angvel_ref"]
|
| 316 |
+
|
| 317 |
+
self._twist_ref_offset = (self._twist_ref_ub + self._twist_ref_lb)/2.0
|
| 318 |
+
self._twist_ref_scale = (self._twist_ref_ub - self._twist_ref_lb)/2.0
|
| 319 |
+
|
| 320 |
+
# adding some custom db info
|
| 321 |
+
agent_twist_ref = self._agent_refs.rob_refs.root_state.get(data_type="twist",gpu=False)
|
| 322 |
+
agent_twist_ref_data = EpisodicData("AgentTwistRefs", agent_twist_ref,
|
| 323 |
+
["v_x", "v_y", "v_z", "omega_x", "omega_y", "omega_z"],
|
| 324 |
+
ep_vec_freq=self._env_opts["vec_ep_freq_metrics_db"],
|
| 325 |
+
store_transitions=self._full_db,
|
| 326 |
+
max_ep_duration=self._max_ep_length())
|
| 327 |
+
rhc_fail_idx = EpisodicData("RhcFailIdx", self._rhc_fail_idx(gpu=False), ["rhc_fail_idx"],
|
| 328 |
+
ep_vec_freq=self._env_opts["vec_ep_freq_metrics_db"],
|
| 329 |
+
store_transitions=self._full_db,
|
| 330 |
+
max_ep_duration=self._max_ep_length())
|
| 331 |
+
|
| 332 |
+
f_names=[]
|
| 333 |
+
for contact in self._contact_names:
|
| 334 |
+
f_names.append(f"fc_{contact}_x_base_loc")
|
| 335 |
+
f_names.append(f"fc_{contact}_y_base_loc")
|
| 336 |
+
f_names.append(f"fc_{contact}_z_base_loc")
|
| 337 |
+
rhc_contact_f = EpisodicData("RhcContactForces",
|
| 338 |
+
self._rhc_cmds.contact_wrenches.get(data_type="f",gpu=False),
|
| 339 |
+
f_names,
|
| 340 |
+
ep_vec_freq=self._env_opts["vec_ep_freq_metrics_db"],
|
| 341 |
+
store_transitions=self._full_db,
|
| 342 |
+
max_ep_duration=self._max_ep_length())
|
| 343 |
+
|
| 344 |
+
self._pow_db_data=torch.full(size=(self._n_envs,2),
|
| 345 |
+
dtype=self._dtype, device="cpu",
|
| 346 |
+
fill_value=-1.0)
|
| 347 |
+
power_db = EpisodicData("Power",
|
| 348 |
+
self._pow_db_data,
|
| 349 |
+
["CoT", "W"],
|
| 350 |
+
ep_vec_freq=self._env_opts["vec_ep_freq_metrics_db"],
|
| 351 |
+
store_transitions=self._full_db,
|
| 352 |
+
max_ep_duration=self._max_ep_length())
|
| 353 |
+
|
| 354 |
+
self._track_error_db=torch.full_like(agent_twist_ref, fill_value=0.0)
|
| 355 |
+
task_err_db = EpisodicData("TrackingError",
|
| 356 |
+
agent_twist_ref,
|
| 357 |
+
["e_vx", "e_vy", "e_vz", "e_omegax", "e_omegay", "e_omegaz"],
|
| 358 |
+
ep_vec_freq=self._env_opts["vec_ep_freq_metrics_db"],
|
| 359 |
+
store_transitions=self._full_db,
|
| 360 |
+
max_ep_duration=self._max_ep_length())
|
| 361 |
+
|
| 362 |
+
self._add_custom_db_data(db_data=agent_twist_ref_data)
|
| 363 |
+
self._add_custom_db_data(db_data=rhc_fail_idx)
|
| 364 |
+
self._add_custom_db_data(db_data=rhc_contact_f)
|
| 365 |
+
self._add_custom_db_data(db_data=power_db)
|
| 366 |
+
self._add_custom_db_data(db_data=task_err_db)
|
| 367 |
+
|
| 368 |
+
# rewards
|
| 369 |
+
self._task_err_weights = torch.full((1, 6), dtype=self._dtype, device=device,
|
| 370 |
+
fill_value=0.0)
|
| 371 |
+
if self._env_opts["directional_tracking"]:
|
| 372 |
+
self._task_err_weights[0, 0] = self._env_opts["task_track_front_weight"] # frontal
|
| 373 |
+
self._task_err_weights[0, 1] = self._env_opts["task_track_lat_weight"] # lateral
|
| 374 |
+
self._task_err_weights[0, 2] = self._env_opts["task_track_vert_weight"] # vertical
|
| 375 |
+
self._task_err_weights[0, 3] = self._env_opts["task_track_omega_x_weight"]
|
| 376 |
+
self._task_err_weights[0, 4] = self._env_opts["task_track_omega_y_weight"]
|
| 377 |
+
self._task_err_weights[0, 5] = self._env_opts["task_track_omega_z_weight"]
|
| 378 |
+
else:
|
| 379 |
+
self._task_err_weights[0, 0] = self._env_opts["task_track_front_weight"]
|
| 380 |
+
self._task_err_weights[0, 1] = self._env_opts["task_track_front_weight"]
|
| 381 |
+
self._task_err_weights[0, 2] = 0.1*self._env_opts["task_track_front_weight"]
|
| 382 |
+
self._task_err_weights[0, 3] = self._env_opts["task_track_omega_x_weight"]
|
| 383 |
+
self._task_err_weights[0, 4] = self._env_opts["task_track_omega_y_weight"]
|
| 384 |
+
self._task_err_weights[0, 5] = self._env_opts["task_track_omega_z_weight"]
|
| 385 |
+
|
| 386 |
+
self._task_pred_err_weights = torch.full((1, 6), dtype=self._dtype, device=device,
|
| 387 |
+
fill_value=0.0)
|
| 388 |
+
if self._env_opts["directional_tracking"]:
|
| 389 |
+
self._task_pred_err_weights[0, 0] = self._env_opts["task_track_front_weight"]
|
| 390 |
+
self._task_pred_err_weights[0, 1] = self._env_opts["task_track_lat_weight"]
|
| 391 |
+
self._task_pred_err_weights[0, 2] = self._env_opts["task_track_vert_weight"]
|
| 392 |
+
self._task_pred_err_weights[0, 3] = self._env_opts["task_track_omega_x_weight"]
|
| 393 |
+
self._task_pred_err_weights[0, 4] = self._env_opts["task_track_omega_y_weight"]
|
| 394 |
+
self._task_pred_err_weights[0, 5] = self._env_opts["task_track_omega_z_weight"]
|
| 395 |
+
else:
|
| 396 |
+
self._task_pred_err_weights[0, 0] = self._env_opts["task_track_front_weight"]
|
| 397 |
+
self._task_pred_err_weights[0, 1] = self._env_opts["task_track_front_weight"]
|
| 398 |
+
self._task_pred_err_weights[0, 2] = 0.1*self._env_opts["task_track_front_weight"]
|
| 399 |
+
self._task_pred_err_weights[0, 3] = self._env_opts["task_track_omega_x_weight"]
|
| 400 |
+
self._task_pred_err_weights[0, 4] = self._env_opts["task_track_omega_y_weight"]
|
| 401 |
+
self._task_pred_err_weights[0, 5] = self._env_opts["task_track_omega_z_weight"]
|
| 402 |
+
|
| 403 |
+
self._power_penalty_weights = torch.full((1, self._n_jnts), dtype=self._dtype, device=device,
|
| 404 |
+
fill_value=1.0)
|
| 405 |
+
self._power_penalty_weights_sum = torch.sum(self._power_penalty_weights).item()
|
| 406 |
+
subr_names=self._get_rewards_names() # initializes
|
| 407 |
+
|
| 408 |
+
# reward clipping
|
| 409 |
+
self._reward_thresh_lb[:, :] = self._env_opts["reward_lb_default"]
|
| 410 |
+
self._reward_thresh_ub[:, :]= self._env_opts["reward_ub_default"]
|
| 411 |
+
|
| 412 |
+
for reward_name, env_opt_key in self._reward_lb_map.items():
|
| 413 |
+
if reward_name in self._reward_map:
|
| 414 |
+
self._reward_thresh_lb[:, self._reward_map[reward_name]] = self._env_opts[env_opt_key]
|
| 415 |
+
|
| 416 |
+
# obs bounds
|
| 417 |
+
self._obs_threshold_lb = -1e3 # used for clipping observations
|
| 418 |
+
self._obs_threshold_ub = 1e3
|
| 419 |
+
|
| 420 |
+
# actions
|
| 421 |
+
if not self._env_opts["use_prob_based_stepping"]:
|
| 422 |
+
self._is_continuous_actions[6:10]=False
|
| 423 |
+
|
| 424 |
+
v_cmd_max = self._env_opts["max_cmd_v"]
|
| 425 |
+
omega_cmd_max = self._env_opts["max_cmd_omega"]
|
| 426 |
+
self._actions_lb[:, 0:3] = -v_cmd_max
|
| 427 |
+
self._actions_ub[:, 0:3] = v_cmd_max
|
| 428 |
+
self._actions_lb[:, 3:6] = -omega_cmd_max # twist cmds
|
| 429 |
+
self._actions_ub[:, 3:6] = omega_cmd_max
|
| 430 |
+
if "contact_flag_start" in self._actions_map:
|
| 431 |
+
idx=self._actions_map["contact_flag_start"]
|
| 432 |
+
if self._env_opts["use_prob_based_stepping"]:
|
| 433 |
+
self._actions_lb[:, idx:idx+self._n_contacts] = 0.0 # contact flags
|
| 434 |
+
self._actions_ub[:, idx:idx+self._n_contacts] = 1.0
|
| 435 |
+
else:
|
| 436 |
+
self._actions_lb[:, idx:idx+self._n_contacts] = -1.0
|
| 437 |
+
self._actions_ub[:, idx:idx+self._n_contacts] = 1.0
|
| 438 |
+
|
| 439 |
+
self.default_action[:, :] = (self._actions_ub+self._actions_lb)/2.0
|
| 440 |
+
# self.default_action[:, ~self._is_continuous_actions] = 1.0
|
| 441 |
+
self.safe_action[:, :] = self.default_action
|
| 442 |
+
if "contact_flag_start" in self._actions_map: # safe actions for contacts is 1 (keep contact)
|
| 443 |
+
idx=self._actions_map["contact_flag_start"]
|
| 444 |
+
self.safe_action[:, idx:idx+self._n_contacts] = 1.0
|
| 445 |
+
|
| 446 |
+
# assign obs bounds (useful if not using automatic obs normalization)
|
| 447 |
+
obs_names=self._get_obs_names()
|
| 448 |
+
obs_patterns=["gn",
|
| 449 |
+
"linvel",
|
| 450 |
+
"omega",
|
| 451 |
+
"q_jnt",
|
| 452 |
+
"v_jnt",
|
| 453 |
+
"fc",
|
| 454 |
+
"rhc_fail",
|
| 455 |
+
"rhc_cmd_q",
|
| 456 |
+
"rhc_cmd_v",
|
| 457 |
+
"rhc_cmd_eff",
|
| 458 |
+
"flight_pos"
|
| 459 |
+
]
|
| 460 |
+
obs_ubs=[1.0,
|
| 461 |
+
5*v_cmd_max,
|
| 462 |
+
5*omega_cmd_max,
|
| 463 |
+
2*torch.pi,
|
| 464 |
+
30.0,
|
| 465 |
+
2.0,
|
| 466 |
+
1.0,
|
| 467 |
+
2*torch.pi,
|
| 468 |
+
30.0,
|
| 469 |
+
200.0,
|
| 470 |
+
self._n_nodes_rhc.mean().item()]
|
| 471 |
+
obs_lbs=[-1.0,
|
| 472 |
+
-5*v_cmd_max,
|
| 473 |
+
-5*omega_cmd_max,
|
| 474 |
+
-2*torch.pi,
|
| 475 |
+
-30.0,
|
| 476 |
+
-2.0,
|
| 477 |
+
0.0,
|
| 478 |
+
-2*torch.pi,
|
| 479 |
+
-30.0,
|
| 480 |
+
-200.0,
|
| 481 |
+
0.0]
|
| 482 |
+
obs_bounds = {name: (lb, ub) for name, lb, ub in zip(obs_patterns, obs_lbs, obs_ubs)}
|
| 483 |
+
|
| 484 |
+
for i in range(len(obs_names)):
|
| 485 |
+
obs_name=obs_names[i]
|
| 486 |
+
for pattern in obs_patterns:
|
| 487 |
+
if pattern in obs_name:
|
| 488 |
+
lb=obs_bounds[pattern][0]
|
| 489 |
+
ub=obs_bounds[pattern][1]
|
| 490 |
+
self._obs_lb[:, i]=lb
|
| 491 |
+
self._obs_ub[:, i]=ub
|
| 492 |
+
break
|
| 493 |
+
|
| 494 |
+
# handle action memory buffer in obs
|
| 495 |
+
if self._env_opts["use_action_history"]: # just history stats
|
| 496 |
+
if self._env_opts["add_prev_actions_stats_to_obs"]:
|
| 497 |
+
i=0
|
| 498 |
+
prev_actions_idx = next((i for i, s in enumerate(obs_names) if "_prev_act" in s), None)
|
| 499 |
+
prev_actions_mean_idx=next((i for i, s in enumerate(obs_names) if "_avrg_act" in s), None)
|
| 500 |
+
prev_actions_std_idx=next((i for i, s in enumerate(obs_names) if "_std_act" in s), None)
|
| 501 |
+
|
| 502 |
+
# assume actions are always normalized in [-1, 1] by agent
|
| 503 |
+
if prev_actions_idx is not None:
|
| 504 |
+
self._obs_lb[:, prev_actions_idx:prev_actions_idx+self.actions_dim()]=-1.0
|
| 505 |
+
self._obs_ub[:, prev_actions_idx:prev_actions_idx+self.actions_dim()]=1.0
|
| 506 |
+
if prev_actions_mean_idx is not None:
|
| 507 |
+
self._obs_lb[:, prev_actions_mean_idx:prev_actions_mean_idx+self.actions_dim()]=-1.0
|
| 508 |
+
self._obs_ub[:, prev_actions_mean_idx:prev_actions_mean_idx+self.actions_dim()]=1.0
|
| 509 |
+
if prev_actions_std_idx is not None:
|
| 510 |
+
self._obs_lb[:, prev_actions_std_idx:prev_actions_std_idx+self.actions_dim()]=0
|
| 511 |
+
self._obs_ub[:, prev_actions_std_idx:prev_actions_std_idx+self.actions_dim()]=1.0
|
| 512 |
+
|
| 513 |
+
else: # full history
|
| 514 |
+
i=0
|
| 515 |
+
first_action_mem_buffer_idx = next((i for i, s in enumerate(obs_names) if "_m1_act" in s), None)
|
| 516 |
+
if first_action_mem_buffer_idx is not None:
|
| 517 |
+
action_idx_start_idx_counter=first_action_mem_buffer_idx
|
| 518 |
+
for j in range(self._env_opts["actions_history_size"]):
|
| 519 |
+
self._obs_lb[:, action_idx_start_idx_counter:action_idx_start_idx_counter+self.actions_dim()]=-1.0
|
| 520 |
+
self._obs_ub[:, action_idx_start_idx_counter:action_idx_start_idx_counter+self.actions_dim()]=1.0
|
| 521 |
+
action_idx_start_idx_counter+=self.actions_dim()
|
| 522 |
+
|
| 523 |
+
# some aux data to avoid allocations at training runtime
|
| 524 |
+
self._rhc_twist_cmd_rhc_world=self._robot_state.root_state.get(data_type="twist",gpu=self._use_gpu).detach().clone()
|
| 525 |
+
self._rhc_twist_cmd_rhc_h=self._rhc_twist_cmd_rhc_world.detach().clone()
|
| 526 |
+
self._agent_twist_ref_current_w=self._rhc_twist_cmd_rhc_world.detach().clone()
|
| 527 |
+
self._agent_twist_ref_current_base_loc=self._rhc_twist_cmd_rhc_world.detach().clone()
|
| 528 |
+
self._substep_avrg_root_twist_base_loc=self._rhc_twist_cmd_rhc_world.detach().clone()
|
| 529 |
+
self._step_avrg_root_twist_base_loc=self._rhc_twist_cmd_rhc_world.detach().clone()
|
| 530 |
+
self._root_twist_avrg_rhc_base_loc=self._rhc_twist_cmd_rhc_world.detach().clone()
|
| 531 |
+
self._root_twist_avrg_rhc_base_loc_next=self._rhc_twist_cmd_rhc_world.detach().clone()
|
| 532 |
+
|
| 533 |
+
self._random_thresh_contacts=torch.rand((self._n_envs,self._n_contacts), device=device)
|
| 534 |
+
# aux data
|
| 535 |
+
self._task_err_scaling = torch.zeros((self._n_envs, 1),dtype=self._dtype,device=device)
|
| 536 |
+
|
| 537 |
+
self._pof1_b_linvel= torch.full(size=(self._n_envs,1),dtype=self._dtype,device=device,fill_value=1-self._env_opts["pof0_linvel"])
|
| 538 |
+
self._pof1_b_omega = torch.full(size=(self._n_envs,1),dtype=self._dtype,device=device,fill_value=1-self._env_opts["pof0_omega"])
|
| 539 |
+
self._bernoulli_coeffs_linvel = self._pof1_b_linvel.clone()
|
| 540 |
+
self._bernoulli_coeffs_linvel[:, :] = 1.0
|
| 541 |
+
self._bernoulli_coeffs_omega = self._pof1_b_omega.clone()
|
| 542 |
+
self._bernoulli_coeffs_omega[:, :] = 1.0
|
| 543 |
+
|
| 544 |
+
# smoothing
|
| 545 |
+
self._track_rew_smoother=None
|
| 546 |
+
if self._env_opts["use_track_reward_smoother"]:
|
| 547 |
+
sub_reward_proxy=self._sub_rewards.get_torch_mirror(gpu=self._use_gpu)[:, 0:1]
|
| 548 |
+
smoothing_dt=self._substep_dt
|
| 549 |
+
if not self._is_substep_rew[self._reward_map["task_error"]]: # assuming first reward is tracking
|
| 550 |
+
smoothing_dt=self._substep_dt*self._action_repeat
|
| 551 |
+
self._track_rew_smoother=ExponentialSignalSmoother(
|
| 552 |
+
name=self.__class__.__name__+"VelErrorSmoother",
|
| 553 |
+
signal=sub_reward_proxy, # same dimension of vel error
|
| 554 |
+
update_dt=smoothing_dt,
|
| 555 |
+
smoothing_horizon=self._env_opts["smoothing_horizon_vel_err"],
|
| 556 |
+
target_smoothing=0.5,
|
| 557 |
+
debug=self._is_debug,
|
| 558 |
+
dtype=self._dtype,
|
| 559 |
+
use_gpu=self._use_gpu)
|
| 560 |
+
|
| 561 |
+
# if we need the action rate, we also need the action history
|
| 562 |
+
if self._env_opts["add_action_rate_reward"]:
|
| 563 |
+
if not self._env_opts["use_action_history"]:
|
| 564 |
+
Journal.log(self.__class__.__name__,
|
| 565 |
+
"_custom_post_init",
|
| 566 |
+
"add_action_rate_reward is True, but ",
|
| 567 |
+
LogType.EXCEP,
|
| 568 |
+
throw_when_excep=True)
|
| 569 |
+
|
| 570 |
+
history_size=self._env_opts["actions_history_size"]
|
| 571 |
+
if history_size < 2:
|
| 572 |
+
Journal.log(self.__class__.__name__,
|
| 573 |
+
"_custom_post_init",
|
| 574 |
+
f"add_action_rate_reward requires actions history ({history_size}) to be >=2!",
|
| 575 |
+
LogType.EXCEP,
|
| 576 |
+
throw_when_excep=True)
|
| 577 |
+
|
| 578 |
+
# add periodic timer if required
|
| 579 |
+
self._periodic_clock=None
|
| 580 |
+
if self._env_opts["add_periodic_clock_to_obs"]:
|
| 581 |
+
self._add_env_opt(self._env_opts, "clock_period",
|
| 582 |
+
default=int(1.5*self._action_repeat*self.task_rand_timeout_bounds()[1])) # correcting with n substeps
|
| 583 |
+
# (we are using the _substep_abs_counter counter)
|
| 584 |
+
self._periodic_clock=PeriodicTimer(counter=self._substep_abs_counter,
|
| 585 |
+
period=self._env_opts["clock_period"],
|
| 586 |
+
dtype=self._dtype,
|
| 587 |
+
device=self._device)
|
| 588 |
+
|
| 589 |
+
def get_file_paths(self):
|
| 590 |
+
paths=AugMPCTrainingEnvBase.get_file_paths(self)
|
| 591 |
+
paths.append(self._this_child_path)
|
| 592 |
+
return paths
|
| 593 |
+
|
| 594 |
+
def get_aux_dir(self):
|
| 595 |
+
aux_dirs = []
|
| 596 |
+
path_getter = PathsGetter()
|
| 597 |
+
aux_dirs.append(path_getter.RHCDIR)
|
| 598 |
+
return aux_dirs
|
| 599 |
+
|
| 600 |
+
def _get_reward_scaling(self):
|
| 601 |
+
if self._env_opts["single_task_ref_per_episode"]:
|
| 602 |
+
return self._env_opts["n_steps_task_rand_ub"]
|
| 603 |
+
else:
|
| 604 |
+
return self._env_opts["episode_timeout_ub"]
|
| 605 |
+
|
| 606 |
+
def _max_ep_length(self):
|
| 607 |
+
if self._env_opts["single_task_ref_per_episode"]:
|
| 608 |
+
return self._env_opts["n_steps_task_rand_ub"]
|
| 609 |
+
else:
|
| 610 |
+
return self._env_opts["episode_timeout_ub"]
|
| 611 |
+
|
| 612 |
+
def _check_sub_truncations(self):
|
| 613 |
+
# overrides parent
|
| 614 |
+
sub_truncations = self._sub_truncations.get_torch_mirror(gpu=self._use_gpu)
|
| 615 |
+
sub_truncations[:, 0:1] = self._ep_timeout_counter.time_limits_reached()
|
| 616 |
+
if self._env_opts["single_task_ref_per_episode"]:
|
| 617 |
+
sub_truncations[:, 1:2] = self._task_rand_counter.time_limits_reached()
|
| 618 |
+
|
| 619 |
+
def _check_sub_terminations(self):
|
| 620 |
+
# default behaviour-> to be overriden by child
|
| 621 |
+
sub_terminations = self._sub_terminations.get_torch_mirror(gpu=self._use_gpu)
|
| 622 |
+
|
| 623 |
+
# terminate if mpc just failed
|
| 624 |
+
sub_terminations[:, 0:1] = self._rhc_status.fails.get_torch_mirror(gpu=self._use_gpu)
|
| 625 |
+
|
| 626 |
+
# check if robot is capsizing
|
| 627 |
+
robot_q_meas = self._robot_state.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 628 |
+
check_capsize(quat=robot_q_meas,max_angle=self._max_pitch_angle,
|
| 629 |
+
output_t=self._is_capsized)
|
| 630 |
+
sub_terminations[:, 1:2] = self._is_capsized
|
| 631 |
+
|
| 632 |
+
if self._env_opts["add_term_mpc_capsize"]:
|
| 633 |
+
# check if robot is about to capsize accordin to MPC
|
| 634 |
+
robot_q_pred = self._rhc_cmds.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 635 |
+
check_capsize(quat=robot_q_pred,max_angle=self._max_pitch_angle,
|
| 636 |
+
output_t=self._is_rhc_capsized)
|
| 637 |
+
sub_terminations[:, 2:3] = self._is_rhc_capsized
|
| 638 |
+
|
| 639 |
+
def _custom_reset(self):
|
| 640 |
+
return None
|
| 641 |
+
|
| 642 |
+
def reset(self):
|
| 643 |
+
AugMPCTrainingEnvBase.reset(self)
|
| 644 |
+
|
| 645 |
+
def _pre_substep(self):
|
| 646 |
+
pass
|
| 647 |
+
|
| 648 |
+
def _custom_post_step(self,episode_finished):
|
| 649 |
+
# executed after checking truncations and terminations and remote env reset
|
| 650 |
+
if self._use_gpu:
|
| 651 |
+
time_to_rand_or_ep_finished = torch.logical_or(self._task_rand_counter.time_limits_reached().cuda(),episode_finished)
|
| 652 |
+
self.randomize_task_refs(env_indxs=time_to_rand_or_ep_finished.flatten())
|
| 653 |
+
else:
|
| 654 |
+
time_to_rand_or_ep_finished = torch.logical_or(self._task_rand_counter.time_limits_reached(),episode_finished)
|
| 655 |
+
self.randomize_task_refs(env_indxs=time_to_rand_or_ep_finished.flatten())
|
| 656 |
+
# task refs are randomized in world frame -> we rotate them in base local
|
| 657 |
+
# (not super efficient, we should do it just for the finished envs)
|
| 658 |
+
self._update_loc_twist_refs()
|
| 659 |
+
|
| 660 |
+
if self._track_rew_smoother is not None: # reset smoother
|
| 661 |
+
self._track_rew_smoother.reset_all(to_be_reset=episode_finished.flatten(),
|
| 662 |
+
value=0.0)
|
| 663 |
+
|
| 664 |
+
def _custom_post_substp_pre_rew(self):
|
| 665 |
+
self._update_loc_twist_refs()
|
| 666 |
+
|
| 667 |
+
def _custom_post_substp_post_rew(self):
|
| 668 |
+
pass
|
| 669 |
+
|
| 670 |
+
def _update_loc_twist_refs(self):
|
| 671 |
+
# get fresh robot orientation
|
| 672 |
+
if not self._override_agent_refs:
|
| 673 |
+
robot_q = self._robot_state.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 674 |
+
# rotate agent ref from world to robot base
|
| 675 |
+
world2base_frame(t_w=self._agent_twist_ref_current_w, q_b=robot_q,
|
| 676 |
+
t_out=self._agent_twist_ref_current_base_loc)
|
| 677 |
+
# write it to agent refs tensors
|
| 678 |
+
self._agent_refs.rob_refs.root_state.set(data_type="twist", data=self._agent_twist_ref_current_base_loc,
|
| 679 |
+
gpu=self._use_gpu)
|
| 680 |
+
|
| 681 |
+
def _apply_actions_to_rhc(self):
|
| 682 |
+
|
| 683 |
+
self._set_rhc_refs()
|
| 684 |
+
|
| 685 |
+
self._write_rhc_refs()
|
| 686 |
+
|
| 687 |
+
def _set_rhc_refs(self):
|
| 688 |
+
|
| 689 |
+
action_to_be_applied = self.get_actual_actions() # see _get_action_names() to get
|
| 690 |
+
# the meaning of each component of this tensor
|
| 691 |
+
|
| 692 |
+
rhc_latest_twist_cmd = self._rhc_refs.rob_refs.root_state.get(data_type="twist", gpu=self._use_gpu)
|
| 693 |
+
rhc_latest_contact_ref = self._rhc_refs.contact_flags.get_torch_mirror(gpu=self._use_gpu)
|
| 694 |
+
rhc_latest_pos_ref = self._rhc_refs.rob_refs.contact_pos.get(data_type="p_z", gpu=self._use_gpu)
|
| 695 |
+
rhc_q=self._rhc_cmds.root_state.get(data_type="q",gpu=self._use_gpu) # this is always
|
| 696 |
+
# avaialble
|
| 697 |
+
|
| 698 |
+
# reference twist for MPC is assumed to always be specified in MPC's
|
| 699 |
+
# horizontal frame, while agent actions are interpreted as in MPC's
|
| 700 |
+
# base frame -> we need to rotate the actions into the horizontal frame
|
| 701 |
+
base2world_frame(t_b=action_to_be_applied[:, 0:6],q_b=rhc_q,t_out=self._rhc_twist_cmd_rhc_world)
|
| 702 |
+
w2hor_frame(t_w=self._rhc_twist_cmd_rhc_world,q_b=rhc_q,t_out=self._rhc_twist_cmd_rhc_h)
|
| 703 |
+
|
| 704 |
+
rhc_latest_twist_cmd[:, 0:6] = self._rhc_twist_cmd_rhc_h
|
| 705 |
+
|
| 706 |
+
# self._rhc_refs.rob_refs.root_state.set(data_type="p", data=rhc_latest_p_ref,
|
| 707 |
+
# gpu=self._use_gpu)
|
| 708 |
+
self._rhc_refs.rob_refs.root_state.set(data_type="twist", data=rhc_latest_twist_cmd,
|
| 709 |
+
gpu=self._use_gpu)
|
| 710 |
+
|
| 711 |
+
# contact flags
|
| 712 |
+
idx=self._actions_map["contact_flag_start"]
|
| 713 |
+
if self._env_opts["use_prob_based_stepping"]:
|
| 714 |
+
# encode actions as probs
|
| 715 |
+
self._random_thresh_contacts.uniform_() # random values in-place between 0 and 1
|
| 716 |
+
rhc_latest_contact_ref[:, :] = action_to_be_applied[:, idx:idx+self._n_contacts] >= self._random_thresh_contacts # keep contact with
|
| 717 |
+
# probability action_to_be_applied[:, 6:10]
|
| 718 |
+
else: # just use a threshold
|
| 719 |
+
rhc_latest_contact_ref[:, :] = action_to_be_applied[:, idx:idx+self._n_contacts] > self._env_opts["step_thresh"]
|
| 720 |
+
# actually apply actions to controller
|
| 721 |
+
|
| 722 |
+
def _write_rhc_refs(self):
|
| 723 |
+
|
| 724 |
+
if self._use_gpu:
|
| 725 |
+
# GPU->CPU --> we cannot use asynchronous data transfer since it's unsafe
|
| 726 |
+
self._rhc_refs.rob_refs.root_state.synch_mirror(from_gpu=True,non_blocking=False) # write from gpu to cpu mirror
|
| 727 |
+
self._rhc_refs.contact_flags.synch_mirror(from_gpu=True,non_blocking=False)
|
| 728 |
+
self._rhc_refs.rob_refs.contact_pos.synch_mirror(from_gpu=True,non_blocking=False)
|
| 729 |
+
|
| 730 |
+
self._rhc_refs.rob_refs.root_state.synch_all(read=False, retry=True) # write mirror to shared mem
|
| 731 |
+
self._rhc_refs.contact_flags.synch_all(read=False, retry=True)
|
| 732 |
+
self._rhc_refs.rob_refs.contact_pos.synch_all(read=False, retry=True)
|
| 733 |
+
|
| 734 |
+
def _override_refs(self,
|
| 735 |
+
env_indxs: torch.Tensor = None):
|
| 736 |
+
|
| 737 |
+
# runs at every post_step
|
| 738 |
+
self._agent_refs.rob_refs.root_state.synch_all(read=True,retry=True) # first read from mem
|
| 739 |
+
if self._use_gpu:
|
| 740 |
+
# copies latest refs to GPU
|
| 741 |
+
self._agent_refs.rob_refs.root_state.synch_mirror(from_gpu=False,non_blocking=False)
|
| 742 |
+
|
| 743 |
+
agent_linvel_ref_current=self._agent_refs.rob_refs.root_state.get(data_type="v",
|
| 744 |
+
gpu=self._use_gpu)
|
| 745 |
+
|
| 746 |
+
agent_yaw_omega_ref_current=self._agent_refs.rob_refs.root_state.get(data_type="omega",
|
| 747 |
+
gpu=self._use_gpu)
|
| 748 |
+
|
| 749 |
+
# self._p_trgt_w[:, :]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[:, 0:2] + \
|
| 750 |
+
# agent_p_ref_current[:, 0:2]
|
| 751 |
+
self._agent_twist_ref_current_w[:, 0:3]=agent_linvel_ref_current # set linvel target
|
| 752 |
+
|
| 753 |
+
self._agent_twist_ref_current_w[:, 5:6]=agent_yaw_omega_ref_current[:, 2:3] # set yaw ang. vel target from shared mem
|
| 754 |
+
|
| 755 |
+
def _fill_substep_obs(self,
|
| 756 |
+
obs: torch.Tensor):
|
| 757 |
+
|
| 758 |
+
# measured stuff
|
| 759 |
+
robot_twist_meas_base_loc = self._robot_state.root_state.get(data_type="twist",gpu=self._use_gpu)
|
| 760 |
+
robot_jnt_v_meas = self._robot_state.jnts_state.get(data_type="v",gpu=self._use_gpu)
|
| 761 |
+
|
| 762 |
+
if self._env_opts["use_linvel_from_rhc"]:
|
| 763 |
+
# twist estimate from mpc
|
| 764 |
+
robot_twist_rhc_base_loc_next = self._rhc_cmds.root_state.get(data_type="twist",gpu=self._use_gpu)
|
| 765 |
+
obs[:, self._obs_map["linvel_meas"]:(self._obs_map["linvel_meas"]+3)] = robot_twist_rhc_base_loc_next[:, 0:3]
|
| 766 |
+
else:
|
| 767 |
+
obs[:, self._obs_map["linvel_meas"]:(self._obs_map["linvel_meas"]+3)] = robot_twist_meas_base_loc[:, 0:3]
|
| 768 |
+
obs[:, self._obs_map["omega_meas"]:(self._obs_map["omega_meas"]+3)] = robot_twist_meas_base_loc[:, 3:6]
|
| 769 |
+
|
| 770 |
+
obs[:, self._obs_map["v_jnt"]:(self._obs_map["v_jnt"]+self._n_jnts)] = robot_jnt_v_meas
|
| 771 |
+
|
| 772 |
+
def _fill_step_obs(self,
|
| 773 |
+
obs: torch.Tensor):
|
| 774 |
+
|
| 775 |
+
# measured stuff
|
| 776 |
+
robot_gravity_norm_base_loc = self._robot_state.root_state.get(data_type="gn",gpu=self._use_gpu)
|
| 777 |
+
robot_twist_meas_base_loc = self._robot_state.root_state.get(data_type="twist",gpu=self._use_gpu)
|
| 778 |
+
robot_jnt_q_meas = self._robot_state.jnts_state.get(data_type="q",gpu=self._use_gpu)
|
| 779 |
+
if self._jnt_q_blacklist_idxs is not None: # we don't want to read joint pos from blacklist
|
| 780 |
+
robot_jnt_q_meas[:, self._jnt_q_blacklist_idxs]=0.0
|
| 781 |
+
robot_jnt_v_meas = self._robot_state.jnts_state.get(data_type="v",gpu=self._use_gpu)
|
| 782 |
+
|
| 783 |
+
# twist estimate from mpc
|
| 784 |
+
robot_twist_rhc_base_loc_next = self._rhc_cmds.root_state.get(data_type="twist",gpu=self._use_gpu)
|
| 785 |
+
# cmds for jnt imp to be applied next
|
| 786 |
+
robot_jnt_q_rhc_applied_next=self._rhc_cmds.jnts_state.get(data_type="q",gpu=self._use_gpu)
|
| 787 |
+
robot_jnt_v_rhc_applied_next=self._rhc_cmds.jnts_state.get(data_type="v",gpu=self._use_gpu)
|
| 788 |
+
robot_jnt_eff_rhc_applied_next=self._rhc_cmds.jnts_state.get(data_type="eff",gpu=self._use_gpu)
|
| 789 |
+
|
| 790 |
+
flight_info_now = self._rhc_refs.flight_info.get(data_type="all",gpu=self._use_gpu)
|
| 791 |
+
flight_settings_now = self._rhc_refs.flight_settings_req.get(data_type="all",gpu=self._use_gpu)
|
| 792 |
+
|
| 793 |
+
# refs
|
| 794 |
+
agent_twist_ref = self._agent_refs.rob_refs.root_state.get(data_type="twist",gpu=self._use_gpu)
|
| 795 |
+
|
| 796 |
+
obs[:, self._obs_map["gn_base"]:(self._obs_map["gn_base"]+3)] = robot_gravity_norm_base_loc # norm. gravity vector in base frame
|
| 797 |
+
|
| 798 |
+
obs[:, self._obs_map["q_jnt"]:(self._obs_map["q_jnt"]+self._n_jnts)] = robot_jnt_q_meas # meas jnt pos
|
| 799 |
+
obs[:, self._obs_map["twist_ref"]:(self._obs_map["twist_ref"]+6)] = agent_twist_ref # high lev agent refs to be tracked
|
| 800 |
+
|
| 801 |
+
if self._env_opts["add_mpc_contact_f_to_obs"]:
|
| 802 |
+
n_forces=3*len(self._contact_names)
|
| 803 |
+
obs[:, self._obs_map["contact_f_mpc"]:(self._obs_map["contact_f_mpc"]+n_forces)] = self._rhc_cmds.contact_wrenches.get(data_type="f",gpu=self._use_gpu)
|
| 804 |
+
if self._env_opts["add_fail_idx_to_obs"]:
|
| 805 |
+
obs[:, self._obs_map["rhc_fail_idx"]:(self._obs_map["rhc_fail_idx"]+1)] = self._rhc_fail_idx(gpu=self._use_gpu)
|
| 806 |
+
if self._env_opts["add_term_mpc_capsize"]:
|
| 807 |
+
obs[:, self._obs_map["gn_base_mpc"]:(self._obs_map["gn_base_mpc"]+3)] = self._rhc_cmds.root_state.get(data_type="gn",gpu=self._use_gpu)
|
| 808 |
+
if self._env_opts["use_rhc_avrg_vel_tracking"]:
|
| 809 |
+
self._get_avrg_rhc_root_twist(out=self._root_twist_avrg_rhc_base_loc, base_loc=True)
|
| 810 |
+
obs[:, self._obs_map["avrg_twist_mpc"]:(self._obs_map["avrg_twist_mpc"]+6)] = self._root_twist_avrg_rhc_base_loc
|
| 811 |
+
if self._env_opts["add_flight_info"]:
|
| 812 |
+
obs[:, self._obs_map["flight_info"]:(self._obs_map["flight_info"]+self._flight_info_size)] = flight_info_now
|
| 813 |
+
if self._env_opts["add_flight_settings"]:
|
| 814 |
+
obs[:, self._obs_map["flight_settings_req"]:(self._obs_map["flight_settings_req"]+self._flight_setting_size)] = \
|
| 815 |
+
flight_settings_now
|
| 816 |
+
|
| 817 |
+
if self._env_opts["add_rhc_cmds_to_obs"]:
|
| 818 |
+
obs[:, self._obs_map["rhc_cmds_q"]:(self._obs_map["rhc_cmds_q"]+self._n_jnts)] = robot_jnt_q_rhc_applied_next
|
| 819 |
+
obs[:, self._obs_map["rhc_cmds_v"]:(self._obs_map["rhc_cmds_v"]+self._n_jnts)] = robot_jnt_v_rhc_applied_next
|
| 820 |
+
obs[:, self._obs_map["rhc_cmds_eff"]:(self._obs_map["rhc_cmds_eff"]+self._n_jnts)] = robot_jnt_eff_rhc_applied_next
|
| 821 |
+
if self._env_opts["use_action_history"]:
|
| 822 |
+
if self._env_opts["add_prev_actions_stats_to_obs"]: # just add last, std and mean to obs
|
| 823 |
+
obs[:, self._obs_map["action_history_prev"]:(self._obs_map["action_history_prev"]+self.actions_dim())]=self._act_mem_buffer.get(idx=0)
|
| 824 |
+
obs[:, self._obs_map["action_history_avrg"]:(self._obs_map["action_history_avrg"]+self.actions_dim())]=self._act_mem_buffer.mean(clone=False)
|
| 825 |
+
obs[:, self._obs_map["action_history_std"]:(self._obs_map["action_history_std"]+self.actions_dim())]=self._act_mem_buffer.std(clone=False)
|
| 826 |
+
else: # add whole memory buffer to obs
|
| 827 |
+
next_idx=self._obs_map["action_history"]
|
| 828 |
+
for i in range(self._env_opts["actions_history_size"]):
|
| 829 |
+
obs[:, next_idx:(next_idx+self.actions_dim())]=self._act_mem_buffer.get(idx=i) # get all (n_envs x (obs_dim x horizon))
|
| 830 |
+
next_idx+=self.actions_dim()
|
| 831 |
+
|
| 832 |
+
if self._env_opts["use_action_smoothing"]: # adding smoothed actions
|
| 833 |
+
obs[:, self._obs_map["action_smoothing"]:(self._obs_map["action_smoothing"]+self.actions_dim())]=self.get_actual_actions(normalized=True)
|
| 834 |
+
next_idx+=self.actions_dim()
|
| 835 |
+
|
| 836 |
+
if self._env_opts["add_periodic_clock_to_obs"]:
|
| 837 |
+
obs[:, next_idx:(next_idx+2)]=self._periodic_clock.get()
|
| 838 |
+
next_idx+=2
|
| 839 |
+
if self._env_opts["add_heightmap_obs"]:
|
| 840 |
+
hm = self._robot_state.height_sensor.get(gpu=self._use_gpu)
|
| 841 |
+
obs[:, self._obs_map["heightmap"]:(self._obs_map["heightmap"]+self._height_flat_dim)] = hm
|
| 842 |
+
|
| 843 |
+
def _get_custom_db_data(self,
|
| 844 |
+
episode_finished,
|
| 845 |
+
ignore_ep_end):
|
| 846 |
+
episode_finished = episode_finished.cpu()
|
| 847 |
+
self.custom_db_data["AgentTwistRefs"].update(
|
| 848 |
+
new_data=self._agent_refs.rob_refs.root_state.get(data_type="twist", gpu=False),
|
| 849 |
+
ep_finished=episode_finished,
|
| 850 |
+
ignore_ep_end=ignore_ep_end)
|
| 851 |
+
self.custom_db_data["RhcFailIdx"].update(new_data=self._rhc_fail_idx(gpu=False),
|
| 852 |
+
ep_finished=episode_finished,
|
| 853 |
+
ignore_ep_end=ignore_ep_end)
|
| 854 |
+
self.custom_db_data["RhcContactForces"].update(
|
| 855 |
+
new_data=self._rhc_cmds.contact_wrenches.get(data_type="f",gpu=False),
|
| 856 |
+
ep_finished=episode_finished,
|
| 857 |
+
ignore_ep_end=ignore_ep_end)
|
| 858 |
+
self.custom_db_data["Power"].update(
|
| 859 |
+
new_data=self._pow_db_data,
|
| 860 |
+
ep_finished=episode_finished,
|
| 861 |
+
ignore_ep_end=ignore_ep_end)
|
| 862 |
+
self.custom_db_data["TrackingError"].update(
|
| 863 |
+
new_data=self._track_error_db,
|
| 864 |
+
ep_finished=episode_finished,
|
| 865 |
+
ignore_ep_end=ignore_ep_end)
|
| 866 |
+
|
| 867 |
+
# reward functions
|
| 868 |
+
def _action_rate(self):
|
| 869 |
+
continuous_actions=self._is_continuous_actions
|
| 870 |
+
discrete_actions=~self._is_continuous_actions
|
| 871 |
+
n_c_actions=continuous_actions.sum().item()
|
| 872 |
+
n_d_actions=discrete_actions.sum().item()
|
| 873 |
+
actions_prev=self._act_mem_buffer.get(idx=1)
|
| 874 |
+
actions_now=self._act_mem_buffer.get(idx=0)
|
| 875 |
+
actions_rate=(actions_now-actions_prev) # actions already normalized
|
| 876 |
+
actions_rate_c=actions_rate[:, continuous_actions]
|
| 877 |
+
actions_rate_d=actions_rate[:, discrete_actions]
|
| 878 |
+
|
| 879 |
+
actions_rate_sqrd=None # assuming n_c_actions > 0 always
|
| 880 |
+
actions_rate_sqrd=self._env_opts["action_rate_rew_c_weight"]*torch.sum(actions_rate_c*actions_rate_c, dim=1, keepdim=True)/n_c_actions
|
| 881 |
+
if discrete_actions.any():
|
| 882 |
+
actions_rate_sqrd+=self._env_opts["action_rate_rew_d_weight"]*torch.sum(actions_rate_d*actions_rate_d, dim=1, keepdim=True)/n_d_actions
|
| 883 |
+
return actions_rate_sqrd
|
| 884 |
+
|
| 885 |
+
def _mech_pow(self, jnts_vel, jnts_effort, autoscaled: bool = False, drained: bool = True):
|
| 886 |
+
mech_pow_jnts=(jnts_effort*jnts_vel)*self._power_penalty_weights
|
| 887 |
+
if drained:
|
| 888 |
+
mech_pow_jnts.clamp_(0.0,torch.inf) # do not account for regenerative power
|
| 889 |
+
mech_pow_tot = torch.sum(mech_pow_jnts, dim=1, keepdim=True)
|
| 890 |
+
self._pow_db_data[:, 1:2]=mech_pow_tot.cpu()
|
| 891 |
+
if autoscaled:
|
| 892 |
+
mech_pow_tot=mech_pow_tot/self._power_penalty_weights_sum
|
| 893 |
+
return mech_pow_tot
|
| 894 |
+
|
| 895 |
+
def _cost_of_transport(self, jnts_vel, jnts_effort, v_norm, mass_weight: bool = False):
|
| 896 |
+
drained_mech_pow=self._mech_pow(jnts_vel=jnts_vel,
|
| 897 |
+
jnts_effort=jnts_effort,
|
| 898 |
+
drained=True)
|
| 899 |
+
CoT=drained_mech_pow/(v_norm+1e-2)
|
| 900 |
+
if mass_weight:
|
| 901 |
+
robot_weight=self._rhc_robot_weight
|
| 902 |
+
CoT=CoT/robot_weight
|
| 903 |
+
|
| 904 |
+
# add to db metrics
|
| 905 |
+
self._pow_db_data[:, 0:1]=CoT.cpu()
|
| 906 |
+
self._pow_db_data[:, 1:2]=drained_mech_pow.cpu()
|
| 907 |
+
|
| 908 |
+
return CoT
|
| 909 |
+
|
| 910 |
+
def _jnt_vel_penalty(self, jnts_vel):
|
| 911 |
+
weighted_jnt_vel = torch.sum(jnts_vel*jnts_vel, dim=1, keepdim=True)/self._n_jnts
|
| 912 |
+
return weighted_jnt_vel
|
| 913 |
+
|
| 914 |
+
def _rhc_fail_idx(self, gpu: bool):
|
| 915 |
+
rhc_fail_idx = self._rhc_status.rhc_fail_idx.get_torch_mirror(gpu=gpu)
|
| 916 |
+
return self._env_opts["rhc_fail_idx_scale"]*rhc_fail_idx
|
| 917 |
+
|
| 918 |
+
# basic L1 and L2 error functions
|
| 919 |
+
def _track_err_wmse(self, task_ref, task_meas, scaling, weights):
|
| 920 |
+
# weighted mean-squared error computation
|
| 921 |
+
task_error = (task_meas-task_ref)
|
| 922 |
+
# add to db metrics
|
| 923 |
+
self._track_error_db[:, :]=torch.abs(task_error)
|
| 924 |
+
scaled_error=task_error/scaling
|
| 925 |
+
|
| 926 |
+
task_wmse = torch.sum(scaled_error*scaled_error*weights, dim=1, keepdim=True)/torch.sum(weights).item()
|
| 927 |
+
return task_wmse # weighted mean square error (along task dimension)
|
| 928 |
+
|
| 929 |
+
def _track_err_dir_wmse(self, task_ref, task_meas, scaling, weights):
|
| 930 |
+
# weighted DIRECTIONAL mean-squared error computation
|
| 931 |
+
task_error = (task_meas-task_ref)
|
| 932 |
+
# add to db metrics
|
| 933 |
+
self._track_error_db[:, :]=torch.abs(task_error)
|
| 934 |
+
task_error=task_error/scaling
|
| 935 |
+
|
| 936 |
+
# projection along commanded direction and gravity, matching paper formulation
|
| 937 |
+
v_ref=task_ref[:, 0:3]
|
| 938 |
+
delta_v=task_error[:, 0:3]
|
| 939 |
+
|
| 940 |
+
v_ref_norm=torch.norm(v_ref, dim=1, keepdim=True)
|
| 941 |
+
cmd_dir=v_ref/(v_ref_norm+1e-8)
|
| 942 |
+
# fallback to measured direction if command is (near) zero to avoid degenerate projection
|
| 943 |
+
meas_dir=task_meas[:, 0:3]
|
| 944 |
+
meas_dir=meas_dir/(torch.norm(meas_dir, dim=1, keepdim=True)+1e-8)
|
| 945 |
+
cmd_dir=torch.where((v_ref_norm>1e-6), cmd_dir, meas_dir)
|
| 946 |
+
|
| 947 |
+
gravity_dir = self._robot_state.root_state.get(data_type="gn",gpu=self._use_gpu) # normalized gravity in base frame
|
| 948 |
+
gravity_dir = gravity_dir/(torch.norm(gravity_dir, dim=1, keepdim=True)+1e-8)
|
| 949 |
+
|
| 950 |
+
forward_error=torch.sum(delta_v*cmd_dir, dim=1, keepdim=True)
|
| 951 |
+
vertical_error=torch.sum(delta_v*gravity_dir, dim=1, keepdim=True)
|
| 952 |
+
lateral_vec=delta_v - vertical_error*gravity_dir - forward_error*cmd_dir
|
| 953 |
+
lateral_error=torch.norm(lateral_vec, dim=1, keepdim=True)
|
| 954 |
+
|
| 955 |
+
# angular directional components: use gravity as vertical, project base x onto the world xy plane for roll, and close the triad with pitch
|
| 956 |
+
base_x = self._base_x_dir
|
| 957 |
+
base_y = self._base_y_dir
|
| 958 |
+
|
| 959 |
+
roll_dir = base_x - torch.sum(base_x*gravity_dir, dim=1, keepdim=True)*gravity_dir
|
| 960 |
+
roll_norm = torch.norm(roll_dir, dim=1, keepdim=True)
|
| 961 |
+
roll_dir_alt = base_y - torch.sum(base_y*gravity_dir, dim=1, keepdim=True)*gravity_dir # fallback if base x is almost aligned with gravity
|
| 962 |
+
roll_norm_alt = torch.norm(roll_dir_alt, dim=1, keepdim=True)
|
| 963 |
+
use_alt_roll = roll_norm < 1e-6
|
| 964 |
+
roll_dir = torch.where(use_alt_roll, roll_dir_alt, roll_dir)
|
| 965 |
+
roll_norm = torch.where(use_alt_roll, roll_norm_alt, roll_norm)
|
| 966 |
+
roll_dir = roll_dir/(roll_norm+1e-8)
|
| 967 |
+
|
| 968 |
+
pitch_dir = torch.cross(gravity_dir, roll_dir, dim=1)
|
| 969 |
+
pitch_dir = pitch_dir/(torch.norm(pitch_dir, dim=1, keepdim=True)+1e-8)
|
| 970 |
+
|
| 971 |
+
delta_omega = task_error[:, 3:6]
|
| 972 |
+
omega_roll_error = torch.sum(delta_omega*roll_dir, dim=1, keepdim=True)
|
| 973 |
+
omega_pitch_error = torch.sum(delta_omega*pitch_dir, dim=1, keepdim=True)
|
| 974 |
+
omega_vertical_error = torch.sum(delta_omega*gravity_dir, dim=1, keepdim=True)
|
| 975 |
+
|
| 976 |
+
full_error=torch.cat((forward_error, lateral_error, vertical_error, omega_roll_error, omega_pitch_error, omega_vertical_error), dim=1)
|
| 977 |
+
task_wmse_dir = torch.sum(full_error*full_error*weights, dim=1, keepdim=True)/torch.sum(weights).item()
|
| 978 |
+
return task_wmse_dir # weighted mean square error (along task dimension)
|
| 979 |
+
|
| 980 |
+
# L2 errors
|
| 981 |
+
def _tracking_err_rel_wmse(self, task_ref, task_meas, weights, directional: bool = False):
|
| 982 |
+
ref_norm = task_ref.norm(dim=1,keepdim=True) # norm of the full twist reference
|
| 983 |
+
self._task_err_scaling[:, :] = ref_norm+1e-2
|
| 984 |
+
if directional:
|
| 985 |
+
task_rel_err_wmse=self._track_err_dir_wmse(task_ref=task_ref, task_meas=task_meas,
|
| 986 |
+
scaling=self._task_err_scaling, weights=weights)
|
| 987 |
+
else:
|
| 988 |
+
task_rel_err_wmse=self._track_err_wmse(task_ref=task_ref, task_meas=task_meas,
|
| 989 |
+
scaling=self._task_err_scaling, weights=weights)
|
| 990 |
+
return task_rel_err_wmse
|
| 991 |
+
|
| 992 |
+
def _tracking_err_wmse(self, task_ref, task_meas, weights, directional: bool = False):
|
| 993 |
+
self._task_err_scaling[:, :] = 1
|
| 994 |
+
if directional:
|
| 995 |
+
task_err_wmse = self._track_err_dir_wmse(task_ref=task_ref,
|
| 996 |
+
task_meas=task_meas, scaling=self._task_err_scaling, weights=weights)
|
| 997 |
+
else:
|
| 998 |
+
task_err_wmse = self._track_err_wmse(task_ref=task_ref,
|
| 999 |
+
task_meas=task_meas, scaling=self._task_err_scaling, weights=weights)
|
| 1000 |
+
return task_err_wmse
|
| 1001 |
+
|
| 1002 |
+
# L1 errors
|
| 1003 |
+
def _tracking_err_rel_lin(self, task_ref, task_meas, weights, directional):
|
| 1004 |
+
task_rel_err_wmse = self._tracking_err_rel_wmse(task_ref=task_ref,
|
| 1005 |
+
task_meas=task_meas, weights=weights, directional=directional)
|
| 1006 |
+
return task_rel_err_wmse.sqrt()
|
| 1007 |
+
|
| 1008 |
+
def _tracking_err_lin(self, task_ref, task_meas, weights, directional: bool = False):
|
| 1009 |
+
self._task_err_scaling[:, :] = 1
|
| 1010 |
+
task_err_wmse=self._tracking_err_wmse(task_ref=task_ref,
|
| 1011 |
+
task_meas=task_meas, weights=weights, directional=directional)
|
| 1012 |
+
return task_err_wmse.sqrt()
|
| 1013 |
+
|
| 1014 |
+
# reward computation over steps/substeps
|
| 1015 |
+
def _compute_step_rewards(self):
|
| 1016 |
+
|
| 1017 |
+
sub_rewards = self._sub_rewards.get_torch_mirror(gpu=self._use_gpu)
|
| 1018 |
+
|
| 1019 |
+
# tracking reward
|
| 1020 |
+
if self._env_opts["use_L1_norm"]: # linear errors
|
| 1021 |
+
task_error_fun = self._tracking_err_lin
|
| 1022 |
+
if self._env_opts["use_relative_error"]:
|
| 1023 |
+
task_error_fun = self._tracking_err_rel_lin
|
| 1024 |
+
else: # quadratic error
|
| 1025 |
+
task_error_fun = self._tracking_err_wmse
|
| 1026 |
+
if self._env_opts["use_relative_error"]:
|
| 1027 |
+
task_error_fun = self._tracking_err_rel_wmse
|
| 1028 |
+
|
| 1029 |
+
agent_task_ref_base_loc = self._agent_refs.rob_refs.root_state.get(data_type="twist",gpu=self._use_gpu) # high level agent refs (hybrid twist)
|
| 1030 |
+
self._get_avrg_step_root_twist(out=self._step_avrg_root_twist_base_loc, base_loc=True)
|
| 1031 |
+
task_error = task_error_fun(task_meas=self._step_avrg_root_twist_base_loc,
|
| 1032 |
+
task_ref=agent_task_ref_base_loc,
|
| 1033 |
+
weights=self._task_err_weights,
|
| 1034 |
+
directional=self._env_opts["directional_tracking"])
|
| 1035 |
+
|
| 1036 |
+
idx=self._reward_map["task_error"]
|
| 1037 |
+
if self._env_opts["use_exp_track_rew"]:
|
| 1038 |
+
sub_rewards[:, idx:(idx+1)] = \
|
| 1039 |
+
self._env_opts["task_track_offset_exp"]*torch.exp(-self._env_opts["task_track_scale_exp"]*task_error)
|
| 1040 |
+
else: # simple linear reward
|
| 1041 |
+
sub_rewards[:, idx:(idx+1)] = \
|
| 1042 |
+
self._env_opts["task_track_offset"]*(1.0-self._env_opts["task_track_scale"]*task_error)
|
| 1043 |
+
|
| 1044 |
+
if self._env_opts["use_fail_idx_weight"]: # add weight based on fail idx
|
| 1045 |
+
fail_idx=self._rhc_fail_idx(gpu=self._use_gpu)
|
| 1046 |
+
sub_rewards[:, idx:(idx+1)]=(1-fail_idx)*sub_rewards[:, idx:(idx+1)]
|
| 1047 |
+
if self._track_rew_smoother is not None: # smooth reward if required
|
| 1048 |
+
self._track_rew_smoother.update(new_signal=sub_rewards[:, 0:1])
|
| 1049 |
+
sub_rewards[:, idx:(idx+1)]=self._track_rew_smoother.get()
|
| 1050 |
+
|
| 1051 |
+
# action rate
|
| 1052 |
+
if self._env_opts["add_action_rate_reward"]:
|
| 1053 |
+
action_rate=self._action_rate()
|
| 1054 |
+
idx=self._reward_map["action_rate"]
|
| 1055 |
+
sub_rewards[:, idx:(idx+1)] = self._env_opts["action_rate_offset"]*(1.0-self._env_opts["action_rate_scale"]*action_rate)
|
| 1056 |
+
|
| 1057 |
+
# mpc vel tracking
|
| 1058 |
+
if self._env_opts["use_rhc_avrg_vel_tracking"]:
|
| 1059 |
+
self._get_avrg_rhc_root_twist(out=self._root_twist_avrg_rhc_base_loc_next,base_loc=True) # get estimated avrg vel
|
| 1060 |
+
# from MPC after stepping
|
| 1061 |
+
task_pred_error=task_error_fun(task_meas=self._root_twist_avrg_rhc_base_loc_next,
|
| 1062 |
+
task_ref=agent_task_ref_base_loc,
|
| 1063 |
+
weights=self._task_pred_err_weights,
|
| 1064 |
+
directional=self._env_opts["directional_tracking"])
|
| 1065 |
+
idx=self._reward_map["rhc_avrg_vel_error"]
|
| 1066 |
+
sub_rewards[:, idx:(idx+1)] = self._env_opts["task_pred_track_offset"]*torch.exp(-self._env_opts["task_pred_track_scale"]*task_pred_error)
|
| 1067 |
+
|
| 1068 |
+
def _compute_substep_rewards(self):
|
| 1069 |
+
|
| 1070 |
+
sub_rewards = self._sub_rewards.get_torch_mirror(gpu=self._use_gpu)
|
| 1071 |
+
|
| 1072 |
+
if self._env_opts["add_CoT_reward"] or self._env_opts["add_power_reward"]:
|
| 1073 |
+
jnts_vel = self._robot_state.jnts_state.get(data_type="v",gpu=self._use_gpu)
|
| 1074 |
+
jnts_effort = self._robot_state.jnts_state.get(data_type="eff",gpu=self._use_gpu)
|
| 1075 |
+
|
| 1076 |
+
if self._env_opts["add_CoT_reward"]:
|
| 1077 |
+
if self._env_opts["use_CoT_wrt_ref"]: # uses v ref norm for computing cot
|
| 1078 |
+
agent_task_ref_base_loc = self._agent_refs.rob_refs.root_state.get(data_type="twist",gpu=self._use_gpu)
|
| 1079 |
+
v_norm=torch.norm(agent_task_ref_base_loc, dim=1, keepdim=True)
|
| 1080 |
+
else: # uses measured velocity
|
| 1081 |
+
robot_twist_meas_base_loc = self._robot_state.root_state.get(data_type="twist",gpu=self._use_gpu)
|
| 1082 |
+
v_norm=torch.norm(robot_twist_meas_base_loc[:,0:3], dim=1, keepdim=True)
|
| 1083 |
+
CoT=self._cost_of_transport(jnts_vel=jnts_vel,jnts_effort=jnts_effort,v_norm=v_norm,
|
| 1084 |
+
mass_weight=True
|
| 1085 |
+
)
|
| 1086 |
+
idx=self._reward_map["CoT"]
|
| 1087 |
+
sub_rewards[:, idx:(idx+1)] = self._env_opts["CoT_offset"]*(1-self._env_opts["CoT_scale"]*CoT)
|
| 1088 |
+
if self._env_opts["add_power_reward"]:
|
| 1089 |
+
weighted_mech_power=self._mech_pow(jnts_vel=jnts_vel,jnts_effort=jnts_effort, drained=True)
|
| 1090 |
+
idx=self._reward_map["mech_pow"]
|
| 1091 |
+
sub_rewards[:, idx:(idx+1)] = self._env_opts["power_offset"]*(1-self._env_opts["power_scale"]*weighted_mech_power)
|
| 1092 |
+
|
| 1093 |
+
if self._env_opts["add_jnt_v_reward"]:
|
| 1094 |
+
jnts_vel = self._robot_state.jnts_state.get(data_type="v",gpu=self._use_gpu)
|
| 1095 |
+
jnt_v=self._jnt_vel_penalty(jnts_vel=jnts_vel)
|
| 1096 |
+
idx=self._reward_map["jnt_v"]
|
| 1097 |
+
sub_rewards[:, idx:(idx+1)] = self._env_opts["jnt_vel_offset"]*(1-self._env_opts["jnt_vel_scale"]*jnt_v)
|
| 1098 |
+
|
| 1099 |
+
def _randomize_task_refs(self,
|
| 1100 |
+
env_indxs: torch.Tensor = None):
|
| 1101 |
+
|
| 1102 |
+
# we randomize the reference in world frame, since it's much more intuitive
|
| 1103 |
+
# (it will be rotated in base frame when provided to the agent and used for rew
|
| 1104 |
+
# computation)
|
| 1105 |
+
|
| 1106 |
+
if self._env_opts["use_pof0"]: # sample from bernoulli distribution
|
| 1107 |
+
torch.bernoulli(input=self._pof1_b_linvel,out=self._bernoulli_coeffs_linvel) # by default bernoulli_coeffs are 1 if not self._env_opts["use_pof0"]
|
| 1108 |
+
torch.bernoulli(input=self._pof1_b_omega,out=self._bernoulli_coeffs_omega)
|
| 1109 |
+
if env_indxs is None:
|
| 1110 |
+
random_uniform=torch.full_like(self._agent_twist_ref_current_w, fill_value=0.0)
|
| 1111 |
+
torch.nn.init.uniform_(random_uniform, a=-1, b=1)
|
| 1112 |
+
self._agent_twist_ref_current_w[:, :] = random_uniform*self._twist_ref_scale + self._twist_ref_offset
|
| 1113 |
+
self._agent_twist_ref_current_w[:, 0:3] = self._agent_twist_ref_current_w[:, 0:3]*self._bernoulli_coeffs_linvel # linvel
|
| 1114 |
+
self._agent_twist_ref_current_w[:, 3:6] = self._agent_twist_ref_current_w[:, 3:6]*self._bernoulli_coeffs_omega # omega
|
| 1115 |
+
else:
|
| 1116 |
+
random_uniform=torch.full_like(self._agent_twist_ref_current_w[env_indxs, :], fill_value=0.0)
|
| 1117 |
+
torch.nn.init.uniform_(random_uniform, a=-1, b=1)
|
| 1118 |
+
self._agent_twist_ref_current_w[env_indxs, :] = random_uniform * self._twist_ref_scale + self._twist_ref_offset
|
| 1119 |
+
self._agent_twist_ref_current_w[env_indxs, 0:3] = self._agent_twist_ref_current_w[env_indxs, 0:3]*self._bernoulli_coeffs_linvel[env_indxs, :]
|
| 1120 |
+
self._agent_twist_ref_current_w[env_indxs, 3:6] = self._agent_twist_ref_current_w[env_indxs, 3:6]*self._bernoulli_coeffs_omega[env_indxs, :] # omega
|
| 1121 |
+
|
| 1122 |
+
def _get_obs_names(self):
|
| 1123 |
+
|
| 1124 |
+
obs_names = [""] * self.obs_dim()
|
| 1125 |
+
|
| 1126 |
+
# proprioceptive stream of obs
|
| 1127 |
+
next_idx=0
|
| 1128 |
+
|
| 1129 |
+
self._obs_map["gn_base"]=next_idx
|
| 1130 |
+
obs_names[0] = "gn_x_base_loc"
|
| 1131 |
+
obs_names[1] = "gn_y_base_loc"
|
| 1132 |
+
obs_names[2] = "gn_z_base_loc"
|
| 1133 |
+
next_idx+=3
|
| 1134 |
+
|
| 1135 |
+
self._obs_map["linvel_meas"]=next_idx
|
| 1136 |
+
obs_names[next_idx] = "linvel_x_base_loc"
|
| 1137 |
+
obs_names[next_idx+1] = "linvel_y_base_loc"
|
| 1138 |
+
obs_names[next_idx+2] = "linvel_z_base_loc"
|
| 1139 |
+
next_idx+=3
|
| 1140 |
+
|
| 1141 |
+
self._obs_map["omega_meas"]=next_idx
|
| 1142 |
+
obs_names[next_idx] = "omega_x_base_loc"
|
| 1143 |
+
obs_names[next_idx+1] = "omega_y_base_loc"
|
| 1144 |
+
obs_names[next_idx+2] = "omega_z_base_loc"
|
| 1145 |
+
next_idx+=3
|
| 1146 |
+
|
| 1147 |
+
jnt_names=self.get_observed_joints()
|
| 1148 |
+
self._obs_map["q_jnt"]=next_idx
|
| 1149 |
+
for i in range(self._n_jnts): # jnt obs (pos):
|
| 1150 |
+
obs_names[next_idx+i] = f"q_jnt_{jnt_names[i]}"
|
| 1151 |
+
next_idx+=self._n_jnts
|
| 1152 |
+
|
| 1153 |
+
self._obs_map["v_jnt"]=next_idx
|
| 1154 |
+
for i in range(self._n_jnts): # jnt obs (v):
|
| 1155 |
+
obs_names[next_idx+i] = f"v_jnt_{jnt_names[i]}"
|
| 1156 |
+
next_idx+=self._n_jnts
|
| 1157 |
+
|
| 1158 |
+
# references
|
| 1159 |
+
self._obs_map["twist_ref"]=next_idx
|
| 1160 |
+
obs_names[next_idx] = "linvel_x_ref_base_loc"
|
| 1161 |
+
obs_names[next_idx+1] = "linvel_y_ref_base_loc"
|
| 1162 |
+
obs_names[next_idx+2] = "linvel_z_ref_base_loc"
|
| 1163 |
+
obs_names[next_idx+3] = "omega_x_ref_base_loc"
|
| 1164 |
+
obs_names[next_idx+4] = "omega_y_ref_base_loc"
|
| 1165 |
+
obs_names[next_idx+5] = "omega_z_ref_base_loc"
|
| 1166 |
+
next_idx+=6
|
| 1167 |
+
|
| 1168 |
+
# contact forces
|
| 1169 |
+
if self._env_opts["add_mpc_contact_f_to_obs"]:
|
| 1170 |
+
i = 0
|
| 1171 |
+
self._obs_map["contact_f_mpc"]=next_idx
|
| 1172 |
+
for contact in self._contact_names:
|
| 1173 |
+
obs_names[next_idx+i] = f"fc_{contact}_x_base_loc"
|
| 1174 |
+
obs_names[next_idx+i+1] = f"fc_{contact}_y_base_loc"
|
| 1175 |
+
obs_names[next_idx+i+2] = f"fc_{contact}_z_base_loc"
|
| 1176 |
+
i+=3
|
| 1177 |
+
next_idx+=3*len(self._contact_names)
|
| 1178 |
+
|
| 1179 |
+
# data directly from MPC
|
| 1180 |
+
if self._env_opts["add_fail_idx_to_obs"]:
|
| 1181 |
+
self._obs_map["rhc_fail_idx"]=next_idx
|
| 1182 |
+
obs_names[next_idx] = "rhc_fail_idx"
|
| 1183 |
+
next_idx+=1
|
| 1184 |
+
if self._env_opts["add_term_mpc_capsize"]:
|
| 1185 |
+
self._obs_map["gn_base_mpc"]=next_idx
|
| 1186 |
+
obs_names[next_idx] = "gn_x_rhc_base_loc"
|
| 1187 |
+
obs_names[next_idx+1] = "gn_y_rhc_base_loc"
|
| 1188 |
+
obs_names[next_idx+2] = "gn_z_rhc_base_loc"
|
| 1189 |
+
next_idx+=3
|
| 1190 |
+
if self._env_opts["use_rhc_avrg_vel_tracking"]:
|
| 1191 |
+
self._obs_map["avrg_twist_mpc"]=next_idx
|
| 1192 |
+
obs_names[next_idx] = "linvel_x_avrg_rhc"
|
| 1193 |
+
obs_names[next_idx+1] = "linvel_y_avrg_rhc"
|
| 1194 |
+
obs_names[next_idx+2] = "linvel_z_avrg_rhc"
|
| 1195 |
+
obs_names[next_idx+3] = "omega_x_avrg_rhc"
|
| 1196 |
+
obs_names[next_idx+4] = "omega_y_avrg_rhc"
|
| 1197 |
+
obs_names[next_idx+5] = "omega_z_avrg_rhc"
|
| 1198 |
+
next_idx+=6
|
| 1199 |
+
|
| 1200 |
+
if self._env_opts["add_flight_info"]:
|
| 1201 |
+
self._obs_map["flight_info"]=next_idx
|
| 1202 |
+
for i in range(len(self._contact_names)):
|
| 1203 |
+
obs_names[next_idx+i] = "flight_pos_"+ self._contact_names[i]
|
| 1204 |
+
next_idx+=len(self._contact_names)
|
| 1205 |
+
for i in range(len(self._contact_names)):
|
| 1206 |
+
obs_names[next_idx+i] = "flight_len_remaining_"+ self._contact_names[i]
|
| 1207 |
+
next_idx+=len(self._contact_names)
|
| 1208 |
+
for i in range(len(self._contact_names)):
|
| 1209 |
+
obs_names[next_idx+i] = "flight_len_nominal_"+ self._contact_names[i]
|
| 1210 |
+
next_idx+=len(self._contact_names)
|
| 1211 |
+
for i in range(len(self._contact_names)):
|
| 1212 |
+
obs_names[next_idx+i] = "flight_apex_nominal_"+ self._contact_names[i]
|
| 1213 |
+
next_idx+=len(self._contact_names)
|
| 1214 |
+
for i in range(len(self._contact_names)):
|
| 1215 |
+
obs_names[next_idx+i] = "flight_end_nominal_"+ self._contact_names[i]
|
| 1216 |
+
next_idx+=len(self._contact_names)
|
| 1217 |
+
|
| 1218 |
+
if self._env_opts["add_flight_settings"]:
|
| 1219 |
+
self._obs_map["flight_settings_req"]=next_idx
|
| 1220 |
+
for i in range(len(self._contact_names)):
|
| 1221 |
+
obs_names[next_idx+i] = "flight_len_req_"+ self._contact_names[i]
|
| 1222 |
+
next_idx+=len(self._contact_names)
|
| 1223 |
+
for i in range(len(self._contact_names)):
|
| 1224 |
+
obs_names[next_idx+i] = "flight_apex_req_"+ self._contact_names[i]
|
| 1225 |
+
next_idx+=len(self._contact_names)
|
| 1226 |
+
for i in range(len(self._contact_names)):
|
| 1227 |
+
obs_names[next_idx+i] = "flight_end_req_"+ self._contact_names[i]
|
| 1228 |
+
next_idx+=len(self._contact_names)
|
| 1229 |
+
|
| 1230 |
+
if self._env_opts["add_rhc_cmds_to_obs"]:
|
| 1231 |
+
self._obs_map["rhc_cmds_q"]=next_idx
|
| 1232 |
+
for i in range(self._n_jnts): # jnt obs (pos):
|
| 1233 |
+
obs_names[next_idx+i] = f"rhc_cmd_q_{jnt_names[i]}"
|
| 1234 |
+
next_idx+=self._n_jnts
|
| 1235 |
+
self._obs_map["rhc_cmds_v"]=next_idx
|
| 1236 |
+
for i in range(self._n_jnts): # jnt obs (pos):
|
| 1237 |
+
obs_names[next_idx+i] = f"rhc_cmd_v_{jnt_names[i]}"
|
| 1238 |
+
next_idx+=self._n_jnts
|
| 1239 |
+
self._obs_map["rhc_cmds_eff"]=next_idx
|
| 1240 |
+
for i in range(self._n_jnts): # jnt obs (pos):
|
| 1241 |
+
obs_names[next_idx+i] = f"rhc_cmd_eff_{jnt_names[i]}"
|
| 1242 |
+
next_idx+=self._n_jnts
|
| 1243 |
+
|
| 1244 |
+
# previous actions info
|
| 1245 |
+
if self._env_opts["use_action_history"]:
|
| 1246 |
+
self._obs_map["action_history"]=next_idx
|
| 1247 |
+
action_names = self._get_action_names()
|
| 1248 |
+
if self._env_opts["add_prev_actions_stats_to_obs"]:
|
| 1249 |
+
self._obs_map["action_history_prev"]=next_idx
|
| 1250 |
+
for act_idx in range(self.actions_dim()):
|
| 1251 |
+
obs_names[next_idx+act_idx] = action_names[act_idx]+f"_prev_act"
|
| 1252 |
+
next_idx+=self.actions_dim()
|
| 1253 |
+
self._obs_map["action_history_avrg"]=next_idx
|
| 1254 |
+
for act_idx in range(self.actions_dim()):
|
| 1255 |
+
obs_names[next_idx+act_idx] = action_names[act_idx]+f"_avrg_act"
|
| 1256 |
+
next_idx+=self.actions_dim()
|
| 1257 |
+
self._obs_map["action_history_std"]=next_idx
|
| 1258 |
+
for act_idx in range(self.actions_dim()):
|
| 1259 |
+
obs_names[next_idx+act_idx] = action_names[act_idx]+f"_std_act"
|
| 1260 |
+
next_idx+=self.actions_dim()
|
| 1261 |
+
else:
|
| 1262 |
+
for i in range(self._env_opts["actions_history_size"]):
|
| 1263 |
+
for act_idx in range(self.actions_dim()):
|
| 1264 |
+
obs_names[next_idx+act_idx] = action_names[act_idx]+f"_m{i+1}_act"
|
| 1265 |
+
next_idx+=self.actions_dim()
|
| 1266 |
+
|
| 1267 |
+
if self._env_opts["use_action_smoothing"]:
|
| 1268 |
+
self._obs_map["action_smoothing"]=next_idx
|
| 1269 |
+
for smoothed_action in range(self.actions_dim()):
|
| 1270 |
+
obs_names[next_idx+smoothed_action] = action_names[smoothed_action]+f"_smoothed"
|
| 1271 |
+
next_idx+=self.actions_dim()
|
| 1272 |
+
|
| 1273 |
+
if self._env_opts["add_periodic_clock_to_obs"]:
|
| 1274 |
+
self._obs_map["clock"]=next_idx
|
| 1275 |
+
obs_names[next_idx] = "clock_cos"
|
| 1276 |
+
obs_names[next_idx+1] = "clock_sin"
|
| 1277 |
+
next_idx+=2
|
| 1278 |
+
if self._env_opts["add_heightmap_obs"] and self._height_grid_size is not None:
|
| 1279 |
+
self._obs_map["heightmap"]=next_idx
|
| 1280 |
+
gs = self._height_grid_size
|
| 1281 |
+
for r in range(gs):
|
| 1282 |
+
for c in range(gs):
|
| 1283 |
+
obs_names[next_idx] = f"height_r{r}_c{c}"
|
| 1284 |
+
next_idx += 1
|
| 1285 |
+
|
| 1286 |
+
return obs_names
|
| 1287 |
+
|
| 1288 |
+
def _set_substep_obs(self):
|
| 1289 |
+
# which obs are to be averaged over substeps?
|
| 1290 |
+
|
| 1291 |
+
self._is_substep_obs[self._obs_map["linvel_meas"]:self._obs_map["linvel_meas"]+3]=True
|
| 1292 |
+
self._is_substep_obs[self._obs_map["omega_meas"]:self._obs_map["omega_meas"]+3]=True
|
| 1293 |
+
self._is_substep_obs[self._obs_map["v_jnt"]:self._obs_map["v_jnt"]+self._n_jnts]=True # also good for noise
|
| 1294 |
+
|
| 1295 |
+
# self._is_substep_obs[self._obs_map["contact_f_mpc"]:self._obs_map["contact_f_mpc"]+3*len(self._contact_names)]=True
|
| 1296 |
+
|
| 1297 |
+
def _get_action_names(self):
|
| 1298 |
+
|
| 1299 |
+
action_names = [""] * self.actions_dim()
|
| 1300 |
+
action_names[0] = "vx_cmd" # twist commands from agent to RHC controller
|
| 1301 |
+
action_names[1] = "vy_cmd"
|
| 1302 |
+
action_names[2] = "vz_cmd"
|
| 1303 |
+
action_names[3] = "roll_omega_cmd"
|
| 1304 |
+
action_names[4] = "pitch_omega_cmd"
|
| 1305 |
+
action_names[5] = "yaw_omega_cmd"
|
| 1306 |
+
|
| 1307 |
+
next_idx=6
|
| 1308 |
+
|
| 1309 |
+
self._actions_map["contact_flag_start"]=next_idx
|
| 1310 |
+
for i in range(len(self._contact_names)):
|
| 1311 |
+
contact=self._contact_names[i]
|
| 1312 |
+
action_names[next_idx] = f"contact_flag_{contact}"
|
| 1313 |
+
next_idx+=1
|
| 1314 |
+
|
| 1315 |
+
return action_names
|
| 1316 |
+
|
| 1317 |
+
def _set_substep_rew(self):
|
| 1318 |
+
|
| 1319 |
+
# which rewards are to be computed at substeps frequency?
|
| 1320 |
+
self._is_substep_rew[self._reward_map["task_error"]]=False
|
| 1321 |
+
if self._env_opts["add_CoT_reward"]:
|
| 1322 |
+
self._is_substep_rew[self._reward_map["CoT"]]=True
|
| 1323 |
+
if self._env_opts["add_power_reward"]:
|
| 1324 |
+
self._is_substep_rew[self._reward_map["mech_pow"]]=True
|
| 1325 |
+
if self._env_opts["add_action_rate_reward"]:
|
| 1326 |
+
self._is_substep_rew[self._reward_map["action_rate"]]=False
|
| 1327 |
+
if self._env_opts["add_jnt_v_reward"]:
|
| 1328 |
+
self._is_substep_rew[self._reward_map["jnt_v"]]=True
|
| 1329 |
+
|
| 1330 |
+
if self._env_opts["use_rhc_avrg_vel_tracking"]:
|
| 1331 |
+
self._is_substep_rew[self._reward_map["rhc_avrg_vel_error"]]=False
|
| 1332 |
+
|
| 1333 |
+
def _get_rewards_names(self):
|
| 1334 |
+
|
| 1335 |
+
counter=0
|
| 1336 |
+
reward_names = []
|
| 1337 |
+
|
| 1338 |
+
# adding rewards
|
| 1339 |
+
reward_names.append("task_error")
|
| 1340 |
+
self._reward_map["task_error"]=counter
|
| 1341 |
+
self._reward_lb_map["task_error"]="task_error_reward_lb"
|
| 1342 |
+
counter+=1
|
| 1343 |
+
if self._env_opts["add_power_reward"] and self._env_opts["add_CoT_reward"]:
|
| 1344 |
+
Journal.log(self.__class__.__name__,
|
| 1345 |
+
"__init__",
|
| 1346 |
+
"Only one between CoT and power reward can be used!",
|
| 1347 |
+
LogType.EXCEP,
|
| 1348 |
+
throw_when_excep=True)
|
| 1349 |
+
if self._env_opts["add_CoT_reward"]:
|
| 1350 |
+
reward_names.append("CoT")
|
| 1351 |
+
self._reward_map["CoT"]=counter
|
| 1352 |
+
self._reward_lb_map["CoT"]="CoT_reward_lb"
|
| 1353 |
+
counter+=1
|
| 1354 |
+
if self._env_opts["add_power_reward"]:
|
| 1355 |
+
reward_names.append("mech_pow")
|
| 1356 |
+
self._reward_map["mech_pow"]=counter
|
| 1357 |
+
self._reward_lb_map["mech_pow"]="power_reward_lb"
|
| 1358 |
+
counter+=1
|
| 1359 |
+
if self._env_opts["add_action_rate_reward"]:
|
| 1360 |
+
reward_names.append("action_rate")
|
| 1361 |
+
self._reward_map["action_rate"]=counter
|
| 1362 |
+
self._reward_lb_map["action_rate"]="action_rate_reward_lb"
|
| 1363 |
+
counter+=1
|
| 1364 |
+
if self._env_opts["add_jnt_v_reward"]:
|
| 1365 |
+
reward_names.append("jnt_v")
|
| 1366 |
+
self._reward_map["jnt_v"]=counter
|
| 1367 |
+
self._reward_lb_map["jnt_v"]="jnt_vel_reward_lb"
|
| 1368 |
+
counter+=1
|
| 1369 |
+
if self._env_opts["use_rhc_avrg_vel_tracking"]:
|
| 1370 |
+
reward_names.append("rhc_avrg_vel_error")
|
| 1371 |
+
self._reward_map["rhc_avrg_vel_error"]=counter
|
| 1372 |
+
self._reward_lb_map["rhc_avrg_vel_error"]="rhc_avrg_vel_reward_lb"
|
| 1373 |
+
counter+=1
|
| 1374 |
+
|
| 1375 |
+
return reward_names
|
| 1376 |
+
|
| 1377 |
+
def _get_sub_trunc_names(self):
|
| 1378 |
+
sub_trunc_names = []
|
| 1379 |
+
sub_trunc_names.append("ep_timeout")
|
| 1380 |
+
if self._env_opts["single_task_ref_per_episode"]:
|
| 1381 |
+
sub_trunc_names.append("task_ref_rand")
|
| 1382 |
+
return sub_trunc_names
|
| 1383 |
+
|
| 1384 |
+
def _get_sub_term_names(self):
|
| 1385 |
+
# to be overridden by child class
|
| 1386 |
+
sub_term_names = []
|
| 1387 |
+
sub_term_names.append("rhc_failure")
|
| 1388 |
+
sub_term_names.append("robot_capsize")
|
| 1389 |
+
if self._env_opts["add_term_mpc_capsize"]:
|
| 1390 |
+
sub_term_names.append("rhc_capsize")
|
| 1391 |
+
|
| 1392 |
+
return sub_term_names
|
| 1393 |
+
|
| 1394 |
+
def _set_jnts_blacklist_pattern(self):
|
| 1395 |
+
# used to exclude pos measurement from wheels
|
| 1396 |
+
self._jnt_q_blacklist_patterns=["wheel"]
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/world_interface_base.py
ADDED
|
@@ -0,0 +1,1486 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from aug_mpc.controllers.rhc.augmpc_cluster_server import AugMpcClusterServer
|
| 2 |
+
from aug_mpc.utils.shared_data.remote_stepping import RemoteStepperClnt
|
| 3 |
+
from aug_mpc.utils.shared_data.remote_stepping import RemoteResetClnt
|
| 4 |
+
from aug_mpc.utils.shared_data.remote_stepping import RemoteResetRequest
|
| 5 |
+
from aug_mpc.utils.jnt_imp_control_base import JntImpCntrlBase
|
| 6 |
+
from aug_mpc.utils.hybrid_quad_xrdf_gen import get_xrdf_cmds
|
| 7 |
+
from aug_mpc.utils.xrdf_gen import generate_srdf, generate_urdf
|
| 8 |
+
from aug_mpc.utils.math_utils import quaternion_difference
|
| 9 |
+
from aug_mpc.utils.custom_arg_parsing import extract_custom_xacro_args, merge_xacro_cmds
|
| 10 |
+
|
| 11 |
+
from aug_mpc.utils.filtering import FirstOrderFilter
|
| 12 |
+
|
| 13 |
+
from mpc_hive.utilities.homing import RobotHomer
|
| 14 |
+
from mpc_hive.utilities.shared_data.jnt_imp_control import JntImpCntrlData
|
| 15 |
+
|
| 16 |
+
from EigenIPC.PyEigenIPC import VLevel, Journal, LogType, dtype
|
| 17 |
+
from EigenIPC.PyEigenIPC import StringTensorServer
|
| 18 |
+
from EigenIPC.PyEigenIPCExt.wrappers.shared_data_view import SharedTWrapper
|
| 19 |
+
|
| 20 |
+
from typing import List, Union, Dict, TypeVar
|
| 21 |
+
|
| 22 |
+
import os
|
| 23 |
+
import inspect
|
| 24 |
+
import signal
|
| 25 |
+
import time
|
| 26 |
+
|
| 27 |
+
import numpy as np
|
| 28 |
+
import torch
|
| 29 |
+
|
| 30 |
+
from abc import ABC, abstractmethod
|
| 31 |
+
|
| 32 |
+
JntImpCntrlChild = TypeVar('JntImpCntrlChild', bound='JntImpCntrlBase')
|
| 33 |
+
|
| 34 |
+
class AugMPCWorldInterfaceBase(ABC):
|
| 35 |
+
|
| 36 |
+
def __init__(self,
|
| 37 |
+
robot_names: List[str],
|
| 38 |
+
robot_urdf_paths: List[str],
|
| 39 |
+
robot_srdf_paths: List[str],
|
| 40 |
+
jnt_imp_config_paths: List[str],
|
| 41 |
+
n_contacts: List[int],
|
| 42 |
+
cluster_dt: List[float],
|
| 43 |
+
use_remote_stepping: List[bool],
|
| 44 |
+
name: str = "AugMPCWorldInterfaceBase",
|
| 45 |
+
num_envs: int = 1,
|
| 46 |
+
debug = False,
|
| 47 |
+
verbose: bool = False,
|
| 48 |
+
vlevel: VLevel = VLevel.V1,
|
| 49 |
+
n_init_step: int = 0,
|
| 50 |
+
timeout_ms: int = 60000,
|
| 51 |
+
env_opts: Dict = None,
|
| 52 |
+
use_gpu: bool = True,
|
| 53 |
+
dtype: torch.dtype = torch.float32,
|
| 54 |
+
dump_basepath: str = "/tmp",
|
| 55 |
+
override_low_lev_controller: bool = False):
|
| 56 |
+
|
| 57 |
+
# checks on input args
|
| 58 |
+
# type checks
|
| 59 |
+
if not isinstance(robot_names, List):
|
| 60 |
+
exception = "robot_names must be a list!"
|
| 61 |
+
Journal.log(self.__class__.__name__,
|
| 62 |
+
"__init__",
|
| 63 |
+
exception,
|
| 64 |
+
LogType.EXCEP,
|
| 65 |
+
throw_when_excep = True)
|
| 66 |
+
if not isinstance(robot_urdf_paths, List):
|
| 67 |
+
exception = "robot_urdf_paths must be a list!"
|
| 68 |
+
Journal.log(self.__class__.__name__,
|
| 69 |
+
"__init__",
|
| 70 |
+
exception,
|
| 71 |
+
LogType.EXCEP,
|
| 72 |
+
throw_when_excep = True)
|
| 73 |
+
if not isinstance(robot_srdf_paths, List):
|
| 74 |
+
exception = "robot_srdf_paths must be a list!"
|
| 75 |
+
Journal.log(self.__class__.__name__,
|
| 76 |
+
"__init__",
|
| 77 |
+
exception,
|
| 78 |
+
LogType.EXCEP,
|
| 79 |
+
throw_when_excep = True)
|
| 80 |
+
if not isinstance(cluster_dt, List):
|
| 81 |
+
exception = "cluster_dt must be a list!"
|
| 82 |
+
Journal.log(self.__class__.__name__,
|
| 83 |
+
"__init__",
|
| 84 |
+
exception,
|
| 85 |
+
LogType.EXCEP,
|
| 86 |
+
throw_when_excep = True)
|
| 87 |
+
if not isinstance(use_remote_stepping, List):
|
| 88 |
+
exception = "use_remote_stepping must be a list!"
|
| 89 |
+
Journal.log(self.__class__.__name__,
|
| 90 |
+
"__init__",
|
| 91 |
+
exception,
|
| 92 |
+
LogType.EXCEP,
|
| 93 |
+
throw_when_excep = True)
|
| 94 |
+
if not isinstance(n_contacts, List):
|
| 95 |
+
exception = "n_contacts must be a list (of integers)!"
|
| 96 |
+
Journal.log(self.__class__.__name__,
|
| 97 |
+
"__init__",
|
| 98 |
+
exception,
|
| 99 |
+
LogType.EXCEP,
|
| 100 |
+
throw_when_excep = True)
|
| 101 |
+
if not isinstance(jnt_imp_config_paths, List):
|
| 102 |
+
exception = "jnt_imp_config_paths must be a list paths!"
|
| 103 |
+
Journal.log(self.__class__.__name__,
|
| 104 |
+
"__init__",
|
| 105 |
+
exception,
|
| 106 |
+
LogType.EXCEP,
|
| 107 |
+
throw_when_excep = True)
|
| 108 |
+
|
| 109 |
+
# dim checks
|
| 110 |
+
if not len(robot_urdf_paths) == len(robot_names):
|
| 111 |
+
exception = f"robot_urdf_paths has len {len(robot_urdf_paths)}" + \
|
| 112 |
+
f" while robot_names {len(robot_names)}"
|
| 113 |
+
Journal.log(self.__class__.__name__,
|
| 114 |
+
"__init__",
|
| 115 |
+
exception,
|
| 116 |
+
LogType.EXCEP,
|
| 117 |
+
throw_when_excep = True)
|
| 118 |
+
if not len(robot_srdf_paths) == len(robot_names):
|
| 119 |
+
exception = f"robot_srdf_paths has len {len(robot_srdf_paths)}" + \
|
| 120 |
+
f" while robot_names {len(robot_names)}"
|
| 121 |
+
Journal.log(self.__class__.__name__,
|
| 122 |
+
"__init__",
|
| 123 |
+
exception,
|
| 124 |
+
LogType.EXCEP,
|
| 125 |
+
throw_when_excep = True)
|
| 126 |
+
if not len(cluster_dt) == len(robot_names):
|
| 127 |
+
exception = f"cluster_dt has len {len(cluster_dt)}" + \
|
| 128 |
+
f" while robot_names {len(robot_names)}"
|
| 129 |
+
Journal.log(self.__class__.__name__,
|
| 130 |
+
"__init__",
|
| 131 |
+
exception,
|
| 132 |
+
LogType.EXCEP,
|
| 133 |
+
throw_when_excep = True)
|
| 134 |
+
if not len(use_remote_stepping) == len(robot_names):
|
| 135 |
+
exception = f"use_remote_stepping has len {len(use_remote_stepping)}" + \
|
| 136 |
+
f" while robot_names {len(robot_names)}"
|
| 137 |
+
Journal.log(self.__class__.__name__,
|
| 138 |
+
"__init__",
|
| 139 |
+
exception,
|
| 140 |
+
LogType.EXCEP,
|
| 141 |
+
throw_when_excep = True)
|
| 142 |
+
if not len(robot_srdf_paths) == len(robot_names):
|
| 143 |
+
exception = f"robot_srdf_paths has len {len(robot_srdf_paths)}" + \
|
| 144 |
+
f" while robot_names {len(robot_names)}"
|
| 145 |
+
Journal.log(self.__class__.__name__,
|
| 146 |
+
"__init__",
|
| 147 |
+
exception,
|
| 148 |
+
LogType.EXCEP,
|
| 149 |
+
throw_when_excep = True)
|
| 150 |
+
if not len(jnt_imp_config_paths) == len(robot_names):
|
| 151 |
+
exception = f"jnt_imp_config_paths has len {len(jnt_imp_config_paths)}" + \
|
| 152 |
+
f" while robot_names {len(robot_names)}"
|
| 153 |
+
Journal.log(self.__class__.__name__,
|
| 154 |
+
"__init__",
|
| 155 |
+
exception,
|
| 156 |
+
LogType.EXCEP,
|
| 157 |
+
throw_when_excep = True)
|
| 158 |
+
|
| 159 |
+
self._remote_exit_flag=None
|
| 160 |
+
|
| 161 |
+
self._name=name
|
| 162 |
+
self._num_envs=num_envs
|
| 163 |
+
self._debug=debug
|
| 164 |
+
self._verbose=verbose
|
| 165 |
+
self._vlevel=vlevel
|
| 166 |
+
self._force_reconnection=True
|
| 167 |
+
self._timeout_ms=timeout_ms
|
| 168 |
+
self._use_gpu=use_gpu
|
| 169 |
+
self._device = "cuda" if self._use_gpu else "cpu"
|
| 170 |
+
self._dtype=dtype
|
| 171 |
+
self._robot_names=robot_names
|
| 172 |
+
self._env_opts={}
|
| 173 |
+
self._env_opts["deact_when_failure"]=True
|
| 174 |
+
self._env_opts["filter_jnt_vel"]=False
|
| 175 |
+
self._env_opts["filter_cutoff_freq"]=10.0 # [Hz]
|
| 176 |
+
self._env_opts["filter_sampling_rate"]=100 # rate at which state is filtered [Hz]
|
| 177 |
+
self._env_opts["add_remote_exit_flag"]=False # add shared data server to trigger a remote exit
|
| 178 |
+
|
| 179 |
+
self._env_opts["enable_height_sensor"]=False
|
| 180 |
+
self._env_opts["height_sensor_resolution"]=0.16
|
| 181 |
+
self._env_opts["height_sensor_pixels"]=10
|
| 182 |
+
self._env_opts["height_sensor_lateral_offset"]=0.0
|
| 183 |
+
self._env_opts["height_sensor_forward_offset"]=0.0
|
| 184 |
+
|
| 185 |
+
self._filter_step_ssteps_freq=None
|
| 186 |
+
|
| 187 |
+
self._env_opts.update(env_opts)
|
| 188 |
+
|
| 189 |
+
self.step_counter = 0 # global step counter
|
| 190 |
+
self._n_init_steps = n_init_step # n steps to be performed before applying solutions from control clusters
|
| 191 |
+
self._srdf_dump_paths = robot_srdf_paths
|
| 192 |
+
self._homers = {}
|
| 193 |
+
self._homing = None
|
| 194 |
+
self._jnt_imp_cntrl_shared_data = {}
|
| 195 |
+
self._jnt_imp_controllers = {}
|
| 196 |
+
self._jnt_imp_config_paths = {}
|
| 197 |
+
|
| 198 |
+
# control cluster data
|
| 199 |
+
self.cluster_sim_step_counters = {}
|
| 200 |
+
self.cluster_servers = {}
|
| 201 |
+
self._trigger_sol = {}
|
| 202 |
+
self._wait_sol = {}
|
| 203 |
+
self._cluster_dt = {}
|
| 204 |
+
self._robot_urdf_paths={}
|
| 205 |
+
self._robot_srdf_paths={}
|
| 206 |
+
self._contact_names={}
|
| 207 |
+
self._num_contacts={}
|
| 208 |
+
|
| 209 |
+
for i in range(len(self._robot_names)):
|
| 210 |
+
robot_name = self._robot_names[i]
|
| 211 |
+
self._cluster_dt[robot_name]=cluster_dt[i]
|
| 212 |
+
self._robot_urdf_paths[robot_name]=robot_urdf_paths[i]
|
| 213 |
+
self._robot_srdf_paths[robot_name]=robot_srdf_paths[i]
|
| 214 |
+
self._contact_names[robot_name]=None
|
| 215 |
+
self._num_contacts[robot_name]=n_contacts[i]
|
| 216 |
+
self._jnt_imp_config_paths[robot_name]=jnt_imp_config_paths[i]
|
| 217 |
+
# db data
|
| 218 |
+
self.debug_data = {}
|
| 219 |
+
self.debug_data["time_to_step_world"] = np.nan
|
| 220 |
+
self.debug_data["time_to_get_states_from_env"] = np.nan
|
| 221 |
+
self.debug_data["cluster_sol_time"] = {}
|
| 222 |
+
self.debug_data["cluster_state_update_dt"] = {}
|
| 223 |
+
self.debug_data["sim_time"] = {}
|
| 224 |
+
self.debug_data["cluster_time"] = {}
|
| 225 |
+
|
| 226 |
+
self._env_timer = time.perf_counter()
|
| 227 |
+
|
| 228 |
+
# remote sim stepping options
|
| 229 |
+
self._timeout = timeout_ms # timeout for remote stepping
|
| 230 |
+
self._use_remote_stepping = use_remote_stepping
|
| 231 |
+
# should use remote stepping
|
| 232 |
+
self._remote_steppers = {}
|
| 233 |
+
self._remote_resetters = {}
|
| 234 |
+
self._remote_reset_requests = {}
|
| 235 |
+
self._is_first_trigger = {}
|
| 236 |
+
|
| 237 |
+
self._closed = False
|
| 238 |
+
|
| 239 |
+
self._this_child_path=os.path.abspath(inspect.getfile(self.__class__))
|
| 240 |
+
self._descr_dump_path=dump_basepath+"/"+f"{self.__class__.__name__}"
|
| 241 |
+
self._urdf_dump_paths = {}
|
| 242 |
+
self._srdf_dump_paths = {}
|
| 243 |
+
self.xrdf_cmd_vals = [] # by default empty, needs to be overriden by
|
| 244 |
+
# child class
|
| 245 |
+
self._world_iface_files_server=None
|
| 246 |
+
|
| 247 |
+
self._override_low_lev_controller=override_low_lev_controller
|
| 248 |
+
|
| 249 |
+
self._root_p = {}
|
| 250 |
+
self._root_q = {}
|
| 251 |
+
self._jnts_q = {}
|
| 252 |
+
self._root_p_prev = {} # used for num differentiation
|
| 253 |
+
self._root_q_prev = {} # used for num differentiation
|
| 254 |
+
self._jnts_q_prev = {} # used for num differentiation
|
| 255 |
+
self._root_v_prev = {} # used for num differentiation
|
| 256 |
+
self._root_omega_prev = {} # used for num differentiation
|
| 257 |
+
self._root_p_default = {}
|
| 258 |
+
self._root_q_default = {}
|
| 259 |
+
self._jnts_q_default = {}
|
| 260 |
+
|
| 261 |
+
self._gravity_normalized = {}
|
| 262 |
+
self._gravity_normalized_base_loc = {}
|
| 263 |
+
|
| 264 |
+
self._root_v = {}
|
| 265 |
+
self._root_v_base_loc = {}
|
| 266 |
+
self._root_v_default = {}
|
| 267 |
+
self._root_omega = {}
|
| 268 |
+
self._root_omega_base_loc = {}
|
| 269 |
+
self._root_omega_default = {}
|
| 270 |
+
self._root_a = {}
|
| 271 |
+
self._root_a_base_loc = {}
|
| 272 |
+
self._root_alpha = {}
|
| 273 |
+
self._root_alpha_base_loc = {}
|
| 274 |
+
|
| 275 |
+
self._jnts_v = {}
|
| 276 |
+
self._jnt_vel_filter = {}
|
| 277 |
+
self._jnts_v_default = {}
|
| 278 |
+
self._jnts_eff = {}
|
| 279 |
+
self._jnts_eff_default = {}
|
| 280 |
+
|
| 281 |
+
self._root_pos_offsets = {}
|
| 282 |
+
self._root_q_offsets = {}
|
| 283 |
+
|
| 284 |
+
self._parse_env_opts()
|
| 285 |
+
|
| 286 |
+
self._enable_height_shared = self._env_opts["enable_height_sensor"]
|
| 287 |
+
self._height_sensor_resolution = self._env_opts["height_sensor_resolution"]
|
| 288 |
+
self._height_sensor_pixels = self._env_opts["height_sensor_pixels"]
|
| 289 |
+
|
| 290 |
+
self._pre_setup() # child's method
|
| 291 |
+
|
| 292 |
+
self._init_world() # after this point all info from sim or robot is
|
| 293 |
+
# available
|
| 294 |
+
|
| 295 |
+
self._publish_world_interface_files()
|
| 296 |
+
|
| 297 |
+
self._setup()
|
| 298 |
+
|
| 299 |
+
self._exit_request=False
|
| 300 |
+
signal.signal(signal.SIGINT, self.signal_handler)
|
| 301 |
+
|
| 302 |
+
def signal_handler(self, sig, frame):
|
| 303 |
+
Journal.log(self.__class__.__name__,
|
| 304 |
+
"signal_handler",
|
| 305 |
+
"received SIGINT -> cleaning up",
|
| 306 |
+
LogType.WARN)
|
| 307 |
+
self._exit_request=True
|
| 308 |
+
|
| 309 |
+
def __del__(self):
|
| 310 |
+
self.close()
|
| 311 |
+
|
| 312 |
+
def is_closed(self):
|
| 313 |
+
return self._closed
|
| 314 |
+
|
| 315 |
+
def close(self) -> None:
|
| 316 |
+
if not self._closed:
|
| 317 |
+
for i in range(len(self._robot_names)):
|
| 318 |
+
if self._robot_names[i] in self.cluster_servers:
|
| 319 |
+
self.cluster_servers[self._robot_names[i]].close()
|
| 320 |
+
if self._use_remote_stepping[i]: # remote signaling
|
| 321 |
+
if self._robot_names[i] in self._remote_reset_requests:
|
| 322 |
+
self._remote_reset_requests[self._robot_names[i]].close()
|
| 323 |
+
self._remote_resetters[self._robot_names[i]].close()
|
| 324 |
+
self._remote_steppers[self._robot_names[i]].close()
|
| 325 |
+
if self._robot_names[i] in self._jnt_imp_cntrl_shared_data:
|
| 326 |
+
jnt_imp_shared_data=self._jnt_imp_cntrl_shared_data[self._robot_names[i]]
|
| 327 |
+
if jnt_imp_shared_data is not None:
|
| 328 |
+
jnt_imp_shared_data.close()
|
| 329 |
+
if self._remote_exit_flag is not None:
|
| 330 |
+
self._remote_exit_flag.close()
|
| 331 |
+
if self._world_iface_files_server is not None:
|
| 332 |
+
self._world_iface_files_server.close()
|
| 333 |
+
self._close()
|
| 334 |
+
self._closed=True
|
| 335 |
+
|
| 336 |
+
def _collect_world_interface_files(self):
|
| 337 |
+
files = [self._this_child_path]
|
| 338 |
+
# prefer generated URDF/SRDF if available, fallback to provided xacros
|
| 339 |
+
if len(self._urdf_dump_paths) > 0:
|
| 340 |
+
files.extend(list(self._urdf_dump_paths.values()))
|
| 341 |
+
else:
|
| 342 |
+
files.extend(list(self._robot_urdf_paths.values()))
|
| 343 |
+
if len(self._srdf_dump_paths) > 0:
|
| 344 |
+
files.extend(list(self._srdf_dump_paths.values()))
|
| 345 |
+
else:
|
| 346 |
+
files.extend(list(self._robot_srdf_paths.values()))
|
| 347 |
+
files.extend(list(self._jnt_imp_config_paths.values()))
|
| 348 |
+
# remove duplicates while preserving order
|
| 349 |
+
unique_files=[]
|
| 350 |
+
for f in files:
|
| 351 |
+
if f not in unique_files:
|
| 352 |
+
unique_files.append(f)
|
| 353 |
+
return unique_files
|
| 354 |
+
|
| 355 |
+
def _publish_world_interface_files(self):
|
| 356 |
+
|
| 357 |
+
if not any(self._use_remote_stepping):
|
| 358 |
+
return
|
| 359 |
+
self._world_iface_files_server=StringTensorServer(length=1,
|
| 360 |
+
basename="SharedWorldInterfaceFilesDropDir",
|
| 361 |
+
name_space=self._robot_names[0],
|
| 362 |
+
verbose=self._verbose,
|
| 363 |
+
vlevel=self._vlevel,
|
| 364 |
+
force_reconnection=True)
|
| 365 |
+
self._world_iface_files_server.run()
|
| 366 |
+
combined_paths=", ".join(self._collect_world_interface_files())
|
| 367 |
+
while not self._world_iface_files_server.write_vec([combined_paths], 0):
|
| 368 |
+
Journal.log(self.__class__.__name__,
|
| 369 |
+
"_publish_world_interface_files",
|
| 370 |
+
f"Failed to pub world interface files. Retrying...",
|
| 371 |
+
LogType.WARN)
|
| 372 |
+
time.sleep(0.1)
|
| 373 |
+
Journal.log(self.__class__.__name__,
|
| 374 |
+
"_publish_world_interface_files",
|
| 375 |
+
f"World interface files advertised: {combined_paths}",
|
| 376 |
+
LogType.STAT)
|
| 377 |
+
|
| 378 |
+
def _setup(self) -> None:
|
| 379 |
+
|
| 380 |
+
for i in range(len(self._robot_names)):
|
| 381 |
+
robot_name = self._robot_names[i]
|
| 382 |
+
|
| 383 |
+
# normalized gravity vector
|
| 384 |
+
self._gravity_normalized[robot_name]=torch.full_like(self._root_v[robot_name], fill_value=0.0)
|
| 385 |
+
self._gravity_normalized[robot_name][:, 2]=-1.0
|
| 386 |
+
self._gravity_normalized_base_loc[robot_name]=self._gravity_normalized[robot_name].detach().clone()
|
| 387 |
+
|
| 388 |
+
self.cluster_sim_step_counters[robot_name]=0
|
| 389 |
+
self._is_first_trigger[robot_name] = True
|
| 390 |
+
if not isinstance(self._cluster_dt[robot_name], (float)):
|
| 391 |
+
exception = f"cluster_dt[{i}] should be a float!"
|
| 392 |
+
Journal.log(self.__class__.__name__,
|
| 393 |
+
"_setup",
|
| 394 |
+
exception,
|
| 395 |
+
LogType.EXCEP,
|
| 396 |
+
throw_when_excep = True)
|
| 397 |
+
self._cluster_dt[robot_name] = self._cluster_dt[robot_name]
|
| 398 |
+
self._trigger_sol[robot_name] = True # allow first trigger
|
| 399 |
+
self._wait_sol[robot_name] = False
|
| 400 |
+
|
| 401 |
+
# initialize a lrhc cluster server for communicating with rhc controllers
|
| 402 |
+
self.cluster_servers[robot_name] = AugMpcClusterServer(cluster_size=self._num_envs,
|
| 403 |
+
cluster_dt=self._cluster_dt[robot_name],
|
| 404 |
+
control_dt=self.physics_dt(),
|
| 405 |
+
jnt_names=self._robot_jnt_names(robot_name=robot_name),
|
| 406 |
+
n_contacts=self._n_contacts(robot_name=robot_name),
|
| 407 |
+
contact_linknames=self._contact_names[robot_name],
|
| 408 |
+
verbose=self._verbose,
|
| 409 |
+
vlevel=self._vlevel,
|
| 410 |
+
debug=self._debug,
|
| 411 |
+
robot_name=robot_name,
|
| 412 |
+
use_gpu=self._use_gpu,
|
| 413 |
+
force_reconnection=self._force_reconnection,
|
| 414 |
+
timeout_ms=self._timeout,
|
| 415 |
+
enable_height_sensor=self._enable_height_shared,
|
| 416 |
+
height_grid_size=self._height_sensor_pixels,
|
| 417 |
+
height_grid_resolution=self._height_sensor_resolution)
|
| 418 |
+
self.cluster_servers[robot_name].run()
|
| 419 |
+
self.debug_data["cluster_sol_time"][robot_name] = np.nan
|
| 420 |
+
self.debug_data["cluster_state_update_dt"][robot_name] = np.nan
|
| 421 |
+
self.debug_data["sim_time"][robot_name] = np.nan
|
| 422 |
+
# remote sim stepping
|
| 423 |
+
if self._use_remote_stepping[i]:
|
| 424 |
+
self._remote_steppers[robot_name] = RemoteStepperClnt(namespace=robot_name,
|
| 425 |
+
verbose=self._debug,
|
| 426 |
+
vlevel=self._vlevel)
|
| 427 |
+
self._remote_resetters[robot_name] = RemoteResetClnt(namespace=robot_name,
|
| 428 |
+
verbose=self._debug,
|
| 429 |
+
vlevel=self._vlevel)
|
| 430 |
+
self._remote_reset_requests[robot_name] = RemoteResetRequest(namespace=robot_name,
|
| 431 |
+
n_env=self._num_envs,
|
| 432 |
+
is_server=True,
|
| 433 |
+
verbose=self._debug,
|
| 434 |
+
vlevel=self._vlevel,
|
| 435 |
+
force_reconnection=self._force_reconnection,
|
| 436 |
+
safe=False)
|
| 437 |
+
self._remote_steppers[robot_name].run()
|
| 438 |
+
self._remote_resetters[robot_name].run()
|
| 439 |
+
self._remote_reset_requests[robot_name].run()
|
| 440 |
+
else:
|
| 441 |
+
self._remote_steppers[robot_name] = None
|
| 442 |
+
self._remote_reset_requests[robot_name] = None
|
| 443 |
+
self._remote_resetters[robot_name] = None
|
| 444 |
+
|
| 445 |
+
self._homers[robot_name] = RobotHomer(srdf_path=self._srdf_dump_paths[robot_name],
|
| 446 |
+
jnt_names=self._robot_jnt_names(robot_name=robot_name),
|
| 447 |
+
filter=True)
|
| 448 |
+
robot_homing=torch.from_numpy(self._homers[robot_name].get_homing().reshape(1,-1))
|
| 449 |
+
if "cuda" in self._device:
|
| 450 |
+
robot_homing=robot_homing.cuda()
|
| 451 |
+
self._homing=robot_homing.repeat(self._num_envs, 1)
|
| 452 |
+
|
| 453 |
+
self._jnts_q_default[robot_name] = self._homing
|
| 454 |
+
self._set_jnts_to_homing(robot_name=robot_name)
|
| 455 |
+
self._set_root_to_defconfig(robot_name=robot_name)
|
| 456 |
+
self._reset_sim()
|
| 457 |
+
|
| 458 |
+
self._init_safe_cluster_actions(robot_name=robot_name)
|
| 459 |
+
|
| 460 |
+
Journal.log(self.__class__.__name__,
|
| 461 |
+
"_setup",
|
| 462 |
+
f"Will use joint impedance config at {self._jnt_imp_config_paths[robot_name]} for {robot_name}",
|
| 463 |
+
LogType.STAT)
|
| 464 |
+
|
| 465 |
+
self._jnt_imp_controllers[robot_name] = self._generate_jnt_imp_control(robot_name=robot_name)
|
| 466 |
+
self._jnt_imp_cntrl_shared_data[robot_name] = JntImpCntrlData(is_server=True,
|
| 467 |
+
n_envs=self._num_envs,
|
| 468 |
+
n_jnts=len(self._robot_jnt_names(robot_name=robot_name)),
|
| 469 |
+
jnt_names=self._robot_jnt_names(robot_name=robot_name),
|
| 470 |
+
namespace=robot_name,
|
| 471 |
+
verbose=self._verbose,
|
| 472 |
+
force_reconnection=self._force_reconnection,
|
| 473 |
+
vlevel=self._vlevel,
|
| 474 |
+
use_gpu=self._use_gpu,
|
| 475 |
+
safe=False)
|
| 476 |
+
self._jnt_imp_cntrl_shared_data[robot_name].run()
|
| 477 |
+
|
| 478 |
+
self._jnt_vel_filter[robot_name]=None
|
| 479 |
+
if self._env_opts["filter_jnt_vel"]:
|
| 480 |
+
self._jnt_vel_filter[robot_name]=FirstOrderFilter(dt=1.0/self._env_opts["filter_sampling_rate"],
|
| 481 |
+
filter_BW=self._env_opts["filter_cutoff_freq"],
|
| 482 |
+
rows=self._num_envs,
|
| 483 |
+
cols=len(self._robot_jnt_names(robot_name=robot_name)),
|
| 484 |
+
device=self._device,
|
| 485 |
+
dtype=self._dtype)
|
| 486 |
+
|
| 487 |
+
physics_rate=1.0/self.physics_dt()
|
| 488 |
+
self._filter_step_ssteps_freq=int(physics_rate/self._env_opts["filter_sampling_rate"])
|
| 489 |
+
if self._filter_step_ssteps_freq <=0:
|
| 490 |
+
Journal.log(self.__class__.__name__,
|
| 491 |
+
"_setup",
|
| 492 |
+
f"The filter_sampling_rate should be smaller that the physics rate ({physics_rate} Hz)",
|
| 493 |
+
LogType.EXCEP,
|
| 494 |
+
throw_when_excep=True)
|
| 495 |
+
|
| 496 |
+
for n in range(self._n_init_steps): # run some initialization steps
|
| 497 |
+
self._step_world()
|
| 498 |
+
if hasattr(self, "_zero_angular_velocities"):
|
| 499 |
+
self._zero_angular_velocities(robot_name=robot_name, env_indxs=None)
|
| 500 |
+
self._read_jnts_state_from_robot(robot_name=robot_name,
|
| 501 |
+
env_indxs=None)
|
| 502 |
+
self._read_root_state_from_robot(robot_name=robot_name,
|
| 503 |
+
env_indxs=None)
|
| 504 |
+
# allow child to perform additional warmup validations (e.g., terrain/tilt)
|
| 505 |
+
# retry_done = False
|
| 506 |
+
if hasattr(self, "_post_warmup_validation"):
|
| 507 |
+
failing = self._post_warmup_validation(robot_name=robot_name)
|
| 508 |
+
if failing is not None and failing.numel() > 0:
|
| 509 |
+
# retry: reset only failing envs, rerun warmup, revalidate once
|
| 510 |
+
failing = failing.to(self._device)
|
| 511 |
+
Journal.log(self.__class__.__name__,
|
| 512 |
+
"_setup",
|
| 513 |
+
f"Warmup validation failed for {robot_name}, envs indexes {failing.tolist()}",
|
| 514 |
+
LogType.EXCEP,
|
| 515 |
+
throw_when_excep=True)
|
| 516 |
+
else:
|
| 517 |
+
Journal.log(self.__class__.__name__,
|
| 518 |
+
"_setup",
|
| 519 |
+
f"Warmup validation passed for {robot_name}",
|
| 520 |
+
LogType.INFO)
|
| 521 |
+
|
| 522 |
+
# write some inits for all robots
|
| 523 |
+
self._update_root_offsets(robot_name)
|
| 524 |
+
self._synch_default_root_states(robot_name=robot_name)
|
| 525 |
+
epsi=0.03 # adding a bit of height to avoid initial penetration
|
| 526 |
+
self._root_p_default[robot_name][:, 2]=self._root_p_default[robot_name][:, 2]+epsi
|
| 527 |
+
|
| 528 |
+
self._reset(env_indxs=None,
|
| 529 |
+
robot_name=robot_name,
|
| 530 |
+
reset_cluster=True,
|
| 531 |
+
reset_cluster_counter=False,
|
| 532 |
+
randomize=True)
|
| 533 |
+
|
| 534 |
+
control_cluster=self.cluster_servers[robot_name]
|
| 535 |
+
self._set_state_to_cluster(robot_name=robot_name)
|
| 536 |
+
control_cluster.write_robot_state()
|
| 537 |
+
control_cluster.pre_trigger()
|
| 538 |
+
to_be_activated=control_cluster.get_inactive_controllers()
|
| 539 |
+
if to_be_activated is not None:
|
| 540 |
+
control_cluster.activate_controllers(
|
| 541 |
+
idxs=to_be_activated)
|
| 542 |
+
|
| 543 |
+
if self._use_remote_stepping[i]:
|
| 544 |
+
self._wait_for_remote_step_req(robot_name=robot_name)
|
| 545 |
+
|
| 546 |
+
self._set_startup_jnt_imp_gains(robot_name=robot_name) # set gains to
|
| 547 |
+
# startup config (usually lower)
|
| 548 |
+
control_cluster.trigger_solution()
|
| 549 |
+
|
| 550 |
+
if self._env_opts["add_remote_exit_flag"]:
|
| 551 |
+
self._remote_exit_flag=SharedTWrapper(namespace = self._robot_names[0],# use first robot as name
|
| 552 |
+
basename = "IbridoRemoteEnvExitFlag",
|
| 553 |
+
is_server = True,
|
| 554 |
+
n_rows = 1,
|
| 555 |
+
n_cols = 1,
|
| 556 |
+
verbose = True,
|
| 557 |
+
vlevel = self._vlevel,
|
| 558 |
+
safe = False,
|
| 559 |
+
dtype=dtype.Bool,
|
| 560 |
+
force_reconnection=True,
|
| 561 |
+
fill_value = False)
|
| 562 |
+
self._remote_exit_flag.run()
|
| 563 |
+
|
| 564 |
+
self._setup_done=True
|
| 565 |
+
|
| 566 |
+
def step(self) -> bool:
|
| 567 |
+
|
| 568 |
+
success=False
|
| 569 |
+
|
| 570 |
+
if self._remote_exit_flag is not None:
|
| 571 |
+
# check for exit request
|
| 572 |
+
self._remote_exit_flag.synch_all(read=True, retry = False)
|
| 573 |
+
self._exit_request=bool(self._remote_exit_flag.get_numpy_mirror()[0, 0].item())
|
| 574 |
+
|
| 575 |
+
if self._exit_request:
|
| 576 |
+
self.close()
|
| 577 |
+
|
| 578 |
+
if self.is_running() and (not self.is_closed()):
|
| 579 |
+
if self._debug:
|
| 580 |
+
self._pre_step_db()
|
| 581 |
+
self._env_timer=time.perf_counter()
|
| 582 |
+
self._step_world()
|
| 583 |
+
self.debug_data["time_to_step_world"] = \
|
| 584 |
+
time.perf_counter() - self._env_timer
|
| 585 |
+
self._post_world_step_db()
|
| 586 |
+
success=True
|
| 587 |
+
else:
|
| 588 |
+
self._pre_step()
|
| 589 |
+
self._step_world()
|
| 590 |
+
self._post_world_step()
|
| 591 |
+
success=True
|
| 592 |
+
|
| 593 |
+
return success
|
| 594 |
+
|
| 595 |
+
def render(self, mode:str="human") -> None:
|
| 596 |
+
self._render_sim(mode)
|
| 597 |
+
|
| 598 |
+
def reset(self,
|
| 599 |
+
env_indxs: torch.Tensor = None,
|
| 600 |
+
reset_cluster: bool = False,
|
| 601 |
+
reset_cluster_counter = False,
|
| 602 |
+
randomize: bool = False,
|
| 603 |
+
reset_sim: bool = False) -> None:
|
| 604 |
+
|
| 605 |
+
for i in range(len(self._robot_names)):
|
| 606 |
+
robot_name=self._robot_names[i]
|
| 607 |
+
self._reset(robot_name=robot_name,
|
| 608 |
+
env_indxs=env_indxs,
|
| 609 |
+
randomize=randomize,
|
| 610 |
+
reset_cluster=reset_cluster,
|
| 611 |
+
reset_cluster_counter=reset_cluster_counter)
|
| 612 |
+
self._set_startup_jnt_imp_gains(robot_name=robot_name,
|
| 613 |
+
env_indxs=env_indxs)
|
| 614 |
+
|
| 615 |
+
if reset_sim:
|
| 616 |
+
self._reset_sim()
|
| 617 |
+
|
| 618 |
+
def _reset_cluster(self,
|
| 619 |
+
robot_name: str,
|
| 620 |
+
env_indxs: torch.Tensor = None,
|
| 621 |
+
reset_cluster_counter: bool = False):
|
| 622 |
+
|
| 623 |
+
control_cluster = self.cluster_servers[robot_name]
|
| 624 |
+
|
| 625 |
+
control_cluster.reset_controllers(idxs=env_indxs)
|
| 626 |
+
|
| 627 |
+
self._set_state_to_cluster(robot_name=robot_name,
|
| 628 |
+
env_indxs=env_indxs)
|
| 629 |
+
control_cluster.write_robot_state() # writes to shared memory
|
| 630 |
+
|
| 631 |
+
if reset_cluster_counter:
|
| 632 |
+
self.cluster_sim_step_counters[robot_name] = 0
|
| 633 |
+
|
| 634 |
+
def _step_jnt_vel_filter(self,
|
| 635 |
+
robot_name: str,
|
| 636 |
+
env_indxs: torch.Tensor = None):
|
| 637 |
+
|
| 638 |
+
self._jnt_vel_filter[robot_name].update(refk=self.jnts_v(robot_name=robot_name, env_idxs=env_indxs),
|
| 639 |
+
idxs=env_indxs)
|
| 640 |
+
|
| 641 |
+
def _set_state_to_cluster(self,
|
| 642 |
+
robot_name: str,
|
| 643 |
+
env_indxs: torch.Tensor = None,
|
| 644 |
+
base_loc: bool = True):
|
| 645 |
+
|
| 646 |
+
if self._debug:
|
| 647 |
+
if not isinstance(env_indxs, (torch.Tensor, type(None))):
|
| 648 |
+
msg = "Provided env_indxs should be a torch tensor of indexes!"
|
| 649 |
+
raise Exception(f"[{self.__class__.__name__}]" + f"[{self.journal.exception}]: " + msg)
|
| 650 |
+
|
| 651 |
+
control_cluster = self.cluster_servers[robot_name]
|
| 652 |
+
# floating base
|
| 653 |
+
rhc_state = control_cluster.get_state()
|
| 654 |
+
# configuration
|
| 655 |
+
rhc_state.root_state.set(data=self.root_p_rel(robot_name=robot_name, env_idxs=env_indxs),
|
| 656 |
+
data_type="p", robot_idxs = env_indxs, gpu=self._use_gpu)
|
| 657 |
+
rhc_state.root_state.set(data=self.root_q(robot_name=robot_name, env_idxs=env_indxs),
|
| 658 |
+
data_type="q", robot_idxs = env_indxs, gpu=self._use_gpu)
|
| 659 |
+
|
| 660 |
+
# twist
|
| 661 |
+
rhc_state.root_state.set(data=self.root_v(robot_name=robot_name, env_idxs=env_indxs,base_loc=base_loc),
|
| 662 |
+
data_type="v", robot_idxs = env_indxs, gpu=self._use_gpu)
|
| 663 |
+
rhc_state.root_state.set(data=self.root_omega(robot_name=robot_name, env_idxs=env_indxs,base_loc=base_loc),
|
| 664 |
+
data_type="omega", robot_idxs = env_indxs, gpu=self._use_gpu)
|
| 665 |
+
|
| 666 |
+
# angular accc.
|
| 667 |
+
rhc_state.root_state.set(data=self.root_a(robot_name=robot_name, env_idxs=env_indxs,base_loc=base_loc),
|
| 668 |
+
data_type="a", robot_idxs = env_indxs, gpu=self._use_gpu)
|
| 669 |
+
rhc_state.root_state.set(data=self.root_alpha(robot_name=robot_name, env_idxs=env_indxs,base_loc=base_loc),
|
| 670 |
+
data_type="alpha", robot_idxs = env_indxs, gpu=self._use_gpu)
|
| 671 |
+
|
| 672 |
+
# gravity vec
|
| 673 |
+
rhc_state.root_state.set(data=self.gravity(robot_name=robot_name, env_idxs=env_indxs,base_loc=base_loc),
|
| 674 |
+
data_type="gn", robot_idxs = env_indxs, gpu=self._use_gpu)
|
| 675 |
+
|
| 676 |
+
# joints
|
| 677 |
+
rhc_state.jnts_state.set(data=self.jnts_q(robot_name=robot_name, env_idxs=env_indxs),
|
| 678 |
+
data_type="q", robot_idxs = env_indxs, gpu=self._use_gpu)
|
| 679 |
+
|
| 680 |
+
v_jnts=self.jnts_v(robot_name=robot_name, env_idxs=env_indxs)
|
| 681 |
+
if self._jnt_vel_filter[robot_name] is not None: # apply filtering
|
| 682 |
+
v_jnts=self._jnt_vel_filter[robot_name].get(idxs=env_indxs)
|
| 683 |
+
rhc_state.jnts_state.set(data=v_jnts,
|
| 684 |
+
data_type="v", robot_idxs = env_indxs, gpu=self._use_gpu)
|
| 685 |
+
rhc_state.jnts_state.set(data=self.jnts_eff(robot_name=robot_name, env_idxs=env_indxs),
|
| 686 |
+
data_type="eff", robot_idxs = env_indxs, gpu=self._use_gpu)
|
| 687 |
+
|
| 688 |
+
# height map
|
| 689 |
+
if self._enable_height_shared:
|
| 690 |
+
hdata = self._height_imgs[robot_name]
|
| 691 |
+
if env_indxs is not None:
|
| 692 |
+
hdata = hdata[env_indxs]
|
| 693 |
+
flat = hdata.reshape(hdata.shape[0], -1)
|
| 694 |
+
rhc_state.height_sensor.set(data=flat, data_type=None, robot_idxs=env_indxs, gpu=self._use_gpu)
|
| 695 |
+
|
| 696 |
+
# Updating contact state for selected contact links
|
| 697 |
+
self._update_contact_state(robot_name=robot_name, env_indxs=env_indxs)
|
| 698 |
+
|
| 699 |
+
def _update_contact_state(self,
|
| 700 |
+
robot_name: str,
|
| 701 |
+
env_indxs: torch.Tensor = None):
|
| 702 |
+
for i in range(0, self.cluster_servers[robot_name].n_contact_sensors()):
|
| 703 |
+
contact_link = self.cluster_servers[robot_name].contact_linknames()[i]
|
| 704 |
+
f_contact = self._get_contact_f(robot_name=robot_name,
|
| 705 |
+
contact_link=contact_link,
|
| 706 |
+
env_indxs=env_indxs)
|
| 707 |
+
if f_contact is not None:
|
| 708 |
+
self.cluster_servers[robot_name].get_state().contact_wrenches.set(data=f_contact, data_type="f",
|
| 709 |
+
contact_name=contact_link,
|
| 710 |
+
robot_idxs = env_indxs,
|
| 711 |
+
gpu=self._use_gpu)
|
| 712 |
+
|
| 713 |
+
def _init_safe_cluster_actions(self,
|
| 714 |
+
robot_name: str):
|
| 715 |
+
|
| 716 |
+
# this does not actually write on shared memory,
|
| 717 |
+
# but it's enough to get safe actions for the simulator before the
|
| 718 |
+
# cluster starts to receive data from the controllers
|
| 719 |
+
control_cluster = self.cluster_servers[robot_name]
|
| 720 |
+
rhc_cmds = control_cluster.get_actions()
|
| 721 |
+
n_jnts = rhc_cmds.n_jnts()
|
| 722 |
+
|
| 723 |
+
null_action = torch.zeros((self._num_envs, n_jnts),
|
| 724 |
+
dtype=self._dtype,
|
| 725 |
+
device=self._device)
|
| 726 |
+
rhc_cmds.jnts_state.set(data=self._homing, data_type="q", gpu=self._use_gpu)
|
| 727 |
+
rhc_cmds.jnts_state.set(data=null_action, data_type="v", gpu=self._use_gpu)
|
| 728 |
+
rhc_cmds.jnts_state.set(data=null_action, data_type="eff", gpu=self._use_gpu)
|
| 729 |
+
|
| 730 |
+
def _pre_step_db(self) -> None:
|
| 731 |
+
|
| 732 |
+
# cluster step logic here
|
| 733 |
+
for i in range(len(self._robot_names)):
|
| 734 |
+
robot_name = self._robot_names[i]
|
| 735 |
+
|
| 736 |
+
if self._override_low_lev_controller:
|
| 737 |
+
# if overriding low-lev jnt imp. this has to run at the highest
|
| 738 |
+
# freq possible
|
| 739 |
+
start=time.perf_counter()
|
| 740 |
+
self._read_jnts_state_from_robot(robot_name=robot_name)
|
| 741 |
+
self.debug_data["time_to_get_states_from_env"]= time.perf_counter()-start
|
| 742 |
+
|
| 743 |
+
self._write_state_to_jnt_imp(robot_name=robot_name)
|
| 744 |
+
self._apply_cmds_to_jnt_imp_control(robot_name=robot_name)
|
| 745 |
+
|
| 746 |
+
if self._jnt_vel_filter[robot_name] is not None and \
|
| 747 |
+
(self.cluster_sim_step_counters[robot_name]+1) % self._filter_step_ssteps_freq == 0:
|
| 748 |
+
# filter joint vel at a fixed frequency wrt sim steps
|
| 749 |
+
if not self._override_low_lev_controller:
|
| 750 |
+
# we need a fresh sensor reading
|
| 751 |
+
self._read_jnts_state_from_robot(robot_name=robot_name)
|
| 752 |
+
self._step_jnt_vel_filter(robot_name=robot_name, env_indxs=None)
|
| 753 |
+
|
| 754 |
+
control_cluster = self.cluster_servers[robot_name]
|
| 755 |
+
if control_cluster.is_cluster_instant(self.cluster_sim_step_counters[robot_name]):
|
| 756 |
+
control_cluster.wait_for_solution() # this is blocking
|
| 757 |
+
failed = control_cluster.get_failed_controllers(gpu=self._use_gpu)
|
| 758 |
+
self._set_cluster_actions(robot_name=robot_name) # write last cmds to low level control
|
| 759 |
+
if not self._override_low_lev_controller:
|
| 760 |
+
self._apply_cmds_to_jnt_imp_control(robot_name=robot_name) # apply to robot
|
| 761 |
+
# we can update the jnt state just at the rate at which the cluster needs it
|
| 762 |
+
start=time.perf_counter()
|
| 763 |
+
self._read_jnts_state_from_robot(robot_name=robot_name, env_indxs=None)
|
| 764 |
+
else:
|
| 765 |
+
# read state necessary for cluster
|
| 766 |
+
start=time.perf_counter()
|
| 767 |
+
self._read_root_state_from_robot(robot_name=robot_name,
|
| 768 |
+
env_indxs=None)
|
| 769 |
+
self.debug_data["time_to_get_states_from_env"]= time.perf_counter()-start
|
| 770 |
+
start=time.perf_counter()
|
| 771 |
+
self._set_state_to_cluster(robot_name=robot_name,
|
| 772 |
+
env_indxs=None)
|
| 773 |
+
control_cluster.write_robot_state()
|
| 774 |
+
self.debug_data["cluster_state_update_dt"][robot_name] = time.perf_counter()-start
|
| 775 |
+
|
| 776 |
+
self._update_jnt_imp_cntrl_shared_data() # only if debug_mode_jnt_imp is enabled
|
| 777 |
+
|
| 778 |
+
if self._use_remote_stepping[i]:
|
| 779 |
+
self._remote_steppers[robot_name].ack() # signal cluster stepping is finished
|
| 780 |
+
if failed is not None and self._env_opts["deact_when_failure"]: # deactivate robot completely
|
| 781 |
+
self._deactivate(env_indxs=failed,
|
| 782 |
+
robot_name=robot_name)
|
| 783 |
+
|
| 784 |
+
self._process_remote_reset_req(robot_name=robot_name) # wait for remote reset request (blocking)
|
| 785 |
+
self._wait_for_remote_step_req(robot_name=robot_name)
|
| 786 |
+
else:
|
| 787 |
+
if failed is not None:
|
| 788 |
+
self._reset(env_indxs=failed,
|
| 789 |
+
robot_name=robot_name,
|
| 790 |
+
reset_cluster=True,
|
| 791 |
+
reset_cluster_counter=False,
|
| 792 |
+
randomize=True)
|
| 793 |
+
self._set_startup_jnt_imp_gains(robot_name=robot_name,
|
| 794 |
+
env_indxs=failed)
|
| 795 |
+
|
| 796 |
+
control_cluster.activate_controllers(idxs=control_cluster.get_inactive_controllers())
|
| 797 |
+
|
| 798 |
+
control_cluster.pre_trigger() # performs pre-trigger steps, like retrieving
|
| 799 |
+
# values of some rhc flags on shared memory
|
| 800 |
+
control_cluster.trigger_solution() # trigger only active controllers
|
| 801 |
+
|
| 802 |
+
def _pre_step(self) -> None:
|
| 803 |
+
|
| 804 |
+
# cluster step logic here
|
| 805 |
+
for i in range(len(self._robot_names)):
|
| 806 |
+
robot_name = self._robot_names[i]
|
| 807 |
+
if self._override_low_lev_controller:
|
| 808 |
+
# if overriding low-lev jnt imp. this has to run at the highest
|
| 809 |
+
# freq possible
|
| 810 |
+
self._read_jnts_state_from_robot(robot_name=robot_name)
|
| 811 |
+
self._write_state_to_jnt_imp(robot_name=robot_name)
|
| 812 |
+
self._apply_cmds_to_jnt_imp_control(robot_name=robot_name)
|
| 813 |
+
|
| 814 |
+
if self._jnt_vel_filter[robot_name] is not None and \
|
| 815 |
+
(self.cluster_sim_step_counters[robot_name]+1) % self._filter_step_ssteps_freq == 0:
|
| 816 |
+
# filter joint vel at a fixed frequency wrt sim steps
|
| 817 |
+
if not self._override_low_lev_controller:
|
| 818 |
+
# we need a fresh sensor reading
|
| 819 |
+
self._read_jnts_state_from_robot(robot_name=robot_name)
|
| 820 |
+
self._step_jnt_vel_filter(robot_name=robot_name, env_indxs=None)
|
| 821 |
+
|
| 822 |
+
control_cluster = self.cluster_servers[robot_name]
|
| 823 |
+
if control_cluster.is_cluster_instant(self.cluster_sim_step_counters[robot_name]):
|
| 824 |
+
control_cluster.wait_for_solution() # this is blocking
|
| 825 |
+
failed = control_cluster.get_failed_controllers(gpu=self._use_gpu)
|
| 826 |
+
self._set_cluster_actions(robot_name=robot_name) # set last cmds to low level control
|
| 827 |
+
if not self._override_low_lev_controller:
|
| 828 |
+
self._apply_cmds_to_jnt_imp_control(robot_name=robot_name) # apply to robot
|
| 829 |
+
# we can update the jnt state just at the rate at which the cluster needs it
|
| 830 |
+
self._read_jnts_state_from_robot(robot_name=robot_name, env_indxs=None)
|
| 831 |
+
# read state necessary for cluster
|
| 832 |
+
self._read_root_state_from_robot(robot_name=robot_name,
|
| 833 |
+
env_indxs=None)
|
| 834 |
+
# write last robot state to the cluster of controllers
|
| 835 |
+
self._set_state_to_cluster(robot_name=robot_name,
|
| 836 |
+
env_indxs=None)
|
| 837 |
+
control_cluster.write_robot_state() # write on shared mem
|
| 838 |
+
|
| 839 |
+
if self._use_remote_stepping[i]:
|
| 840 |
+
self._remote_steppers[robot_name].ack() # signal cluster stepping is finished
|
| 841 |
+
if failed is not None and self._env_opts["deact_when_failure"]:
|
| 842 |
+
self._deactivate(env_indxs=failed,
|
| 843 |
+
robot_name=robot_name)
|
| 844 |
+
self._process_remote_reset_req(robot_name=robot_name) # wait for remote reset request (blocking)
|
| 845 |
+
self._wait_for_remote_step_req(robot_name=robot_name)
|
| 846 |
+
else:
|
| 847 |
+
if failed is not None:
|
| 848 |
+
self._reset(env_indxs=failed,
|
| 849 |
+
robot_name=robot_name,
|
| 850 |
+
reset_cluster=True,
|
| 851 |
+
reset_cluster_counter=False,
|
| 852 |
+
randomize=True)
|
| 853 |
+
self._set_startup_jnt_imp_gains(robot_name=robot_name,
|
| 854 |
+
env_indxs=failed)
|
| 855 |
+
control_cluster.activate_controllers(idxs=control_cluster.get_inactive_controllers())
|
| 856 |
+
|
| 857 |
+
control_cluster.pre_trigger() # performs pre-trigger steps, like retrieving
|
| 858 |
+
# values of some rhc flags on shared memory
|
| 859 |
+
control_cluster.trigger_solution() # trigger only active controllers
|
| 860 |
+
|
| 861 |
+
def _post_world_step_db(self) -> bool:
|
| 862 |
+
|
| 863 |
+
for i in range(len(self._robot_names)):
|
| 864 |
+
robot_name = self._robot_names[i]
|
| 865 |
+
control_cluster = self.cluster_servers[robot_name]
|
| 866 |
+
self.cluster_sim_step_counters[robot_name]+=1 # this has to be update with sim freq
|
| 867 |
+
if self._debug:
|
| 868 |
+
self.debug_data["sim_time"][robot_name]=self._get_world_time(robot_name=robot_name)
|
| 869 |
+
self.debug_data["cluster_sol_time"][robot_name] = \
|
| 870 |
+
control_cluster.solution_time()
|
| 871 |
+
|
| 872 |
+
self.step_counter +=1
|
| 873 |
+
|
| 874 |
+
def _get_world_time(self, robot_name: str):
|
| 875 |
+
return self.cluster_sim_step_counters[robot_name]*self.physics_dt()
|
| 876 |
+
|
| 877 |
+
def _post_world_step(self) -> bool:
|
| 878 |
+
|
| 879 |
+
for i in range(len(self._robot_names)):
|
| 880 |
+
robot_name = self._robot_names[i]
|
| 881 |
+
self.cluster_sim_step_counters[robot_name]+=1
|
| 882 |
+
self.step_counter +=1
|
| 883 |
+
|
| 884 |
+
def _reset(self,
|
| 885 |
+
robot_name: str,
|
| 886 |
+
env_indxs: torch.Tensor = None,
|
| 887 |
+
randomize: bool = False,
|
| 888 |
+
reset_cluster: bool = False,
|
| 889 |
+
reset_cluster_counter = False):
|
| 890 |
+
|
| 891 |
+
# resets the state of target robot and env to the defaults
|
| 892 |
+
self._reset_state(env_indxs=env_indxs,
|
| 893 |
+
robot_name=robot_name,
|
| 894 |
+
randomize=randomize)
|
| 895 |
+
# and jnt imp. controllers
|
| 896 |
+
self._reset_jnt_imp_control(robot_name=robot_name,
|
| 897 |
+
env_indxs=env_indxs)
|
| 898 |
+
|
| 899 |
+
self._read_jnts_state_from_robot(robot_name=robot_name,
|
| 900 |
+
env_indxs=env_indxs)
|
| 901 |
+
self._read_root_state_from_robot(robot_name=robot_name,
|
| 902 |
+
env_indxs=env_indxs)
|
| 903 |
+
|
| 904 |
+
if self._jnt_vel_filter[robot_name] is not None:
|
| 905 |
+
self._jnt_vel_filter[robot_name].reset(idxs=env_indxs)
|
| 906 |
+
|
| 907 |
+
if reset_cluster: # reset controllers remotely
|
| 908 |
+
self._reset_cluster(env_indxs=env_indxs,
|
| 909 |
+
robot_name=robot_name,
|
| 910 |
+
reset_cluster_counter=reset_cluster_counter)
|
| 911 |
+
|
| 912 |
+
def _randomize_yaw(self,
|
| 913 |
+
robot_name: str,
|
| 914 |
+
env_indxs: torch.Tensor = None):
|
| 915 |
+
|
| 916 |
+
root_q_default = self._root_q_default[robot_name]
|
| 917 |
+
if env_indxs is None:
|
| 918 |
+
env_indxs = torch.arange(root_q_default.shape[0])
|
| 919 |
+
|
| 920 |
+
num_indices = env_indxs.shape[0]
|
| 921 |
+
yaw_angles = torch.rand((num_indices,),
|
| 922 |
+
device=root_q_default.device) * 2 * torch.pi # uniformly distributed random angles
|
| 923 |
+
|
| 924 |
+
# Compute cos and sin once
|
| 925 |
+
cos_half = torch.cos(yaw_angles / 2)
|
| 926 |
+
root_q_default[env_indxs, :] = torch.stack((cos_half,
|
| 927 |
+
torch.zeros_like(cos_half),
|
| 928 |
+
torch.zeros_like(cos_half),
|
| 929 |
+
torch.sin(yaw_angles / 2)), dim=1).reshape(num_indices, 4)
|
| 930 |
+
|
| 931 |
+
def _deactivate(self,
|
| 932 |
+
robot_name: str,
|
| 933 |
+
env_indxs: torch.Tensor = None):
|
| 934 |
+
|
| 935 |
+
# deactivate jnt imp controllers for given robots and envs (makes the robot fall)
|
| 936 |
+
self._jnt_imp_controllers[robot_name].deactivate(robot_indxs=env_indxs)
|
| 937 |
+
|
| 938 |
+
def _n_contacts(self, robot_name: str) -> List[int]:
|
| 939 |
+
return self._num_contacts[robot_name]
|
| 940 |
+
|
| 941 |
+
def root_p(self,
|
| 942 |
+
robot_name: str,
|
| 943 |
+
env_idxs: torch.Tensor = None):
|
| 944 |
+
|
| 945 |
+
if env_idxs is None:
|
| 946 |
+
return self._root_p[robot_name]
|
| 947 |
+
else:
|
| 948 |
+
return self._root_p[robot_name][env_idxs, :]
|
| 949 |
+
|
| 950 |
+
def root_p_rel(self,
|
| 951 |
+
robot_name: str,
|
| 952 |
+
env_idxs: torch.Tensor = None):
|
| 953 |
+
|
| 954 |
+
rel_pos = torch.sub(self.root_p(robot_name=robot_name,
|
| 955 |
+
env_idxs=env_idxs),
|
| 956 |
+
self._root_pos_offsets[robot_name][env_idxs, :])
|
| 957 |
+
return rel_pos
|
| 958 |
+
|
| 959 |
+
def root_q(self,
|
| 960 |
+
robot_name: str,
|
| 961 |
+
env_idxs: torch.Tensor = None):
|
| 962 |
+
|
| 963 |
+
if env_idxs is None:
|
| 964 |
+
return self._root_q[robot_name]
|
| 965 |
+
else:
|
| 966 |
+
return self._root_q[robot_name][env_idxs, :]
|
| 967 |
+
|
| 968 |
+
def root_q_rel(self,
|
| 969 |
+
robot_name: str,
|
| 970 |
+
env_idxs: torch.Tensor = None):
|
| 971 |
+
|
| 972 |
+
rel_q = quaternion_difference(self._root_q_offsets[robot_name][env_idxs, :],
|
| 973 |
+
self.root_q(robot_name=robot_name,
|
| 974 |
+
env_idxs=env_idxs))
|
| 975 |
+
return rel_q
|
| 976 |
+
|
| 977 |
+
def root_v(self,
|
| 978 |
+
robot_name: str,
|
| 979 |
+
env_idxs: torch.Tensor = None,
|
| 980 |
+
base_loc: bool = True):
|
| 981 |
+
|
| 982 |
+
root_v=self._root_v[robot_name]
|
| 983 |
+
if base_loc:
|
| 984 |
+
root_v=self._root_v_base_loc[robot_name]
|
| 985 |
+
if env_idxs is None:
|
| 986 |
+
return root_v
|
| 987 |
+
else:
|
| 988 |
+
return root_v[env_idxs, :]
|
| 989 |
+
|
| 990 |
+
def root_omega(self,
|
| 991 |
+
robot_name: str,
|
| 992 |
+
env_idxs: torch.Tensor = None,
|
| 993 |
+
base_loc: bool = True):
|
| 994 |
+
|
| 995 |
+
root_omega=self._root_omega[robot_name]
|
| 996 |
+
if base_loc:
|
| 997 |
+
root_omega=self._root_omega_base_loc[robot_name]
|
| 998 |
+
if env_idxs is None:
|
| 999 |
+
return root_omega
|
| 1000 |
+
else:
|
| 1001 |
+
return root_omega[env_idxs, :]
|
| 1002 |
+
|
| 1003 |
+
def root_a(self,
|
| 1004 |
+
robot_name: str,
|
| 1005 |
+
env_idxs: torch.Tensor = None,
|
| 1006 |
+
base_loc: bool = True):
|
| 1007 |
+
|
| 1008 |
+
root_a=self._root_a[robot_name]
|
| 1009 |
+
if base_loc:
|
| 1010 |
+
root_a=self._root_a_base_loc[robot_name]
|
| 1011 |
+
if env_idxs is None:
|
| 1012 |
+
return root_a
|
| 1013 |
+
else:
|
| 1014 |
+
return root_a[env_idxs, :]
|
| 1015 |
+
|
| 1016 |
+
def root_alpha(self,
|
| 1017 |
+
robot_name: str,
|
| 1018 |
+
env_idxs: torch.Tensor = None,
|
| 1019 |
+
base_loc: bool = True):
|
| 1020 |
+
|
| 1021 |
+
root_alpha=self._root_alpha[robot_name]
|
| 1022 |
+
if base_loc:
|
| 1023 |
+
root_alpha=self._root_alpha_base_loc[robot_name]
|
| 1024 |
+
if env_idxs is None:
|
| 1025 |
+
return root_alpha
|
| 1026 |
+
else:
|
| 1027 |
+
return root_alpha[env_idxs, :]
|
| 1028 |
+
|
| 1029 |
+
def gravity(self,
|
| 1030 |
+
robot_name: str,
|
| 1031 |
+
env_idxs: torch.Tensor = None,
|
| 1032 |
+
base_loc: bool = True):
|
| 1033 |
+
|
| 1034 |
+
gravity_loc=self._gravity_normalized[robot_name]
|
| 1035 |
+
if base_loc:
|
| 1036 |
+
gravity_loc=self._gravity_normalized_base_loc[robot_name]
|
| 1037 |
+
if env_idxs is None:
|
| 1038 |
+
return gravity_loc
|
| 1039 |
+
else:
|
| 1040 |
+
return gravity_loc[env_idxs, :]
|
| 1041 |
+
|
| 1042 |
+
def jnts_q(self,
|
| 1043 |
+
robot_name: str,
|
| 1044 |
+
env_idxs: torch.Tensor = None):
|
| 1045 |
+
|
| 1046 |
+
if env_idxs is None:
|
| 1047 |
+
return self._jnts_q[robot_name]
|
| 1048 |
+
else:
|
| 1049 |
+
return self._jnts_q[robot_name][env_idxs, :]
|
| 1050 |
+
|
| 1051 |
+
def jnts_v(self,
|
| 1052 |
+
robot_name: str,
|
| 1053 |
+
env_idxs: torch.Tensor = None):
|
| 1054 |
+
|
| 1055 |
+
if env_idxs is None:
|
| 1056 |
+
return self._jnts_v[robot_name]
|
| 1057 |
+
else:
|
| 1058 |
+
return self._jnts_v[robot_name][env_idxs, :]
|
| 1059 |
+
|
| 1060 |
+
def jnts_eff(self,
|
| 1061 |
+
robot_name: str,
|
| 1062 |
+
env_idxs: torch.Tensor = None): # (measured) efforts
|
| 1063 |
+
|
| 1064 |
+
if env_idxs is None:
|
| 1065 |
+
return self._jnts_eff[robot_name]
|
| 1066 |
+
else:
|
| 1067 |
+
return self._jnts_eff[robot_name][env_idxs, :]
|
| 1068 |
+
|
| 1069 |
+
def _wait_for_remote_step_req(self,
|
| 1070 |
+
robot_name: str):
|
| 1071 |
+
if not self._remote_steppers[robot_name].wait(self._timeout):
|
| 1072 |
+
self.close()
|
| 1073 |
+
Journal.log(self.__class__.__name__,
|
| 1074 |
+
"_wait_for_remote_step_req",
|
| 1075 |
+
"Didn't receive any remote step req within timeout!",
|
| 1076 |
+
LogType.EXCEP,
|
| 1077 |
+
throw_when_excep = True)
|
| 1078 |
+
|
| 1079 |
+
def _process_remote_reset_req(self,
|
| 1080 |
+
robot_name: str):
|
| 1081 |
+
|
| 1082 |
+
if not self._remote_resetters[robot_name].wait(self._timeout):
|
| 1083 |
+
self.close()
|
| 1084 |
+
Journal.log(self.__class__.__name__,
|
| 1085 |
+
"_process_remote_reset_req",
|
| 1086 |
+
"Didn't receive any remote reset req within timeout!",
|
| 1087 |
+
LogType.EXCEP,
|
| 1088 |
+
throw_when_excep = True)
|
| 1089 |
+
|
| 1090 |
+
reset_requests = self._remote_reset_requests[robot_name]
|
| 1091 |
+
reset_requests.synch_all(read=True, retry=True) # read reset requests from shared mem
|
| 1092 |
+
to_be_reset = reset_requests.to_be_reset(gpu=self._use_gpu)
|
| 1093 |
+
if to_be_reset is not None:
|
| 1094 |
+
self._reset(env_indxs=to_be_reset,
|
| 1095 |
+
robot_name=robot_name,
|
| 1096 |
+
reset_cluster=True,
|
| 1097 |
+
reset_cluster_counter=False,
|
| 1098 |
+
randomize=True)
|
| 1099 |
+
self._set_startup_jnt_imp_gains(robot_name=robot_name,
|
| 1100 |
+
env_indxs=to_be_reset)
|
| 1101 |
+
control_cluster = self.cluster_servers[robot_name]
|
| 1102 |
+
control_cluster.activate_controllers(idxs=to_be_reset) # activate controllers
|
| 1103 |
+
# (necessary if failed)
|
| 1104 |
+
|
| 1105 |
+
self._remote_resetters[robot_name].ack() # signal reset performed
|
| 1106 |
+
|
| 1107 |
+
def _update_jnt_imp_cntrl_shared_data(self):
|
| 1108 |
+
if self._debug:
|
| 1109 |
+
for i in range(0, len(self._robot_names)):
|
| 1110 |
+
robot_name = self._robot_names[i]
|
| 1111 |
+
# updating all the jnt impedance data - > this may introduce some overhead
|
| 1112 |
+
imp_data = self._jnt_imp_cntrl_shared_data[robot_name].imp_data_view
|
| 1113 |
+
# set data
|
| 1114 |
+
imp_data.set(data_type="pos_err",
|
| 1115 |
+
data=self._jnt_imp_controllers[robot_name].pos_err(),
|
| 1116 |
+
gpu=self._use_gpu)
|
| 1117 |
+
imp_data.set(data_type="vel_err",
|
| 1118 |
+
data=self._jnt_imp_controllers[robot_name].vel_err(),
|
| 1119 |
+
gpu=self._use_gpu)
|
| 1120 |
+
imp_data.set(data_type="pos_gains",
|
| 1121 |
+
data=self._jnt_imp_controllers[robot_name].pos_gains(),
|
| 1122 |
+
gpu=self._use_gpu)
|
| 1123 |
+
imp_data.set(data_type="vel_gains",
|
| 1124 |
+
data=self._jnt_imp_controllers[robot_name].vel_gains(),
|
| 1125 |
+
gpu=self._use_gpu)
|
| 1126 |
+
imp_data.set(data_type="eff_ff",
|
| 1127 |
+
data=self._jnt_imp_controllers[robot_name].eff_ref(),
|
| 1128 |
+
gpu=self._use_gpu)
|
| 1129 |
+
imp_data.set(data_type="pos",
|
| 1130 |
+
data=self._jnt_imp_controllers[robot_name].pos(),
|
| 1131 |
+
gpu=self._use_gpu)
|
| 1132 |
+
imp_data.set(data_type="pos_ref",
|
| 1133 |
+
data=self._jnt_imp_controllers[robot_name].pos_ref(),
|
| 1134 |
+
gpu=self._use_gpu)
|
| 1135 |
+
imp_data.set(data_type="vel",
|
| 1136 |
+
data=self._jnt_imp_controllers[robot_name].vel(),
|
| 1137 |
+
gpu=self._use_gpu)
|
| 1138 |
+
imp_data.set(data_type="vel_ref",
|
| 1139 |
+
data=self._jnt_imp_controllers[robot_name].vel_ref(),
|
| 1140 |
+
gpu=self._use_gpu)
|
| 1141 |
+
imp_data.set(data_type="eff",
|
| 1142 |
+
data=self._jnt_imp_controllers[robot_name].eff(),
|
| 1143 |
+
gpu=self._use_gpu)
|
| 1144 |
+
imp_data.set(data_type="imp_eff",
|
| 1145 |
+
data=self._jnt_imp_controllers[robot_name].imp_eff(),
|
| 1146 |
+
gpu=self._use_gpu)
|
| 1147 |
+
# copy from GPU to CPU if using gpu
|
| 1148 |
+
if self._use_gpu:
|
| 1149 |
+
imp_data.synch_mirror(from_gpu=True,non_blocking=True)
|
| 1150 |
+
# even if it's from GPU->CPu we can use non-blocking since it's just for db
|
| 1151 |
+
# purposes
|
| 1152 |
+
# write copies to shared memory
|
| 1153 |
+
imp_data.synch_all(read=False, retry=False)
|
| 1154 |
+
|
| 1155 |
+
def _set_startup_jnt_imp_gains(self,
|
| 1156 |
+
robot_name:str,
|
| 1157 |
+
env_indxs: torch.Tensor = None):
|
| 1158 |
+
|
| 1159 |
+
startup_p_gains=self._jnt_imp_controllers[robot_name].startup_p_gains()
|
| 1160 |
+
startup_d_gains=self._jnt_imp_controllers[robot_name].startup_d_gains()
|
| 1161 |
+
|
| 1162 |
+
if env_indxs is not None:
|
| 1163 |
+
self._jnt_imp_controllers[robot_name].set_gains(robot_indxs=env_indxs,
|
| 1164 |
+
pos_gains=startup_p_gains[env_indxs, :],
|
| 1165 |
+
vel_gains=startup_d_gains[env_indxs, :])
|
| 1166 |
+
else:
|
| 1167 |
+
self._jnt_imp_controllers[robot_name].set_gains(robot_indxs=env_indxs,
|
| 1168 |
+
pos_gains=startup_p_gains[:, :],
|
| 1169 |
+
vel_gains=startup_d_gains[:, :])
|
| 1170 |
+
|
| 1171 |
+
def _write_state_to_jnt_imp(self,
|
| 1172 |
+
robot_name: str):
|
| 1173 |
+
|
| 1174 |
+
# always update ,imp. controller internal state (jnt imp control is supposed to be
|
| 1175 |
+
# always running)
|
| 1176 |
+
self._jnt_imp_controllers[robot_name].update_state(pos=self.jnts_q(robot_name=robot_name),
|
| 1177 |
+
vel = self.jnts_v(robot_name=robot_name),
|
| 1178 |
+
eff = self.jnts_eff(robot_name=robot_name))
|
| 1179 |
+
|
| 1180 |
+
def _set_cluster_actions(self,
|
| 1181 |
+
robot_name):
|
| 1182 |
+
control_cluster = self.cluster_servers[robot_name]
|
| 1183 |
+
actions=control_cluster.get_actions()
|
| 1184 |
+
active_controllers=control_cluster.get_active_controllers(gpu=self._use_gpu)
|
| 1185 |
+
|
| 1186 |
+
if active_controllers is not None:
|
| 1187 |
+
self._jnt_imp_controllers[robot_name].set_refs(
|
| 1188 |
+
pos_ref=actions.jnts_state.get(data_type="q", gpu=self._use_gpu)[active_controllers, :],
|
| 1189 |
+
vel_ref=actions.jnts_state.get(data_type="v", gpu=self._use_gpu)[active_controllers, :],
|
| 1190 |
+
eff_ref=actions.jnts_state.get(data_type="eff", gpu=self._use_gpu)[active_controllers, :],
|
| 1191 |
+
robot_indxs=active_controllers)
|
| 1192 |
+
|
| 1193 |
+
def _jnt_imp_reset_overrride(self, robot_name:str):
|
| 1194 |
+
# to be overriden
|
| 1195 |
+
pass
|
| 1196 |
+
|
| 1197 |
+
def _apply_cmds_to_jnt_imp_control(self, robot_name:str):
|
| 1198 |
+
|
| 1199 |
+
self._jnt_imp_controllers[robot_name].apply_cmds()
|
| 1200 |
+
|
| 1201 |
+
def _update_root_offsets(self,
|
| 1202 |
+
robot_name: str,
|
| 1203 |
+
env_indxs: torch.Tensor = None):
|
| 1204 |
+
|
| 1205 |
+
if self._debug:
|
| 1206 |
+
for_robots = ""
|
| 1207 |
+
if env_indxs is not None:
|
| 1208 |
+
if not isinstance(env_indxs, torch.Tensor):
|
| 1209 |
+
msg = "Provided env_indxs should be a torch tensor of indexes!"
|
| 1210 |
+
Journal.log(self.__class__.__name__,
|
| 1211 |
+
"update_root_offsets",
|
| 1212 |
+
msg,
|
| 1213 |
+
LogType.EXCEP,
|
| 1214 |
+
throw_when_excep = True)
|
| 1215 |
+
if self._use_gpu:
|
| 1216 |
+
if not env_indxs.device.type == "cuda":
|
| 1217 |
+
error = "Provided env_indxs should be on GPU!"
|
| 1218 |
+
Journal.log(self.__class__.__name__,
|
| 1219 |
+
"_step_jnt_imp_control",
|
| 1220 |
+
error,
|
| 1221 |
+
LogType.EXCEP,
|
| 1222 |
+
True)
|
| 1223 |
+
else:
|
| 1224 |
+
if not env_indxs.device.type == "cpu":
|
| 1225 |
+
error = "Provided env_indxs should be on CPU!"
|
| 1226 |
+
Journal.log(self.__class__.__name__,
|
| 1227 |
+
"_step_jnt_imp_control",
|
| 1228 |
+
error,
|
| 1229 |
+
LogType.EXCEP,
|
| 1230 |
+
True)
|
| 1231 |
+
for_robots = f"for robot {robot_name}, indexes: " + str(env_indxs.tolist())
|
| 1232 |
+
if self._verbose:
|
| 1233 |
+
Journal.log(self.__class__.__name__,
|
| 1234 |
+
"update_root_offsets",
|
| 1235 |
+
f"updating root offsets " + for_robots,
|
| 1236 |
+
LogType.STAT,
|
| 1237 |
+
throw_when_excep = True)
|
| 1238 |
+
|
| 1239 |
+
# only planar position used
|
| 1240 |
+
if env_indxs is None:
|
| 1241 |
+
self._root_pos_offsets[robot_name][:, 0:2] = self._root_p[robot_name][:, 0:2]
|
| 1242 |
+
self._root_q_offsets[robot_name][:, :] = self._root_q[robot_name]
|
| 1243 |
+
|
| 1244 |
+
else:
|
| 1245 |
+
self._root_pos_offsets[robot_name][env_indxs, 0:2] = self._root_p[robot_name][env_indxs, 0:2]
|
| 1246 |
+
self._root_q_offsets[robot_name][env_indxs, :] = self._root_q[robot_name][env_indxs, :]
|
| 1247 |
+
|
| 1248 |
+
def _reset_jnt_imp_control(self,
|
| 1249 |
+
robot_name: str,
|
| 1250 |
+
env_indxs: torch.Tensor = None):
|
| 1251 |
+
|
| 1252 |
+
if self._debug:
|
| 1253 |
+
for_robots = ""
|
| 1254 |
+
if env_indxs is not None:
|
| 1255 |
+
if not isinstance(env_indxs, torch.Tensor):
|
| 1256 |
+
Journal.log(self.__class__.__name__,
|
| 1257 |
+
"reset_jnt_imp_control",
|
| 1258 |
+
"Provided env_indxs should be a torch tensor of indexes!",
|
| 1259 |
+
LogType.EXCEP,
|
| 1260 |
+
throw_when_excep = True)
|
| 1261 |
+
if self._use_gpu:
|
| 1262 |
+
if not env_indxs.device.type == "cuda":
|
| 1263 |
+
error = "Provided env_indxs should be on GPU!"
|
| 1264 |
+
Journal.log(self.__class__.__name__,
|
| 1265 |
+
"_step_jnt_imp_control",
|
| 1266 |
+
error,
|
| 1267 |
+
LogType.EXCEP,
|
| 1268 |
+
True)
|
| 1269 |
+
else:
|
| 1270 |
+
if not env_indxs.device.type == "cpu":
|
| 1271 |
+
error = "Provided env_indxs should be on CPU!"
|
| 1272 |
+
Journal.log(self.__class__.__name__,
|
| 1273 |
+
"_step_jnt_imp_control",
|
| 1274 |
+
error,
|
| 1275 |
+
LogType.EXCEP,
|
| 1276 |
+
True)
|
| 1277 |
+
for_robots = f"for robot {robot_name}, indexes: " + str(env_indxs)
|
| 1278 |
+
|
| 1279 |
+
if self._verbose:
|
| 1280 |
+
Journal.log(self.__class__.__name__,
|
| 1281 |
+
"reset_jnt_imp_control",
|
| 1282 |
+
f"resetting joint impedances " + for_robots,
|
| 1283 |
+
LogType.STAT,
|
| 1284 |
+
throw_when_excep = True)
|
| 1285 |
+
|
| 1286 |
+
# resets all internal data, refs to defaults
|
| 1287 |
+
self._jnt_imp_controllers[robot_name].reset(robot_indxs=env_indxs)
|
| 1288 |
+
|
| 1289 |
+
#restore jnt imp refs to homing
|
| 1290 |
+
if env_indxs is None:
|
| 1291 |
+
self._jnt_imp_controllers[robot_name].set_refs(pos_ref=self._homing[:, :],
|
| 1292 |
+
robot_indxs = None)
|
| 1293 |
+
else:
|
| 1294 |
+
self._jnt_imp_controllers[robot_name].set_refs(pos_ref=self._homing[env_indxs, :],
|
| 1295 |
+
robot_indxs = env_indxs)
|
| 1296 |
+
|
| 1297 |
+
# self._write_state_to_jnt_imp(robot_name=robot_name)
|
| 1298 |
+
# actually applies reset commands to the articulation
|
| 1299 |
+
self._write_state_to_jnt_imp(robot_name=robot_name)
|
| 1300 |
+
self._jnt_imp_reset_overrride(robot_name=robot_name)
|
| 1301 |
+
self._apply_cmds_to_jnt_imp_control(robot_name=robot_name)
|
| 1302 |
+
|
| 1303 |
+
def _synch_default_root_states(self,
|
| 1304 |
+
robot_name: str,
|
| 1305 |
+
env_indxs: torch.Tensor = None):
|
| 1306 |
+
|
| 1307 |
+
if self._debug:
|
| 1308 |
+
for_robots = ""
|
| 1309 |
+
if env_indxs is not None:
|
| 1310 |
+
if not isinstance(env_indxs, torch.Tensor):
|
| 1311 |
+
msg = "Provided env_indxs should be a torch tensor of indexes!"
|
| 1312 |
+
Journal.log(self.__class__.__name__,
|
| 1313 |
+
"synch_default_root_states",
|
| 1314 |
+
msg,
|
| 1315 |
+
LogType.EXCEP,
|
| 1316 |
+
throw_when_excep = True)
|
| 1317 |
+
if self._use_gpu:
|
| 1318 |
+
if not env_indxs.device.type == "cuda":
|
| 1319 |
+
error = "Provided env_indxs should be on GPU!"
|
| 1320 |
+
Journal.log(self.__class__.__name__,
|
| 1321 |
+
"_step_jnt_imp_control",
|
| 1322 |
+
error,
|
| 1323 |
+
LogType.EXCEP,
|
| 1324 |
+
True)
|
| 1325 |
+
else:
|
| 1326 |
+
if not env_indxs.device.type == "cpu":
|
| 1327 |
+
error = "Provided env_indxs should be on CPU!"
|
| 1328 |
+
Journal.log(self.__class__.__name__,
|
| 1329 |
+
"_step_jnt_imp_control",
|
| 1330 |
+
error,
|
| 1331 |
+
LogType.EXCEP,
|
| 1332 |
+
True)
|
| 1333 |
+
for_robots = f"for robot {robot_name}, indexes: " + str(env_indxs.tolist())
|
| 1334 |
+
if self._verbose:
|
| 1335 |
+
Journal.log(self.__class__.__name__,
|
| 1336 |
+
"synch_default_root_states",
|
| 1337 |
+
f"updating default root states " + for_robots,
|
| 1338 |
+
LogType.STAT,
|
| 1339 |
+
throw_when_excep = True)
|
| 1340 |
+
|
| 1341 |
+
if env_indxs is None:
|
| 1342 |
+
self._root_p_default[robot_name][:, :] = self._root_p[robot_name]
|
| 1343 |
+
self._root_q_default[robot_name][:, :] = self._root_q[robot_name]
|
| 1344 |
+
else:
|
| 1345 |
+
self._root_p_default[robot_name][env_indxs, :] = self._root_p[robot_name][env_indxs, :]
|
| 1346 |
+
self._root_q_default[robot_name][env_indxs, :] = self._root_q[robot_name][env_indxs, :]
|
| 1347 |
+
|
| 1348 |
+
def _generate_rob_descriptions(self,
|
| 1349 |
+
robot_name: str,
|
| 1350 |
+
urdf_path: str,
|
| 1351 |
+
srdf_path: str):
|
| 1352 |
+
|
| 1353 |
+
custom_xacro_args=extract_custom_xacro_args(self._env_opts)
|
| 1354 |
+
Journal.log(self.__class__.__name__,
|
| 1355 |
+
"_generate_rob_descriptions",
|
| 1356 |
+
"generating URDF for robot "+ f"{robot_name}, from URDF {urdf_path}...",
|
| 1357 |
+
LogType.STAT,
|
| 1358 |
+
throw_when_excep = True)
|
| 1359 |
+
xrdf_cmds=self._xrdf_cmds(robot_name=robot_name)
|
| 1360 |
+
xrdf_cmds=merge_xacro_cmds(prev_cmds=xrdf_cmds,
|
| 1361 |
+
new_cmds=custom_xacro_args)
|
| 1362 |
+
self._urdf_dump_paths[robot_name]=generate_urdf(robot_name=robot_name,
|
| 1363 |
+
xacro_path=urdf_path,
|
| 1364 |
+
dump_path=self._descr_dump_path,
|
| 1365 |
+
xrdf_cmds=xrdf_cmds)
|
| 1366 |
+
Journal.log(self.__class__.__name__,
|
| 1367 |
+
"_generate_rob_descriptions",
|
| 1368 |
+
"generating SRDF for robot "+ f"{robot_name}, from SRDF {srdf_path}...",
|
| 1369 |
+
LogType.STAT,
|
| 1370 |
+
throw_when_excep = True)
|
| 1371 |
+
# we also generate SRDF files, which are useful for control
|
| 1372 |
+
self._srdf_dump_paths[robot_name]=generate_srdf(robot_name=robot_name,
|
| 1373 |
+
xacro_path=srdf_path,
|
| 1374 |
+
dump_path=self._descr_dump_path,
|
| 1375 |
+
xrdf_cmds=xrdf_cmds)
|
| 1376 |
+
|
| 1377 |
+
def _xrdf_cmds(self, robot_name:str):
|
| 1378 |
+
urdfpath=self._robot_urdf_paths[robot_name]
|
| 1379 |
+
# we assume directory tree of the robot package is like
|
| 1380 |
+
# robot-ros-pkg/robot_urdf/urdf/robot.urdf.xacro
|
| 1381 |
+
parts = urdfpath.split('/')
|
| 1382 |
+
urdf_descr_root_path = '/'.join(parts[:-2])
|
| 1383 |
+
cmds = get_xrdf_cmds(urdf_descr_root_path=urdf_descr_root_path)
|
| 1384 |
+
return cmds
|
| 1385 |
+
|
| 1386 |
+
@abstractmethod
|
| 1387 |
+
def current_tstep(self) -> int:
|
| 1388 |
+
pass
|
| 1389 |
+
|
| 1390 |
+
@abstractmethod
|
| 1391 |
+
def current_time(self) -> float:
|
| 1392 |
+
pass
|
| 1393 |
+
|
| 1394 |
+
@abstractmethod
|
| 1395 |
+
def is_running(self) -> bool:
|
| 1396 |
+
pass
|
| 1397 |
+
|
| 1398 |
+
@abstractmethod
|
| 1399 |
+
def _get_contact_f(self,
|
| 1400 |
+
robot_name: str,
|
| 1401 |
+
contact_link: str,
|
| 1402 |
+
env_indxs: torch.Tensor) -> torch.Tensor:
|
| 1403 |
+
return None
|
| 1404 |
+
|
| 1405 |
+
@abstractmethod
|
| 1406 |
+
def physics_dt(self) -> float:
|
| 1407 |
+
pass
|
| 1408 |
+
|
| 1409 |
+
@abstractmethod
|
| 1410 |
+
def rendering_dt(self) -> float:
|
| 1411 |
+
pass
|
| 1412 |
+
|
| 1413 |
+
@abstractmethod
|
| 1414 |
+
def set_physics_dt(self, physics_dt:float):
|
| 1415 |
+
pass
|
| 1416 |
+
|
| 1417 |
+
@abstractmethod
|
| 1418 |
+
def set_rendering_dt(self, rendering_dt:float):
|
| 1419 |
+
pass
|
| 1420 |
+
|
| 1421 |
+
@abstractmethod
|
| 1422 |
+
def _robot_jnt_names(self, robot_name: str) -> List[str]:
|
| 1423 |
+
pass
|
| 1424 |
+
|
| 1425 |
+
@abstractmethod
|
| 1426 |
+
def _read_root_state_from_robot(self,
|
| 1427 |
+
robot_name: str,
|
| 1428 |
+
env_indxs: torch.Tensor = None):
|
| 1429 |
+
pass
|
| 1430 |
+
|
| 1431 |
+
@abstractmethod
|
| 1432 |
+
def _read_jnts_state_from_robot(self,
|
| 1433 |
+
robot_name: str,
|
| 1434 |
+
env_indxs: torch.Tensor = None):
|
| 1435 |
+
pass
|
| 1436 |
+
|
| 1437 |
+
@abstractmethod
|
| 1438 |
+
def _init_robots_state(self):
|
| 1439 |
+
pass
|
| 1440 |
+
|
| 1441 |
+
@abstractmethod
|
| 1442 |
+
def _reset_state(self,
|
| 1443 |
+
robot_name: str,
|
| 1444 |
+
env_indxs: torch.Tensor = None,
|
| 1445 |
+
randomize: bool = False):
|
| 1446 |
+
pass
|
| 1447 |
+
|
| 1448 |
+
@abstractmethod
|
| 1449 |
+
def _init_world(self):
|
| 1450 |
+
pass
|
| 1451 |
+
|
| 1452 |
+
@abstractmethod
|
| 1453 |
+
def _reset_sim(self) -> None:
|
| 1454 |
+
pass
|
| 1455 |
+
|
| 1456 |
+
@abstractmethod
|
| 1457 |
+
def _set_jnts_to_homing(self, robot_name: str):
|
| 1458 |
+
pass
|
| 1459 |
+
|
| 1460 |
+
@abstractmethod
|
| 1461 |
+
def _set_root_to_defconfig(self, robot_name: str):
|
| 1462 |
+
pass
|
| 1463 |
+
|
| 1464 |
+
@abstractmethod
|
| 1465 |
+
def _parse_env_opts(self):
|
| 1466 |
+
pass
|
| 1467 |
+
|
| 1468 |
+
@abstractmethod
|
| 1469 |
+
def _pre_setup(self):
|
| 1470 |
+
pass
|
| 1471 |
+
|
| 1472 |
+
@abstractmethod
|
| 1473 |
+
def _generate_jnt_imp_control(self) -> JntImpCntrlChild:
|
| 1474 |
+
pass
|
| 1475 |
+
|
| 1476 |
+
@abstractmethod
|
| 1477 |
+
def _render_sim(self, mode:str="human") -> None:
|
| 1478 |
+
pass
|
| 1479 |
+
|
| 1480 |
+
@abstractmethod
|
| 1481 |
+
def _close(self) -> None:
|
| 1482 |
+
pass
|
| 1483 |
+
|
| 1484 |
+
@abstractmethod
|
| 1485 |
+
def _step_world(self) -> None:
|
| 1486 |
+
pass
|
bundles/centauro/d2026_01_19_h14_m54_s32-CentauroCloopPartialNoYawUbPercep_FakePosTrackEnvPhaseControl/xbot2_basic.yaml
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
XBotInterface:
|
| 2 |
+
urdf_path: $PWD/centauro.urdf
|
| 3 |
+
srdf_path: $PWD/centauro.srdf
|
| 4 |
+
|
| 5 |
+
ModelInterface:
|
| 6 |
+
model_type: RBDL
|
| 7 |
+
is_model_floating_base: true
|
| 8 |
+
|
| 9 |
+
motor_pd:
|
| 10 |
+
"j_arm*_1": [500, 10]
|
| 11 |
+
"j_arm*_2": [500, 10]
|
| 12 |
+
"j_arm*_3": [500, 10]
|
| 13 |
+
"j_arm*_4": [500, 10]
|
| 14 |
+
"j_arm*_5": [100, 5]
|
| 15 |
+
"j_arm*_6": [100, 5]
|
| 16 |
+
"j_arm*_7": [100, 5]
|
| 17 |
+
"hip_yaw_*": [3000, 30]
|
| 18 |
+
"hip_pitch_*": [3000, 30]
|
| 19 |
+
"knee_pitch_*": [3000, 30]
|
| 20 |
+
"ankle_pitch_*": [1000, 10]
|
| 21 |
+
"ankle_yaw_*": [300, 10]
|
| 22 |
+
"neck_pitch": [10, 1]
|
| 23 |
+
"neck_yaw": [10, 1]
|
| 24 |
+
"torso_yaw": [1000, 30]
|
| 25 |
+
"j_wheel_*": [0, 30]
|
| 26 |
+
"velodyne_*": [10, 1]
|
| 27 |
+
"d435_*": [10, 1]
|
| 28 |
+
|
| 29 |
+
startup_motor_pd:
|
| 30 |
+
"j_arm*_1": [500, 30]
|
| 31 |
+
"j_arm*_2": [500, 30]
|
| 32 |
+
"j_arm*_3": [500, 30]
|
| 33 |
+
"j_arm*_4": [500, 30]
|
| 34 |
+
"j_arm*_5": [100, 5]
|
| 35 |
+
"j_arm*_6": [100, 5]
|
| 36 |
+
"j_arm*_7": [100, 5]
|
| 37 |
+
"hip_yaw_*": [800, 80]
|
| 38 |
+
"hip_pitch_*": [800, 80]
|
| 39 |
+
"knee_pitch_*": [800, 80]
|
| 40 |
+
"ankle_pitch_*": [800, 80]
|
| 41 |
+
"ankle_yaw_*": [480, 50]
|
| 42 |
+
"neck_pitch": [10, 1]
|
| 43 |
+
"neck_yaw": [10, 1]
|
| 44 |
+
"torso_yaw": [800, 80]
|
| 45 |
+
"j_wheel_*": [0, 30]
|
| 46 |
+
"velodyne_*": [10, 1]
|
| 47 |
+
"d435_*": [10, 1]
|
| 48 |
+
|
| 49 |
+
motor_vel:
|
| 50 |
+
j_wheel_*: [1]
|
| 51 |
+
neck_velodyne: [1]
|
| 52 |
+
|
| 53 |
+
# hal
|
| 54 |
+
xbotcore_device_configs:
|
| 55 |
+
sim: $PWD/hal/centauro_gz.yaml
|
| 56 |
+
dummy: $PWD/hal/centauro_dummy.yaml
|
| 57 |
+
|
| 58 |
+
# threads
|
| 59 |
+
xbotcore_threads:
|
| 60 |
+
rt_main: {sched: fifo , prio: 60, period: 0.001}
|
| 61 |
+
nrt_main: {sched: other, prio: 0 , period: 0.005}
|
| 62 |
+
|
| 63 |
+
# plugins
|
| 64 |
+
xbotcore_plugins:
|
| 65 |
+
|
| 66 |
+
homing:
|
| 67 |
+
thread: rt_main
|
| 68 |
+
type: homing
|
| 69 |
+
|
| 70 |
+
ros_io: {thread: nrt_main, type: ros_io}
|
| 71 |
+
|
| 72 |
+
ros_control: {thread: nrt_main, type: ros_control, params: {autostart: {type: bool, value: true}}}
|
| 73 |
+
|
| 74 |
+
# global parameters
|
| 75 |
+
xbotcore_param:
|
| 76 |
+
/xbot/hal/joint_safety/filter_autostart: {value: true, type: bool}
|
| 77 |
+
# /xbot/hal/joint_safety/filter_cutoff_hz: {value: 1.0, type: double}
|
| 78 |
+
/xbot/hal/joint_safety/filter_safe_cutoff_hz: {value: 5.0, type: double}
|
| 79 |
+
/xbot/hal/joint_safety/filter_medium_cutoff_hz: {value: 10.0, type: double}
|
| 80 |
+
/xbot/hal/joint_safety/filter_fast_cutoff_hz: {value: 15.0, type: double}
|
| 81 |
+
/xbot/hal/enable_safety: {value: false, type: bool}
|
bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/bundle.yaml
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
bundle_format: augmpc_model_bundle_v1
|
| 2 |
+
bundle_name: d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv
|
| 3 |
+
checkpoint_file: d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv_model
|
| 4 |
+
preserved_training_cfgs:
|
| 5 |
+
- ibrido_run__2026_02_21_13_59_20_ID/training_cfg_centauro_ub_cloop.sh
|
| 6 |
+
framework:
|
| 7 |
+
repos:
|
| 8 |
+
AugMPC:
|
| 9 |
+
commit: f2ff28085ea76d2b548841de6f363f7183480f86
|
| 10 |
+
branch: ibrido
|
| 11 |
+
remote: git@github.com:AndrePatri/AugMPC.git
|
| 12 |
+
dirty: false
|
| 13 |
+
AugMPCEnvs:
|
| 14 |
+
commit: 46c5d4161cb4b249b3a2e50c93c6bc2aa087f027
|
| 15 |
+
branch: ibrido
|
| 16 |
+
remote: git@github.com:AndrePatri/AugMPCEnvs.git
|
| 17 |
+
dirty: false
|
| 18 |
+
AugMPCModels:
|
| 19 |
+
commit: 8b15c800c0f5684c61fdaf4847156ff71df61ebc
|
| 20 |
+
branch: main
|
| 21 |
+
remote: https://huggingface.co/AndrePatri/AugMPCModels
|
| 22 |
+
dirty: true
|
| 23 |
+
CentauroHybridMPC:
|
| 24 |
+
commit: 640889d4c3b9c8d360b5a3ccde6fc2bd8f139891
|
| 25 |
+
branch: ibrido
|
| 26 |
+
remote: git@github.com:ADVRHumanoids/CentauroHybridMPC.git
|
| 27 |
+
dirty: false
|
| 28 |
+
EigenIPC:
|
| 29 |
+
commit: 7c1c3ecd08716e61ed164a6e0bb788aa716705ca
|
| 30 |
+
branch: devel
|
| 31 |
+
remote: git@github.com:AndrePatri/EigenIPC.git
|
| 32 |
+
dirty: false
|
| 33 |
+
IBRIDO:
|
| 34 |
+
commit: 0ceb5f3e0508b6ecdce12bcc8f0dcbcde8f29a93
|
| 35 |
+
branch: main
|
| 36 |
+
remote: git@github.com:AndrePatri/IBRIDO.git
|
| 37 |
+
dirty: false
|
| 38 |
+
IsaacLab:
|
| 39 |
+
commit: a520a883ce996d855cc9d5255d71fd1c1307633f
|
| 40 |
+
branch: HEAD
|
| 41 |
+
remote: git@github.com:isaac-sim/IsaacLab.git
|
| 42 |
+
dirty: true
|
| 43 |
+
KyonRLStepping:
|
| 44 |
+
commit: 2bea2b8d70078974869df0549e90fc27ff31f851
|
| 45 |
+
branch: ibrido
|
| 46 |
+
remote: git@github.com:ADVRHumanoids/KyonRLStepping.git
|
| 47 |
+
dirty: false
|
| 48 |
+
MPCHive:
|
| 49 |
+
commit: 45b4fc692850cef607020dda2e32fd708e7fff62
|
| 50 |
+
branch: devel
|
| 51 |
+
remote: git@github.com:AndrePatri/MPCHive.git
|
| 52 |
+
dirty: false
|
| 53 |
+
MPCViz:
|
| 54 |
+
commit: 806d03efcc9d8ab1fb04991a159c19ba89bfb85b
|
| 55 |
+
branch: ros2_humble
|
| 56 |
+
remote: git@github.com:AndrePatri/MPCViz.git
|
| 57 |
+
dirty: false
|
| 58 |
+
adarl:
|
| 59 |
+
commit: f585499e49fa05fdd070a77f3211c0996599b87b
|
| 60 |
+
branch: ibrido
|
| 61 |
+
remote: git@github.com:c-rizz/adarl.git
|
| 62 |
+
dirty: false
|
| 63 |
+
casadi:
|
| 64 |
+
commit: 79cebe3b416dee22abc87de0076b80a5b97bd345
|
| 65 |
+
branch: optional_float
|
| 66 |
+
remote: git@github.com:AndrePatri/casadi.git
|
| 67 |
+
dirty: true
|
| 68 |
+
horizon:
|
| 69 |
+
commit: 3b084317709ff9b88d4a07ac5436f5988b39eece
|
| 70 |
+
branch: ibrido
|
| 71 |
+
remote: git@github.com:AndrePatri/horizon.git
|
| 72 |
+
dirty: true
|
| 73 |
+
iit-centauro-ros-pkg:
|
| 74 |
+
commit: 6069807ebb37a6d7df39430a02685e09ed9b167a
|
| 75 |
+
branch: ibrido_ros2
|
| 76 |
+
remote: git@github.com:AndrePatri/iit-centauro-ros-pkg.git
|
| 77 |
+
dirty: false
|
| 78 |
+
iit-dagana-ros-pkg:
|
| 79 |
+
commit: f7ecd6c84a0b7f3320c1b7de6449cbcd4445d2fe
|
| 80 |
+
branch: ibrido_ros2
|
| 81 |
+
remote: git@github.com:AndrePatri/iit-dagana-ros-pkg.git
|
| 82 |
+
dirty: false
|
| 83 |
+
iit-kyon-description:
|
| 84 |
+
commit: 50fd7c8909b3ddfd1ebbe67c61d6b775b86df6b1
|
| 85 |
+
branch: ibrido_ros2
|
| 86 |
+
remote: git@github.com:ADVRHumanoids/iit-kyon-ros-pkg.git
|
| 87 |
+
dirty: false
|
| 88 |
+
iit-kyon-description-mpc:
|
| 89 |
+
commit: 3a92bee28405172e8f6c628b4498703724d35bf5
|
| 90 |
+
branch: ibrido_ros2
|
| 91 |
+
remote: git@github.com:ADVRHumanoids/iit-kyon-ros-pkg.git
|
| 92 |
+
dirty: false
|
| 93 |
+
iit-kyon-ros-pkg:
|
| 94 |
+
commit: 298917efffb63dbca540e0aedbd21b41bf393fbf
|
| 95 |
+
branch: ibrido_ros2_simple
|
| 96 |
+
remote: git@github.com:ADVRHumanoids/iit-kyon-ros-pkg.git
|
| 97 |
+
dirty: false
|
| 98 |
+
phase_manager:
|
| 99 |
+
commit: 9925d18c0d7a55d013cbaa4998c61d85a3a8944f
|
| 100 |
+
branch: ibrido
|
| 101 |
+
remote: git@github.com:AndrePatri/phase_manager.git
|
| 102 |
+
dirty: false
|
| 103 |
+
unitree_ros:
|
| 104 |
+
commit: c75a622b8782d11dd6aa4c2ebd3b0f9c13a56aae
|
| 105 |
+
branch: ibrido
|
| 106 |
+
remote: git@github.com:AndrePatri/unitree_ros.git
|
| 107 |
+
dirty: true
|
bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/centauro_big_wheels_ub_2026_02_21_13_59_20_ID.srdf
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?xml version="1.0" ?>
|
| 2 |
+
<!-- =================================================================================== -->
|
| 3 |
+
<!-- | This document was autogenerated by xacro from /root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_srdf/srdf/centauro.srdf.xacro | -->
|
| 4 |
+
<!-- | EDITING THIS FILE BY HAND IS NOT RECOMMENDED | -->
|
| 5 |
+
<!-- =================================================================================== -->
|
| 6 |
+
<!--This does not replace URDF, and is not an extension of URDF.
|
| 7 |
+
This is a format for representing semantic information about the robot structure.
|
| 8 |
+
A URDF file must exist for this robot as well, where the joints and the links that are referenced are defined
|
| 9 |
+
-->
|
| 10 |
+
<robot name="centauro">
|
| 11 |
+
<!-- none, ball, dagana_fixed, dagana -->
|
| 12 |
+
<group name="base">
|
| 13 |
+
<link name="pelvis"/>
|
| 14 |
+
</group>
|
| 15 |
+
<group name="imu_sensors">
|
| 16 |
+
<link name="imu_link"/>
|
| 17 |
+
</group>
|
| 18 |
+
<group name="front_left_leg">
|
| 19 |
+
<chain base_link="pelvis" tip_link="wheel_1"/>
|
| 20 |
+
</group>
|
| 21 |
+
<group name="front_right_leg">
|
| 22 |
+
<chain base_link="pelvis" tip_link="wheel_2"/>
|
| 23 |
+
</group>
|
| 24 |
+
<group name="rear_right_leg">
|
| 25 |
+
<chain base_link="pelvis" tip_link="wheel_4"/>
|
| 26 |
+
</group>
|
| 27 |
+
<group name="rear_left_leg">
|
| 28 |
+
<chain base_link="pelvis" tip_link="wheel_3"/>
|
| 29 |
+
</group>
|
| 30 |
+
<group name="left_arm">
|
| 31 |
+
<chain base_link="torso_2" tip_link="arm1_8"/>
|
| 32 |
+
</group>
|
| 33 |
+
<group name="right_arm">
|
| 34 |
+
<chain base_link="torso_2" tip_link="arm2_8"/>
|
| 35 |
+
</group>
|
| 36 |
+
<group name="torso">
|
| 37 |
+
<chain base_link="pelvis" tip_link="torso_2"/>
|
| 38 |
+
</group>
|
| 39 |
+
<group name="velodyne">
|
| 40 |
+
<chain base_link="torso_2" tip_link="velodyne_motor"/>
|
| 41 |
+
</group>
|
| 42 |
+
<group name="d435_head">
|
| 43 |
+
<chain base_link="torso_2" tip_link="d435_head_motor"/>
|
| 44 |
+
</group>
|
| 45 |
+
<group name="chains">
|
| 46 |
+
<group name="front_left_leg"/>
|
| 47 |
+
<group name="front_right_leg"/>
|
| 48 |
+
<group name="rear_right_leg"/>
|
| 49 |
+
<group name="rear_left_leg"/>
|
| 50 |
+
<group name="left_arm"/>
|
| 51 |
+
<group name="right_arm"/>
|
| 52 |
+
<group name="torso"/>
|
| 53 |
+
<group name="velodyne"/>
|
| 54 |
+
<group name="d435_head"/>
|
| 55 |
+
</group>
|
| 56 |
+
<!-- Homing posture -->
|
| 57 |
+
<!-- <group_state name="home" group="chains">
|
| 58 |
+
<joint name="hip_yaw_1" value="-0.746874"/>
|
| 59 |
+
<joint name="hip_pitch_1" value="-1.25409"/>
|
| 60 |
+
<joint name="knee_pitch_1" value="-1.55576"/>
|
| 61 |
+
<joint name="ankle_pitch_1" value="-0.301666"/>
|
| 62 |
+
<joint name="ankle_yaw_1" value="0.746874"/>
|
| 63 |
+
<joint name="hip_yaw_2" value="0.746874"/>
|
| 64 |
+
<joint name="hip_pitch_2" value="1.25409"/>
|
| 65 |
+
<joint name="knee_pitch_2" value="1.55576"/>
|
| 66 |
+
<joint name="ankle_pitch_2" value="0.301666"/>
|
| 67 |
+
<joint name="ankle_yaw_2" value="-0.746874"/>
|
| 68 |
+
<joint name="hip_yaw_3" value="0.746874"/>
|
| 69 |
+
<joint name="hip_pitch_3" value="1.25409"/>
|
| 70 |
+
<joint name="knee_pitch_3" value="1.55576"/>
|
| 71 |
+
<joint name="ankle_pitch_3" value="0.301667"/>
|
| 72 |
+
<joint name="ankle_yaw_3" value="-0.746874"/>
|
| 73 |
+
<joint name="hip_yaw_4" value="-0.746874"/>
|
| 74 |
+
<joint name="hip_pitch_4" value="-1.25409"/>
|
| 75 |
+
<joint name="knee_pitch_4" value="-1.55576"/>
|
| 76 |
+
<joint name="ankle_pitch_4" value="-0.301667"/>
|
| 77 |
+
<joint name="ankle_yaw_4" value="0.746874"/>
|
| 78 |
+
<joint name="torso_yaw" value="3.56617e-13"/>
|
| 79 |
+
<joint name="velodyne_joint" value="0"/>
|
| 80 |
+
<joint name="d435_head_joint" value="0"/>
|
| 81 |
+
<joint name="j_arm1_1" value="0.520149"/>
|
| 82 |
+
<joint name="j_arm1_2" value="0.320865"/>
|
| 83 |
+
<joint name="j_arm1_3" value="0.274669"/>
|
| 84 |
+
<joint name="j_arm1_4" value="-2.23604"/>
|
| 85 |
+
<joint name="j_arm1_5" value="0.0500815"/>
|
| 86 |
+
<joint name="j_arm1_6" value="-0.781461"/>
|
| 87 |
+
<joint name="j_arm2_1" value="0.520149"/>
|
| 88 |
+
<joint name="j_arm2_2" value="-0.320865"/>
|
| 89 |
+
<joint name="j_arm2_3" value="-0.274669"/>
|
| 90 |
+
<joint name="j_arm2_4" value="-2.23604"/>
|
| 91 |
+
<joint name="j_arm2_5" value="-0.0500815"/>
|
| 92 |
+
<joint name="j_arm2_6" value="-0.781461"/>
|
| 93 |
+
<joint name="j_wheel_1" value="0.0"/>
|
| 94 |
+
<joint name="j_wheel_2" value="0.0"/>
|
| 95 |
+
<joint name="j_wheel_3" value="0.0"/>
|
| 96 |
+
<joint name="j_wheel_4" value="0.0"/>
|
| 97 |
+
<xacro:if value="${END_EFFECTOR_LEFT == 'dagana'}">
|
| 98 |
+
<joint name="dagana_1_claw_joint" value="0"/>
|
| 99 |
+
</xacro:if>
|
| 100 |
+
<xacro:if value="${END_EFFECTOR_RIGHT == 'dagana'}">
|
| 101 |
+
<joint name="dagana_2_claw_joint" value="0"/>
|
| 102 |
+
</xacro:if>
|
| 103 |
+
|
| 104 |
+
</group_state> -->
|
| 105 |
+
<!-- Balanced weight homing -->
|
| 106 |
+
<group_state group="chains" name="home">
|
| 107 |
+
<joint name="hip_yaw_1" value="-0.5"/>
|
| 108 |
+
<joint name="hip_pitch_1" value="-1.37"/>
|
| 109 |
+
<joint name="knee_pitch_1" value="-1.34"/>
|
| 110 |
+
<joint name="ankle_pitch_1" value="-0.03"/>
|
| 111 |
+
<joint name="ankle_yaw_1" value="0.6"/>
|
| 112 |
+
<joint name="hip_yaw_2" value="0.5"/>
|
| 113 |
+
<joint name="hip_pitch_2" value="1.37"/>
|
| 114 |
+
<joint name="knee_pitch_2" value="1.34"/>
|
| 115 |
+
<joint name="ankle_pitch_2" value="-0.03"/>
|
| 116 |
+
<joint name="ankle_yaw_2" value="-0.6"/>
|
| 117 |
+
<joint name="hip_yaw_3" value="1.28"/>
|
| 118 |
+
<joint name="hip_pitch_3" value="1.29"/>
|
| 119 |
+
<joint name="knee_pitch_3" value="1.71"/>
|
| 120 |
+
<joint name="ankle_pitch_3" value="0.43"/>
|
| 121 |
+
<joint name="ankle_yaw_3" value="-1.3"/>
|
| 122 |
+
<joint name="hip_yaw_4" value="-1.28"/>
|
| 123 |
+
<joint name="hip_pitch_4" value="-1.29"/>
|
| 124 |
+
<joint name="knee_pitch_4" value="-1.71"/>
|
| 125 |
+
<joint name="ankle_pitch_4" value="-0.43"/>
|
| 126 |
+
<joint name="ankle_yaw_4" value="1.3"/>
|
| 127 |
+
<joint name="torso_yaw" value="3.56617e-13"/>
|
| 128 |
+
<joint name="velodyne_joint" value="0"/>
|
| 129 |
+
<joint name="d435_head_joint" value="0"/>
|
| 130 |
+
<joint name="j_arm1_1" value="0.520149"/>
|
| 131 |
+
<joint name="j_arm1_2" value="0.320865"/>
|
| 132 |
+
<joint name="j_arm1_3" value="0.274669"/>
|
| 133 |
+
<joint name="j_arm1_4" value="-2.23604"/>
|
| 134 |
+
<joint name="j_arm1_5" value="0.0500815"/>
|
| 135 |
+
<joint name="j_arm1_6" value="-0.781461"/>
|
| 136 |
+
<joint name="j_arm2_1" value="0.520149"/>
|
| 137 |
+
<joint name="j_arm2_2" value="-0.320865"/>
|
| 138 |
+
<joint name="j_arm2_3" value="-0.274669"/>
|
| 139 |
+
<joint name="j_arm2_4" value="-2.23604"/>
|
| 140 |
+
<joint name="j_arm2_5" value="-0.0500815"/>
|
| 141 |
+
<joint name="j_arm2_6" value="-0.781461"/>
|
| 142 |
+
<joint name="j_wheel_1" value="0.0"/>
|
| 143 |
+
<joint name="j_wheel_2" value="0.0"/>
|
| 144 |
+
<joint name="j_wheel_3" value="0.0"/>
|
| 145 |
+
<joint name="j_wheel_4" value="0.0"/>
|
| 146 |
+
</group_state>
|
| 147 |
+
</robot>
|
bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/centauro_big_wheels_ub_2026_02_21_13_59_20_ID.urdf
ADDED
|
@@ -0,0 +1,1569 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?xml version="1.0" ?>
|
| 2 |
+
<!-- =================================================================================== -->
|
| 3 |
+
<!-- | This document was autogenerated by xacro from /root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/urdf/centauro.urdf.xacro | -->
|
| 4 |
+
<!-- | EDITING THIS FILE BY HAND IS NOT RECOMMENDED | -->
|
| 5 |
+
<!-- =================================================================================== -->
|
| 6 |
+
<robot name="centauro">
|
| 7 |
+
<!-- none, ball, dagana_fixed, dagana -->
|
| 8 |
+
<!-- scaling facto for available peack torque link side, from 0 to 1 -->
|
| 9 |
+
<material name="black">
|
| 10 |
+
<color rgba="0.4 0.4 0.4 1"/>
|
| 11 |
+
</material>
|
| 12 |
+
<material name="dark">
|
| 13 |
+
<color rgba="0.1 0.1 0.1 1"/>
|
| 14 |
+
</material>
|
| 15 |
+
<material name="dark_grey">
|
| 16 |
+
<color rgba="0.2 0.2 0.2 1"/>
|
| 17 |
+
</material>
|
| 18 |
+
<!-- Note that the "23" suffix denotes the new bigger-size wheel -->
|
| 19 |
+
<!-- ??? -->
|
| 20 |
+
<!-- ??? -->
|
| 21 |
+
<!-- Origin -->
|
| 22 |
+
<!-- <xacro:property name="hip_yaw_lower" value="${[-2.827,-2.583, -2.583 ,-2.827]}"/>
|
| 23 |
+
<xacro:property name="hip_yaw_upper" value="${[ 2.583, 2.827, 2.827 , 2.583]}"/> -->
|
| 24 |
+
<link name="base_link"/>
|
| 25 |
+
<joint name="base_joint" type="fixed">
|
| 26 |
+
<parent link="base_link"/>
|
| 27 |
+
<child link="pelvis"/>
|
| 28 |
+
<origin rpy="0 0 0" xyz="0 0 0"/>
|
| 29 |
+
</joint>
|
| 30 |
+
<link name="pelvis">
|
| 31 |
+
<inertial>
|
| 32 |
+
<origin xyz="-0.0016320207 0.0026534004000000003 0.079167428"/>
|
| 33 |
+
<mass value="26.584529"/>
|
| 34 |
+
<inertia ixx="0.39195477" ixy="0.024781258999999996" ixz="0.017108606999999998" iyy="1.0000708999999999" iyz="0.0052627106000000005" izz="1.0679988999999999"/>
|
| 35 |
+
</inertial>
|
| 36 |
+
<visual>
|
| 37 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 38 |
+
<geometry>
|
| 39 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/pelvis.stl" scale="0.001 0.001 0.001"/>
|
| 40 |
+
</geometry>
|
| 41 |
+
</visual>
|
| 42 |
+
<collision>
|
| 43 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 44 |
+
<geometry>
|
| 45 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/pelvis_reduced.stl" scale="0.001 0.001 0.001"/>
|
| 46 |
+
</geometry>
|
| 47 |
+
</collision>
|
| 48 |
+
</link>
|
| 49 |
+
<link name="imu_link"/>
|
| 50 |
+
<joint name="imu_joint" type="fixed">
|
| 51 |
+
<parent link="pelvis"/>
|
| 52 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.248316 0.0 0.015"/>
|
| 53 |
+
<child link="imu_link"/>
|
| 54 |
+
</joint>
|
| 55 |
+
<!-- torso links -->
|
| 56 |
+
<link name="torso_2">
|
| 57 |
+
<inertial>
|
| 58 |
+
<origin xyz="-0.019497794 0.0045317835 0.13768283"/>
|
| 59 |
+
<mass value="12.553731"/>
|
| 60 |
+
<inertia ixx="0.063643392" ixy="8.939e-05" ixz="-0.00086873" iyy="0.02680235" iyz="-4.657e-05" izz="0.04743015"/>
|
| 61 |
+
</inertial>
|
| 62 |
+
<visual>
|
| 63 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 64 |
+
<geometry>
|
| 65 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/link1_no_head.stl" scale="0.001 0.001 0.001"/>
|
| 66 |
+
</geometry>
|
| 67 |
+
</visual>
|
| 68 |
+
<collision>
|
| 69 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 70 |
+
<geometry>
|
| 71 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/link1_no_head.stl" scale="0.001 0.001 0.001"/>
|
| 72 |
+
</geometry>
|
| 73 |
+
</collision>
|
| 74 |
+
</link>
|
| 75 |
+
<!-- /torso links -->
|
| 76 |
+
<!-- torso joints -->
|
| 77 |
+
<joint name="torso_yaw" type="revolute">
|
| 78 |
+
<parent link="pelvis"/>
|
| 79 |
+
<origin xyz="0.2 0.0 0.256"/>
|
| 80 |
+
<child link="torso_2"/>
|
| 81 |
+
<axis xyz="0 0 1"/>
|
| 82 |
+
<limit effort="147" lower="-2.618" upper="2.618" velocity="5.7"/>
|
| 83 |
+
<!-- TODO -->
|
| 84 |
+
</joint>
|
| 85 |
+
<!-- /torso joints -->
|
| 86 |
+
<!-- /macro arms -->
|
| 87 |
+
<!-- LINKS -->
|
| 88 |
+
<!-- shoulder yaw-roll-->
|
| 89 |
+
<link name="arm1_1">
|
| 90 |
+
<inertial>
|
| 91 |
+
<origin xyz="-0.0074457212 0.03410796 0.00010978102"/>
|
| 92 |
+
<mass value="1.9628675"/>
|
| 93 |
+
<inertia ixx="0.0053547717" ixy="0.00036428926" ixz="1.5089568e-05" iyy="0.0033923328" iyz="5.5692312e-05" izz="0.0068921413"/>
|
| 94 |
+
</inertial>
|
| 95 |
+
<visual>
|
| 96 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 97 |
+
<geometry>
|
| 98 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/ShoulderPitch.STL" scale="0.001 -0.001 0.001"/>
|
| 99 |
+
</geometry>
|
| 100 |
+
<material name="dark_grey"/>
|
| 101 |
+
</visual>
|
| 102 |
+
<collision>
|
| 103 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 104 |
+
<geometry>
|
| 105 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/ShoulderPitch.STL" scale="0.001 -0.001 0.001"/>
|
| 106 |
+
</geometry>
|
| 107 |
+
</collision>
|
| 108 |
+
</link>
|
| 109 |
+
<!-- shoulder yaw-roll-->
|
| 110 |
+
<!-- shoulder roll-pitch-->
|
| 111 |
+
<link name="arm1_2">
|
| 112 |
+
<inertial>
|
| 113 |
+
<origin xyz="0.058142302 5.7450803e-05 -0.077477683"/>
|
| 114 |
+
<mass value="1.8595811"/>
|
| 115 |
+
<inertia ixx="0.013776643" ixy="3.7788675e-05" ixz="0.0037690171" iyy="0.015677464" iyz="-9.4893549e-06" izz="0.0046317657"/>
|
| 116 |
+
</inertial>
|
| 117 |
+
<visual>
|
| 118 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 119 |
+
<geometry>
|
| 120 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/ShoulderRoll.STL" scale="0.001 -0.001 0.001"/>
|
| 121 |
+
</geometry>
|
| 122 |
+
</visual>
|
| 123 |
+
<collision>
|
| 124 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 125 |
+
<geometry>
|
| 126 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/ShoulderRoll.STL" scale="0.001 -0.001 0.001"/>
|
| 127 |
+
</geometry>
|
| 128 |
+
</collision>
|
| 129 |
+
</link>
|
| 130 |
+
<!-- shoulder roll-pitch-->
|
| 131 |
+
<!-- shoulder-elbow -->
|
| 132 |
+
<link name="arm1_3">
|
| 133 |
+
<inertial>
|
| 134 |
+
<origin xyz="0.014625194 0.0008172672 -0.028333545"/>
|
| 135 |
+
<mass value="1.6678109"/>
|
| 136 |
+
<inertia ixx="0.0064480435" ixy="-0.00015639093" ixz="0.0012205359" iyy="0.0073372077" iyz="8.9941532e-05" izz="0.0036738448"/>
|
| 137 |
+
</inertial>
|
| 138 |
+
<visual>
|
| 139 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 140 |
+
<geometry>
|
| 141 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/ShoulderYaw.STL" scale="0.001 -0.001 0.001"/>
|
| 142 |
+
</geometry>
|
| 143 |
+
<material name="dark_grey"/>
|
| 144 |
+
</visual>
|
| 145 |
+
<collision>
|
| 146 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 147 |
+
<geometry>
|
| 148 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/ShoulderYaw.STL" scale="0.001 -0.001 0.001"/>
|
| 149 |
+
</geometry>
|
| 150 |
+
</collision>
|
| 151 |
+
</link>
|
| 152 |
+
<!-- /shoulder-elbow -->
|
| 153 |
+
<!-- elbow yaw-pitch -->
|
| 154 |
+
<link name="arm1_4">
|
| 155 |
+
<inertial>
|
| 156 |
+
<origin xyz="-0.0076833067 -0.040302205 -0.043492779"/>
|
| 157 |
+
<mass value="1.3157289"/>
|
| 158 |
+
<inertia ixx="0.004330394" ixy="-0.00011737391" ixz="-0.00041923199" iyy="0.0038539919" iyz="-0.00079573038" izz="0.0017594689"/>
|
| 159 |
+
</inertial>
|
| 160 |
+
<visual>
|
| 161 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 162 |
+
<geometry>
|
| 163 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/Elbow.STL" scale="0.001 -0.001 0.001"/>
|
| 164 |
+
</geometry>
|
| 165 |
+
</visual>
|
| 166 |
+
<collision>
|
| 167 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 168 |
+
<geometry>
|
| 169 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/Elbow.STL" scale="0.001 -0.001 0.001"/>
|
| 170 |
+
</geometry>
|
| 171 |
+
</collision>
|
| 172 |
+
</link>
|
| 173 |
+
<!-- /elbow yaw-pitch -->
|
| 174 |
+
<!-- elbow-wrist -->
|
| 175 |
+
<link name="arm1_5">
|
| 176 |
+
<inertial>
|
| 177 |
+
<origin xyz="-0.00011079615 0.011590836 -0.07816026"/>
|
| 178 |
+
<mass value="1.4908547"/>
|
| 179 |
+
<inertia ixx="0.0085692128" ixy="1.7856252e-05" ixz="1.9379365e-05" iyy="0.0077454159" iyz="-0.00032860094" izz="0.0027441921"/>
|
| 180 |
+
</inertial>
|
| 181 |
+
<visual>
|
| 182 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 183 |
+
<geometry>
|
| 184 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/Forearm.STL" scale="0.001 -0.001 0.001"/>
|
| 185 |
+
</geometry>
|
| 186 |
+
<material name="dark_grey"/>
|
| 187 |
+
</visual>
|
| 188 |
+
<collision>
|
| 189 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 190 |
+
<geometry>
|
| 191 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/Forearm.STL" scale="0.001 -0.001 0.001"/>
|
| 192 |
+
</geometry>
|
| 193 |
+
</collision>
|
| 194 |
+
</link>
|
| 195 |
+
<!-- /elbow-wrist -->
|
| 196 |
+
<!-- wrist yaw-pitch -->
|
| 197 |
+
<link name="arm1_6">
|
| 198 |
+
<inertial>
|
| 199 |
+
<origin xyz="-4.6502396e-06 -0.038014094 -0.069926878"/>
|
| 200 |
+
<mass value="1.1263612"/>
|
| 201 |
+
<inertia ixx="0.0051871784" ixy="2.724437e-05" ixz="2.2833496e-06" iyy="0.0048037789" iyz="-0.00072165653" izz="0.0012771388"/>
|
| 202 |
+
</inertial>
|
| 203 |
+
<visual>
|
| 204 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 205 |
+
<geometry>
|
| 206 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/wrist_pitch_right.stl" scale="0.001 -0.001 0.001"/>
|
| 207 |
+
</geometry>
|
| 208 |
+
</visual>
|
| 209 |
+
<collision>
|
| 210 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 211 |
+
<geometry>
|
| 212 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/wrist_pitch_right.stl" scale="0.001 -0.001 0.001"/>
|
| 213 |
+
</geometry>
|
| 214 |
+
</collision>
|
| 215 |
+
</link>
|
| 216 |
+
<!-- /wrist yaw-pitch -->
|
| 217 |
+
<!-- <link name="arm${arm_num}_7">
|
| 218 |
+
<inertial>
|
| 219 |
+
<origin xyz="${Wrist_3_x} ${rot*Wrist_3_y} ${Wrist_3_z}"/>
|
| 220 |
+
<mass value="${Wrist_3_mass}"/>
|
| 221 |
+
<inertia ixx="${Wrist_3_xx}" ixy="${rot*Wrist_3_xy}" ixz="${Wrist_3_xz}" iyy="${Wrist_3_yy}" iyz="${rot*Wrist_3_yz}" izz="${Wrist_3_zz}"/>
|
| 222 |
+
</inertial>
|
| 223 |
+
|
| 224 |
+
<visual>
|
| 225 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
|
| 226 |
+
<geometry>
|
| 227 |
+
<mesh filename="${MESH_PATH}/ForearmYaw.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 228 |
+
</geometry>
|
| 229 |
+
<material name="dark_grey"/>
|
| 230 |
+
</visual>
|
| 231 |
+
|
| 232 |
+
<collision>
|
| 233 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
|
| 234 |
+
<geometry>
|
| 235 |
+
<mesh filename="${MESH_PATH}/simple/ForearmYaw.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 236 |
+
</geometry>
|
| 237 |
+
</collision>
|
| 238 |
+
</link> -->
|
| 239 |
+
<!-- /LINKS -->
|
| 240 |
+
<!-- JOINTS -->
|
| 241 |
+
<!-- shoulder yaw -->
|
| 242 |
+
<joint name="j_arm1_1" type="revolute">
|
| 243 |
+
<parent link="torso_2"/>
|
| 244 |
+
<child link="arm1_1"/>
|
| 245 |
+
<origin rpy="0.174533 0.0 -0.5235988" xyz="0.0457475 0.169137 0.116626"/>
|
| 246 |
+
<axis xyz="0 1 0"/>
|
| 247 |
+
<limit effort="147.0" lower="-3.312" upper="1.615" velocity="3.86"/>
|
| 248 |
+
</joint>
|
| 249 |
+
<!-- /shoulder yaw -->
|
| 250 |
+
<!-- shoulder roll -->
|
| 251 |
+
<joint name="j_arm1_2" type="revolute">
|
| 252 |
+
<parent link="arm1_1"/>
|
| 253 |
+
<child link="arm1_2"/>
|
| 254 |
+
<origin rpy="-0.1745327 0.0 0.0" xyz="-0.09015 0.062 0.0"/>
|
| 255 |
+
<axis xyz="1 0 0"/>
|
| 256 |
+
<limit effort="147.0" lower="0.02" upper="3.431" velocity="3.86"/>
|
| 257 |
+
</joint>
|
| 258 |
+
<!-- /shoulder roll -->
|
| 259 |
+
<!-- shoulder pitch-->
|
| 260 |
+
<joint name="j_arm1_3" type="revolute">
|
| 261 |
+
<parent link="arm1_2"/>
|
| 262 |
+
<child link="arm1_3"/>
|
| 263 |
+
<origin xyz="0.09015 0.0 -0.21815"/>
|
| 264 |
+
<axis xyz="0 0 1"/>
|
| 265 |
+
<limit effort="147.0" lower="-2.552" upper="2.566" velocity="6.06"/>
|
| 266 |
+
</joint>
|
| 267 |
+
<!-- /shoulder pitch -->
|
| 268 |
+
<!-- elbow yaw -->
|
| 269 |
+
<joint name="j_arm1_4" type="revolute">
|
| 270 |
+
<parent link="arm1_3"/>
|
| 271 |
+
<child link="arm1_4"/>
|
| 272 |
+
<origin xyz="0.045 0.05515 -0.074"/>
|
| 273 |
+
<axis xyz="0 1 0"/>
|
| 274 |
+
<limit effort="147.0" lower="-2.465" upper="0.28" velocity="6.06"/>
|
| 275 |
+
</joint>
|
| 276 |
+
<!-- /elbow yaw -->
|
| 277 |
+
<!-- elbow pitch-->
|
| 278 |
+
<joint name="j_arm1_5" type="revolute">
|
| 279 |
+
<parent link="arm1_4"/>
|
| 280 |
+
<child link="arm1_5"/>
|
| 281 |
+
<origin xyz="-0.015 -0.05515 -0.095"/>
|
| 282 |
+
<axis xyz="0 0 1"/>
|
| 283 |
+
<limit effort="55.0" lower="-2.569" upper="2.562" velocity="11.72"/>
|
| 284 |
+
</joint>
|
| 285 |
+
<!-- /elbow pitch-->
|
| 286 |
+
<!-- wrist yaw-->
|
| 287 |
+
<joint name="j_arm1_6" type="revolute">
|
| 288 |
+
<parent link="arm1_5"/>
|
| 289 |
+
<child link="arm1_6"/>
|
| 290 |
+
<origin xyz="0.0 0.049 -0.156"/>
|
| 291 |
+
<axis xyz="0 1 0"/>
|
| 292 |
+
<limit effort="55.0" lower="-1.529" upper="1.509" velocity="11.72"/>
|
| 293 |
+
</joint>
|
| 294 |
+
<!-- /wrist yaw-->
|
| 295 |
+
<!-- wrist pitch-->
|
| 296 |
+
<!-- <joint name="j_arm${arm_num}_7" type="fixed">
|
| 297 |
+
<parent link="arm${arm_num}_6"/>
|
| 298 |
+
<child link="arm${arm_num}_7"/>
|
| 299 |
+
<origin xyz="${Wrist_3_Ox} ${rot*Wrist_3_Oy} ${Wrist_3_Oz}"/>
|
| 300 |
+
<axis xyz="0 0 1"/>
|
| 301 |
+
<limit lower="${j_arm_7_lower[arm_num-1]}" upper="${j_arm_7_upper[arm_num-1]}" effort="${j_arm_7_torque[arm_num-1]}" velocity="${j_arm_7_velocity[arm_num-1]}"/>
|
| 302 |
+
</joint> -->
|
| 303 |
+
<!-- wrist pitch-->
|
| 304 |
+
<!-- force-troque sensor -->
|
| 305 |
+
<!-- end-effector -->
|
| 306 |
+
<!-- wrist pitch-->
|
| 307 |
+
<!-- <joint name="j_ft_${arm_num}" type="fixed">
|
| 308 |
+
<parent link="arm${arm_num}_7"/>
|
| 309 |
+
<child link="ft_arm${arm_num}"/>
|
| 310 |
+
<origin xyz="${Ft_arm_Ox} ${Ft_arm_Oy} ${Ft_arm_Oz}" rpy="${Ft_arm_roll} ${Ft_arm_pitch} ${Ft_arm_yaw}" />
|
| 311 |
+
<axis xyz="0 0 1"/>
|
| 312 |
+
<limit lower="0.0" upper="0.0" effort="0" velocity="0"/>
|
| 313 |
+
</joint> -->
|
| 314 |
+
<!-- wrist pitch-->
|
| 315 |
+
<!-- <link name="ft_arm${arm_num}">
|
| 316 |
+
<inertial>
|
| 317 |
+
<origin xyz="${Ft_arm_x} ${rot*Ft_arm_y} ${Ft_arm_z}"/>
|
| 318 |
+
<mass value="${Ft_arm_mass}"/>
|
| 319 |
+
<inertia ixx="${Ft_arm_xx}" ixy="${rot*Ft_arm_xy}" ixz="${Ft_arm_xz}" iyy="${Ft_arm_yy}" iyz="${rot*Ft_arm_yz}" izz="${Ft_arm_zz}"/>
|
| 320 |
+
</inertial> -->
|
| 321 |
+
<!--visual>
|
| 322 |
+
<origin xyz="0.0 0.0 0.0" rpy="${PI} 0.0 0.0"/>
|
| 323 |
+
<geometry>
|
| 324 |
+
<mesh filename="${MESH_PATH}/Wrist.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 325 |
+
</geometry>
|
| 326 |
+
</visual-->
|
| 327 |
+
<!--collision>
|
| 328 |
+
<origin xyz="0.0 0.0 0.0" rpy="${PI} 0.0 0.0"/>
|
| 329 |
+
<geometry>
|
| 330 |
+
<mesh filename="${MESH_PATH}/simple/Wrist.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 331 |
+
</geometry>
|
| 332 |
+
</collision-->
|
| 333 |
+
<!-- </link> -->
|
| 334 |
+
<!-- LINKS -->
|
| 335 |
+
<!-- shoulder yaw-roll-->
|
| 336 |
+
<link name="arm2_1">
|
| 337 |
+
<inertial>
|
| 338 |
+
<origin xyz="-0.0074457212 -0.03410796 0.00010978102"/>
|
| 339 |
+
<mass value="1.9628675"/>
|
| 340 |
+
<inertia ixx="0.0053547717" ixy="-0.00036428926" ixz="1.5089568e-05" iyy="0.0033923328" iyz="-5.5692312e-05" izz="0.0068921413"/>
|
| 341 |
+
</inertial>
|
| 342 |
+
<visual>
|
| 343 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 344 |
+
<geometry>
|
| 345 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/ShoulderPitch.STL" scale="0.001 0.001 0.001"/>
|
| 346 |
+
</geometry>
|
| 347 |
+
<material name="dark_grey"/>
|
| 348 |
+
</visual>
|
| 349 |
+
<collision>
|
| 350 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 351 |
+
<geometry>
|
| 352 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/ShoulderPitch.STL" scale="0.001 0.001 0.001"/>
|
| 353 |
+
</geometry>
|
| 354 |
+
</collision>
|
| 355 |
+
</link>
|
| 356 |
+
<!-- shoulder yaw-roll-->
|
| 357 |
+
<!-- shoulder roll-pitch-->
|
| 358 |
+
<link name="arm2_2">
|
| 359 |
+
<inertial>
|
| 360 |
+
<origin xyz="0.058142302 -5.7450803e-05 -0.077477683"/>
|
| 361 |
+
<mass value="1.8595811"/>
|
| 362 |
+
<inertia ixx="0.013776643" ixy="-3.7788675e-05" ixz="0.0037690171" iyy="0.015677464" iyz="9.4893549e-06" izz="0.0046317657"/>
|
| 363 |
+
</inertial>
|
| 364 |
+
<visual>
|
| 365 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 366 |
+
<geometry>
|
| 367 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/ShoulderRoll.STL" scale="0.001 0.001 0.001"/>
|
| 368 |
+
</geometry>
|
| 369 |
+
</visual>
|
| 370 |
+
<collision>
|
| 371 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 372 |
+
<geometry>
|
| 373 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/ShoulderRoll.STL" scale="0.001 0.001 0.001"/>
|
| 374 |
+
</geometry>
|
| 375 |
+
</collision>
|
| 376 |
+
</link>
|
| 377 |
+
<!-- shoulder roll-pitch-->
|
| 378 |
+
<!-- shoulder-elbow -->
|
| 379 |
+
<link name="arm2_3">
|
| 380 |
+
<inertial>
|
| 381 |
+
<origin xyz="0.014625194 -0.0008172672 -0.028333545"/>
|
| 382 |
+
<mass value="1.6678109"/>
|
| 383 |
+
<inertia ixx="0.0064480435" ixy="0.00015639093" ixz="0.0012205359" iyy="0.0073372077" iyz="-8.9941532e-05" izz="0.0036738448"/>
|
| 384 |
+
</inertial>
|
| 385 |
+
<visual>
|
| 386 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 387 |
+
<geometry>
|
| 388 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/ShoulderYaw.STL" scale="0.001 0.001 0.001"/>
|
| 389 |
+
</geometry>
|
| 390 |
+
<material name="dark_grey"/>
|
| 391 |
+
</visual>
|
| 392 |
+
<collision>
|
| 393 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 394 |
+
<geometry>
|
| 395 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/ShoulderYaw.STL" scale="0.001 0.001 0.001"/>
|
| 396 |
+
</geometry>
|
| 397 |
+
</collision>
|
| 398 |
+
</link>
|
| 399 |
+
<!-- /shoulder-elbow -->
|
| 400 |
+
<!-- elbow yaw-pitch -->
|
| 401 |
+
<link name="arm2_4">
|
| 402 |
+
<inertial>
|
| 403 |
+
<origin xyz="-0.0076833067 0.040302205 -0.043492779"/>
|
| 404 |
+
<mass value="1.3157289"/>
|
| 405 |
+
<inertia ixx="0.004330394" ixy="0.00011737391" ixz="-0.00041923199" iyy="0.0038539919" iyz="0.00079573038" izz="0.0017594689"/>
|
| 406 |
+
</inertial>
|
| 407 |
+
<visual>
|
| 408 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 409 |
+
<geometry>
|
| 410 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/Elbow.STL" scale="0.001 0.001 0.001"/>
|
| 411 |
+
</geometry>
|
| 412 |
+
</visual>
|
| 413 |
+
<collision>
|
| 414 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 415 |
+
<geometry>
|
| 416 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/Elbow.STL" scale="0.001 0.001 0.001"/>
|
| 417 |
+
</geometry>
|
| 418 |
+
</collision>
|
| 419 |
+
</link>
|
| 420 |
+
<!-- /elbow yaw-pitch -->
|
| 421 |
+
<!-- elbow-wrist -->
|
| 422 |
+
<link name="arm2_5">
|
| 423 |
+
<inertial>
|
| 424 |
+
<origin xyz="-0.00011079615 -0.011590836 -0.07816026"/>
|
| 425 |
+
<mass value="1.4908547"/>
|
| 426 |
+
<inertia ixx="0.0085692128" ixy="-1.7856252e-05" ixz="1.9379365e-05" iyy="0.0077454159" iyz="0.00032860094" izz="0.0027441921"/>
|
| 427 |
+
</inertial>
|
| 428 |
+
<visual>
|
| 429 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 430 |
+
<geometry>
|
| 431 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/Forearm.STL" scale="0.001 0.001 0.001"/>
|
| 432 |
+
</geometry>
|
| 433 |
+
<material name="dark_grey"/>
|
| 434 |
+
</visual>
|
| 435 |
+
<collision>
|
| 436 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 437 |
+
<geometry>
|
| 438 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/Forearm.STL" scale="0.001 0.001 0.001"/>
|
| 439 |
+
</geometry>
|
| 440 |
+
</collision>
|
| 441 |
+
</link>
|
| 442 |
+
<!-- /elbow-wrist -->
|
| 443 |
+
<!-- wrist yaw-pitch -->
|
| 444 |
+
<link name="arm2_6">
|
| 445 |
+
<inertial>
|
| 446 |
+
<origin xyz="-4.6502396e-06 0.038014094 -0.069926878"/>
|
| 447 |
+
<mass value="1.1263612"/>
|
| 448 |
+
<inertia ixx="0.0051871784" ixy="-2.724437e-05" ixz="2.2833496e-06" iyy="0.0048037789" iyz="0.00072165653" izz="0.0012771388"/>
|
| 449 |
+
</inertial>
|
| 450 |
+
<visual>
|
| 451 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 452 |
+
<geometry>
|
| 453 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/wrist_pitch_right.stl" scale="0.001 0.001 0.001"/>
|
| 454 |
+
</geometry>
|
| 455 |
+
</visual>
|
| 456 |
+
<collision>
|
| 457 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 458 |
+
<geometry>
|
| 459 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/wrist_pitch_right.stl" scale="0.001 0.001 0.001"/>
|
| 460 |
+
</geometry>
|
| 461 |
+
</collision>
|
| 462 |
+
</link>
|
| 463 |
+
<!-- /wrist yaw-pitch -->
|
| 464 |
+
<!-- <link name="arm${arm_num}_7">
|
| 465 |
+
<inertial>
|
| 466 |
+
<origin xyz="${Wrist_3_x} ${rot*Wrist_3_y} ${Wrist_3_z}"/>
|
| 467 |
+
<mass value="${Wrist_3_mass}"/>
|
| 468 |
+
<inertia ixx="${Wrist_3_xx}" ixy="${rot*Wrist_3_xy}" ixz="${Wrist_3_xz}" iyy="${Wrist_3_yy}" iyz="${rot*Wrist_3_yz}" izz="${Wrist_3_zz}"/>
|
| 469 |
+
</inertial>
|
| 470 |
+
|
| 471 |
+
<visual>
|
| 472 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
|
| 473 |
+
<geometry>
|
| 474 |
+
<mesh filename="${MESH_PATH}/ForearmYaw.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 475 |
+
</geometry>
|
| 476 |
+
<material name="dark_grey"/>
|
| 477 |
+
</visual>
|
| 478 |
+
|
| 479 |
+
<collision>
|
| 480 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0"/>
|
| 481 |
+
<geometry>
|
| 482 |
+
<mesh filename="${MESH_PATH}/simple/ForearmYaw.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 483 |
+
</geometry>
|
| 484 |
+
</collision>
|
| 485 |
+
</link> -->
|
| 486 |
+
<!-- /LINKS -->
|
| 487 |
+
<!-- JOINTS -->
|
| 488 |
+
<!-- shoulder yaw -->
|
| 489 |
+
<joint name="j_arm2_1" type="revolute">
|
| 490 |
+
<parent link="torso_2"/>
|
| 491 |
+
<child link="arm2_1"/>
|
| 492 |
+
<origin rpy="-0.174533 0.0 0.5235988" xyz="0.0457475 -0.169137 0.116626"/>
|
| 493 |
+
<axis xyz="0 1 0"/>
|
| 494 |
+
<limit effort="147.0" lower="-3.3458" upper="1.6012" velocity="3.86"/>
|
| 495 |
+
</joint>
|
| 496 |
+
<!-- /shoulder yaw -->
|
| 497 |
+
<!-- shoulder roll -->
|
| 498 |
+
<joint name="j_arm2_2" type="revolute">
|
| 499 |
+
<parent link="arm2_1"/>
|
| 500 |
+
<child link="arm2_2"/>
|
| 501 |
+
<origin rpy="0.1745327 0.0 0.0" xyz="-0.09015 -0.062 0.0"/>
|
| 502 |
+
<axis xyz="1 0 0"/>
|
| 503 |
+
<limit effort="147.0" lower="-3.4258" upper="-0.0138" velocity="3.86"/>
|
| 504 |
+
</joint>
|
| 505 |
+
<!-- /shoulder roll -->
|
| 506 |
+
<!-- shoulder pitch-->
|
| 507 |
+
<joint name="j_arm2_3" type="revolute">
|
| 508 |
+
<parent link="arm2_2"/>
|
| 509 |
+
<child link="arm2_3"/>
|
| 510 |
+
<origin xyz="0.09015 0.0 -0.21815"/>
|
| 511 |
+
<axis xyz="0 0 1"/>
|
| 512 |
+
<limit effort="147.0" lower="-2.5614" upper="2.5606" velocity="6.06"/>
|
| 513 |
+
</joint>
|
| 514 |
+
<!-- /shoulder pitch -->
|
| 515 |
+
<!-- elbow yaw -->
|
| 516 |
+
<joint name="j_arm2_4" type="revolute">
|
| 517 |
+
<parent link="arm2_3"/>
|
| 518 |
+
<child link="arm2_4"/>
|
| 519 |
+
<origin xyz="0.045 -0.05515 -0.074"/>
|
| 520 |
+
<axis xyz="0 1 0"/>
|
| 521 |
+
<limit effort="147.0" lower="-2.4794" upper="0.2886" velocity="6.06"/>
|
| 522 |
+
</joint>
|
| 523 |
+
<!-- /elbow yaw -->
|
| 524 |
+
<!-- elbow pitch-->
|
| 525 |
+
<joint name="j_arm2_5" type="revolute">
|
| 526 |
+
<parent link="arm2_4"/>
|
| 527 |
+
<child link="arm2_5"/>
|
| 528 |
+
<origin xyz="-0.015 0.05515 -0.095"/>
|
| 529 |
+
<axis xyz="0 0 1"/>
|
| 530 |
+
<limit effort="55.0" lower="-2.5394" upper="2.5546" velocity="11.72"/>
|
| 531 |
+
</joint>
|
| 532 |
+
<!-- /elbow pitch-->
|
| 533 |
+
<!-- wrist yaw-->
|
| 534 |
+
<joint name="j_arm2_6" type="revolute">
|
| 535 |
+
<parent link="arm2_5"/>
|
| 536 |
+
<child link="arm2_6"/>
|
| 537 |
+
<origin xyz="0.0 -0.049 -0.156"/>
|
| 538 |
+
<axis xyz="0 1 0"/>
|
| 539 |
+
<limit effort="55.0" lower="-1.5154" upper="1.5156" velocity="11.72"/>
|
| 540 |
+
</joint>
|
| 541 |
+
<!-- /wrist yaw-->
|
| 542 |
+
<!-- wrist pitch-->
|
| 543 |
+
<!-- <joint name="j_arm${arm_num}_7" type="fixed">
|
| 544 |
+
<parent link="arm${arm_num}_6"/>
|
| 545 |
+
<child link="arm${arm_num}_7"/>
|
| 546 |
+
<origin xyz="${Wrist_3_Ox} ${rot*Wrist_3_Oy} ${Wrist_3_Oz}"/>
|
| 547 |
+
<axis xyz="0 0 1"/>
|
| 548 |
+
<limit lower="${j_arm_7_lower[arm_num-1]}" upper="${j_arm_7_upper[arm_num-1]}" effort="${j_arm_7_torque[arm_num-1]}" velocity="${j_arm_7_velocity[arm_num-1]}"/>
|
| 549 |
+
</joint> -->
|
| 550 |
+
<!-- wrist pitch-->
|
| 551 |
+
<!-- force-troque sensor -->
|
| 552 |
+
<!-- end-effector -->
|
| 553 |
+
<!-- wrist pitch-->
|
| 554 |
+
<!-- <joint name="j_ft_${arm_num}" type="fixed">
|
| 555 |
+
<parent link="arm${arm_num}_7"/>
|
| 556 |
+
<child link="ft_arm${arm_num}"/>
|
| 557 |
+
<origin xyz="${Ft_arm_Ox} ${Ft_arm_Oy} ${Ft_arm_Oz}" rpy="${Ft_arm_roll} ${Ft_arm_pitch} ${Ft_arm_yaw}" />
|
| 558 |
+
<axis xyz="0 0 1"/>
|
| 559 |
+
<limit lower="0.0" upper="0.0" effort="0" velocity="0"/>
|
| 560 |
+
</joint> -->
|
| 561 |
+
<!-- wrist pitch-->
|
| 562 |
+
<!-- <link name="ft_arm${arm_num}">
|
| 563 |
+
<inertial>
|
| 564 |
+
<origin xyz="${Ft_arm_x} ${rot*Ft_arm_y} ${Ft_arm_z}"/>
|
| 565 |
+
<mass value="${Ft_arm_mass}"/>
|
| 566 |
+
<inertia ixx="${Ft_arm_xx}" ixy="${rot*Ft_arm_xy}" ixz="${Ft_arm_xz}" iyy="${Ft_arm_yy}" iyz="${rot*Ft_arm_yz}" izz="${Ft_arm_zz}"/>
|
| 567 |
+
</inertial> -->
|
| 568 |
+
<!--visual>
|
| 569 |
+
<origin xyz="0.0 0.0 0.0" rpy="${PI} 0.0 0.0"/>
|
| 570 |
+
<geometry>
|
| 571 |
+
<mesh filename="${MESH_PATH}/Wrist.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 572 |
+
</geometry>
|
| 573 |
+
</visual-->
|
| 574 |
+
<!--collision>
|
| 575 |
+
<origin xyz="0.0 0.0 0.0" rpy="${PI} 0.0 0.0"/>
|
| 576 |
+
<geometry>
|
| 577 |
+
<mesh filename="${MESH_PATH}/simple/Wrist.STL" scale="0.001 ${-rot*0.001} 0.001" />
|
| 578 |
+
</geometry>
|
| 579 |
+
</collision-->
|
| 580 |
+
<!-- </link> -->
|
| 581 |
+
<link name="ball1">
|
| 582 |
+
<inertial>
|
| 583 |
+
<origin rpy="0 0 0" xyz="-1.0072498e-05 3.7590658e-05 0.019772332"/>
|
| 584 |
+
<mass value="1.27"/>
|
| 585 |
+
<inertia ixx="0.0023061092" ixy="2.9181758e-07" ixz="-2.1246683999999997e-07" iyy="0.0023053155000000002" iyz="7.9290978e-07" izz="0.0030675615999999997"/>
|
| 586 |
+
</inertial>
|
| 587 |
+
<visual>
|
| 588 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 589 |
+
<geometry name="ball1_visual">
|
| 590 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/BallHand.stl" scale="0.001 0.001 0.001"/>
|
| 591 |
+
</geometry>
|
| 592 |
+
<material name="dark_grey"/>
|
| 593 |
+
</visual>
|
| 594 |
+
<collision>
|
| 595 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 596 |
+
<geometry name="ball1_collision">
|
| 597 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/BallHand.stl" scale="0.001 0.001 0.001"/>
|
| 598 |
+
</geometry>
|
| 599 |
+
</collision>
|
| 600 |
+
</link>
|
| 601 |
+
<link name="ball1_tip"/>
|
| 602 |
+
<joint name="j_arm1_8" type="fixed">
|
| 603 |
+
<parent link="arm1_6"/>
|
| 604 |
+
<child link="ball1"/>
|
| 605 |
+
<origin rpy="0. 0. 0." xyz="0. -0.05 -0.105"/>
|
| 606 |
+
</joint>
|
| 607 |
+
<joint name="j_ball1_tip" type="fixed">
|
| 608 |
+
<parent link="ball1"/>
|
| 609 |
+
<child link="ball1_tip"/>
|
| 610 |
+
<origin rpy="0 0 0" xyz="0 0 -0.07"/>
|
| 611 |
+
</joint>
|
| 612 |
+
<!-- add armX_8 link for legacy reasons (same as ballX) -->
|
| 613 |
+
<joint name="j_ball1_fixed" type="fixed">
|
| 614 |
+
<parent link="ball1"/>
|
| 615 |
+
<child link="arm1_8"/>
|
| 616 |
+
</joint>
|
| 617 |
+
<link name="arm1_8">
|
| 618 |
+
<inertial>
|
| 619 |
+
<mass value="0"/>
|
| 620 |
+
<inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0"/>
|
| 621 |
+
</inertial>
|
| 622 |
+
</link>
|
| 623 |
+
<link name="ball2">
|
| 624 |
+
<inertial>
|
| 625 |
+
<origin rpy="0 0 0" xyz="-1.0072498e-05 3.7590658e-05 0.019772332"/>
|
| 626 |
+
<mass value="1.27"/>
|
| 627 |
+
<inertia ixx="0.0023061092" ixy="2.9181758e-07" ixz="-2.1246683999999997e-07" iyy="0.0023053155000000002" iyz="7.9290978e-07" izz="0.0030675615999999997"/>
|
| 628 |
+
</inertial>
|
| 629 |
+
<visual>
|
| 630 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 631 |
+
<geometry name="ball2_visual">
|
| 632 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/BallHand.stl" scale="0.001 0.001 0.001"/>
|
| 633 |
+
</geometry>
|
| 634 |
+
<material name="dark_grey"/>
|
| 635 |
+
</visual>
|
| 636 |
+
<collision>
|
| 637 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 638 |
+
<geometry name="ball2_collision">
|
| 639 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/BallHand.stl" scale="0.001 0.001 0.001"/>
|
| 640 |
+
</geometry>
|
| 641 |
+
</collision>
|
| 642 |
+
</link>
|
| 643 |
+
<link name="ball2_tip"/>
|
| 644 |
+
<joint name="j_arm2_8" type="fixed">
|
| 645 |
+
<parent link="arm2_6"/>
|
| 646 |
+
<child link="ball2"/>
|
| 647 |
+
<origin rpy="0. 0. 0." xyz="0. 0.05 -0.105"/>
|
| 648 |
+
</joint>
|
| 649 |
+
<joint name="j_ball2_tip" type="fixed">
|
| 650 |
+
<parent link="ball2"/>
|
| 651 |
+
<child link="ball2_tip"/>
|
| 652 |
+
<origin rpy="0 0 0" xyz="0 0 -0.07"/>
|
| 653 |
+
</joint>
|
| 654 |
+
<!-- add armX_8 link for legacy reasons (same as ballX) -->
|
| 655 |
+
<joint name="j_ball2_fixed" type="fixed">
|
| 656 |
+
<parent link="ball2"/>
|
| 657 |
+
<child link="arm2_8"/>
|
| 658 |
+
</joint>
|
| 659 |
+
<link name="arm2_8">
|
| 660 |
+
<inertial>
|
| 661 |
+
<mass value="0"/>
|
| 662 |
+
<inertia ixx="0" ixy="0" ixz="0" iyy="0" iyz="0" izz="0"/>
|
| 663 |
+
</inertial>
|
| 664 |
+
</link>
|
| 665 |
+
<!-- LINKS -->
|
| 666 |
+
<link name="neck_1">
|
| 667 |
+
<inertial>
|
| 668 |
+
<origin xyz="0 0 0"/>
|
| 669 |
+
<mass value="0.33878686"/>
|
| 670 |
+
<!-- MASS/INERTIA TO DO -->
|
| 671 |
+
<inertia ixx="0.0003718568" ixy="-9.42983e-05" ixz="-2.80644e-05" iyy="0.0001886879" iyz="-1.54534e-05" izz="0.0005023443"/>
|
| 672 |
+
</inertial>
|
| 673 |
+
<visual>
|
| 674 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 675 |
+
<geometry>
|
| 676 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/head-base_mesh.stl" scale="0.001 0.001 0.001"/>
|
| 677 |
+
</geometry>
|
| 678 |
+
</visual>
|
| 679 |
+
<collision>
|
| 680 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 681 |
+
<geometry>
|
| 682 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/head-base_mesh.stl" scale="0.001 0.001 0.001"/>
|
| 683 |
+
</geometry>
|
| 684 |
+
</collision>
|
| 685 |
+
</link>
|
| 686 |
+
<link name="velodyne_motor">
|
| 687 |
+
<inertial>
|
| 688 |
+
<origin xyz="0 0 0"/>
|
| 689 |
+
<mass value="0.33878686"/>
|
| 690 |
+
<!-- MASS/INERTIA TO DO -->
|
| 691 |
+
<inertia ixx="0.0003718568" ixy="-9.42983e-05" ixz="-2.80644e-05" iyy="0.0001886879" iyz="-1.54534e-05" izz="0.0005023443"/>
|
| 692 |
+
</inertial>
|
| 693 |
+
<visual>
|
| 694 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 695 |
+
<geometry>
|
| 696 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/lidar_mesh.stl" scale="0.001 0.001 0.001"/>
|
| 697 |
+
</geometry>
|
| 698 |
+
</visual>
|
| 699 |
+
<collision>
|
| 700 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 701 |
+
<geometry>
|
| 702 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/lidar_mesh.stl" scale="0.001 0.001 0.001"/>
|
| 703 |
+
</geometry>
|
| 704 |
+
</collision>
|
| 705 |
+
</link>
|
| 706 |
+
<link name="d435_head_motor">
|
| 707 |
+
<inertial>
|
| 708 |
+
<origin xyz="0 0 0"/>
|
| 709 |
+
<mass value="0.33878686"/>
|
| 710 |
+
<!-- MASS/INERTIA TO DO -->
|
| 711 |
+
<inertia ixx="0.0003718568" ixy="-9.42983e-05" ixz="-2.80644e-05" iyy="0.0001886879" iyz="-1.54534e-05" izz="0.0005023443"/>
|
| 712 |
+
</inertial>
|
| 713 |
+
<visual>
|
| 714 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 715 |
+
<geometry>
|
| 716 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/neck-pitch_mesh.stl" scale="0.001 0.001 0.001"/>
|
| 717 |
+
</geometry>
|
| 718 |
+
</visual>
|
| 719 |
+
<collision>
|
| 720 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0 0.0"/>
|
| 721 |
+
<geometry>
|
| 722 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/simple/neck-pitch_mesh.stl" scale="0.001 0.001 0.001"/>
|
| 723 |
+
</geometry>
|
| 724 |
+
</collision>
|
| 725 |
+
</link>
|
| 726 |
+
<!--JOINTS -->
|
| 727 |
+
<joint name="neck_base" type="fixed">
|
| 728 |
+
<parent link="torso_2"/>
|
| 729 |
+
<origin rpy="0 0 0" xyz="0.0030637045 0.0061607221 0.158"/>
|
| 730 |
+
<child link="neck_1"/>
|
| 731 |
+
<axis xyz="0 0 1"/>
|
| 732 |
+
</joint>
|
| 733 |
+
<joint name="velodyne_joint" type="revolute">
|
| 734 |
+
<parent link="neck_1"/>
|
| 735 |
+
<origin rpy="0 0 0" xyz="0.0822724 0 0.242"/>
|
| 736 |
+
<child link="velodyne_motor"/>
|
| 737 |
+
<axis xyz="0 -1 0"/>
|
| 738 |
+
<limit effort="35" lower="-1.1" upper="1.1" velocity="5.7"/>
|
| 739 |
+
<dynamics friction="10.0"/>
|
| 740 |
+
</joint>
|
| 741 |
+
<joint name="d435_head_joint" type="revolute">
|
| 742 |
+
<parent link="neck_1"/>
|
| 743 |
+
<origin rpy="0 0 0" xyz="0.06 0 0.1375"/>
|
| 744 |
+
<child link="d435_head_motor"/>
|
| 745 |
+
<axis xyz="0 -1 0"/>
|
| 746 |
+
<limit effort="35" lower="-1.1" upper="1.1" velocity="5.7"/>
|
| 747 |
+
<dynamics friction="10.0"/>
|
| 748 |
+
</joint>
|
| 749 |
+
<!-- camera body, with origin at bottom screw mount -->
|
| 750 |
+
<joint name="D435_head_camera_joint" type="fixed">
|
| 751 |
+
<origin rpy="0 0 0" xyz="0.03015 0 -0.0125"/>
|
| 752 |
+
<parent link="d435_head_motor"/>
|
| 753 |
+
<child link="D435_head_camera_bottom_screw_frame"/>
|
| 754 |
+
</joint>
|
| 755 |
+
<link name="D435_head_camera_bottom_screw_frame"/>
|
| 756 |
+
<joint name="D435_head_camera_link_joint" type="fixed">
|
| 757 |
+
<origin rpy="0 0 0" xyz="0 0.0175 0.0125"/>
|
| 758 |
+
<parent link="D435_head_camera_bottom_screw_frame"/>
|
| 759 |
+
<child link="D435_head_camera_link"/>
|
| 760 |
+
</joint>
|
| 761 |
+
<link name="D435_head_camera_link">
|
| 762 |
+
<visual>
|
| 763 |
+
<origin rpy="1.570796326795 0 1.570796326795" xyz="0.0149 -0.0175 0"/>
|
| 764 |
+
<geometry>
|
| 765 |
+
<box size="0.09 0.025 0.02505"/>
|
| 766 |
+
<!-- <mesh filename="${MESH_PATH}/realsense/d435.dae"/> -->
|
| 767 |
+
</geometry>
|
| 768 |
+
<material name="D435_head_camera_aluminum"/>
|
| 769 |
+
</visual>
|
| 770 |
+
<collision>
|
| 771 |
+
<origin rpy="0 0 0" xyz="0 -0.0175 0"/>
|
| 772 |
+
<geometry>
|
| 773 |
+
<box size="0.02505 0.09 0.025"/>
|
| 774 |
+
</geometry>
|
| 775 |
+
</collision>
|
| 776 |
+
<inertial>
|
| 777 |
+
<!-- The following are not reliable values, and should not be used for modeling -->
|
| 778 |
+
<mass value="0.564"/>
|
| 779 |
+
<origin xyz="0 0 0"/>
|
| 780 |
+
<inertia ixx="0.003881243" ixy="0.0" ixz="0.0" iyy="0.000498940" iyz="0.0" izz="0.003879257"/>
|
| 781 |
+
</inertial>
|
| 782 |
+
</link>
|
| 783 |
+
<!-- camera body, with origin at bottom screw mount -->
|
| 784 |
+
<joint name="D435i_camera_joint" type="fixed">
|
| 785 |
+
<origin rpy="0 0.54 0" xyz="0.272 0 0.084"/>
|
| 786 |
+
<parent link="pelvis"/>
|
| 787 |
+
<child link="D435i_camera_bottom_screw_frame"/>
|
| 788 |
+
</joint>
|
| 789 |
+
<link name="D435i_camera_bottom_screw_frame"/>
|
| 790 |
+
<joint name="D435i_camera_link_joint" type="fixed">
|
| 791 |
+
<origin rpy="0 0.0050 -0.008" xyz="0.053 0.0 -0.035"/>
|
| 792 |
+
<parent link="D435i_camera_bottom_screw_frame"/>
|
| 793 |
+
<child link="D435i_camera_link"/>
|
| 794 |
+
</joint>
|
| 795 |
+
<link name="D435i_camera_link">
|
| 796 |
+
<visual>
|
| 797 |
+
<origin rpy="1.570796326795 0 1.570796326795" xyz="0.053 -0.0 0"/>
|
| 798 |
+
<geometry>
|
| 799 |
+
<!-- <box size="${d435_cam_width} ${d435_cam_height} ${d435_cam_depth}"/> -->
|
| 800 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/realsense/d435.dae"/>
|
| 801 |
+
</geometry>
|
| 802 |
+
<material name="D435i_camera_aluminum"/>
|
| 803 |
+
</visual>
|
| 804 |
+
<collision>
|
| 805 |
+
<origin rpy="0 0 0" xyz="0 -0.0 0"/>
|
| 806 |
+
<geometry>
|
| 807 |
+
<box size="0.02505 0.09 0.025"/>
|
| 808 |
+
</geometry>
|
| 809 |
+
</collision>
|
| 810 |
+
<inertial>
|
| 811 |
+
<!-- The following are not reliable values, and should not be used for modeling -->
|
| 812 |
+
<mass value="0.564"/>
|
| 813 |
+
<origin xyz="0 0 0"/>
|
| 814 |
+
<inertia ixx="0.003881243" ixy="0.0" ixz="0.0" iyy="0.000498940" iyz="0.0" izz="0.003879257"/>
|
| 815 |
+
</inertial>
|
| 816 |
+
</link>
|
| 817 |
+
<!-- /macro centauro_wheel -->
|
| 818 |
+
<!-- /macro arms -->
|
| 819 |
+
<!-- /macro legs -->
|
| 820 |
+
<link name="hip1_1">
|
| 821 |
+
<inertial>
|
| 822 |
+
<origin xyz="0.0003595855 0.033338818000000006 -0.059190309"/>
|
| 823 |
+
<mass value="2.3349153"/>
|
| 824 |
+
<!-- org 2 -->
|
| 825 |
+
<inertia ixx="0.0068405374" ixy="1.8572633e-05" ixz="-4.8325972e-05" iyy="0.0026261815" iyz="0.0001564273" izz="0.0066933354"/>
|
| 826 |
+
</inertial>
|
| 827 |
+
<visual>
|
| 828 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 829 |
+
<geometry>
|
| 830 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-yaw.stl" scale="0.001 -0.001 0.001"/>
|
| 831 |
+
</geometry>
|
| 832 |
+
<material name="dark_grey"/>
|
| 833 |
+
</visual>
|
| 834 |
+
<collision>
|
| 835 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 836 |
+
<geometry>
|
| 837 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-yaw.stl" scale="0.001 -0.001 0.001"/>
|
| 838 |
+
</geometry>
|
| 839 |
+
</collision>
|
| 840 |
+
</link>
|
| 841 |
+
<link name="hip2_1">
|
| 842 |
+
<inertial>
|
| 843 |
+
<origin xyz="-4.6285952e-06 -0.2214019 0.03316685"/>
|
| 844 |
+
<mass value="3.4572118"/>
|
| 845 |
+
<!-- org 4.5 -->
|
| 846 |
+
<inertia ixx="0.050469853" ixy="-7.784938699999999e-06" ixz="-9.220580999999999e-06" iyy="0.008181596999999999" iyz="0.0059796848" izz="0.048213808999999996"/>
|
| 847 |
+
</inertial>
|
| 848 |
+
<visual>
|
| 849 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 850 |
+
<geometry>
|
| 851 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 852 |
+
</geometry>
|
| 853 |
+
</visual>
|
| 854 |
+
<collision>
|
| 855 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 856 |
+
<geometry>
|
| 857 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 858 |
+
</geometry>
|
| 859 |
+
</collision>
|
| 860 |
+
</link>
|
| 861 |
+
<link name="knee_1">
|
| 862 |
+
<inertial>
|
| 863 |
+
<origin xyz="0.00012063381 0.14620674 0.029740711000000003"/>
|
| 864 |
+
<mass value="2.1199315"/>
|
| 865 |
+
<!-- org 3.5, foot un modeled-->
|
| 866 |
+
<inertia ixx="0.018426402999999997" ixy="2.8226635999999997e-05" ixz="-2.9204348e-05" iyy="0.0047685615" iyz="-0.002640771" izz="0.017793722"/>
|
| 867 |
+
</inertial>
|
| 868 |
+
<visual>
|
| 869 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 870 |
+
<geometry>
|
| 871 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/knee.stl" scale="0.001 0.001 -0.001"/>
|
| 872 |
+
</geometry>
|
| 873 |
+
<material name="dark_grey"/>
|
| 874 |
+
</visual>
|
| 875 |
+
<collision>
|
| 876 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 877 |
+
<geometry>
|
| 878 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/knee.stl" scale="0.001 0.001 -0.001"/>
|
| 879 |
+
</geometry>
|
| 880 |
+
</collision>
|
| 881 |
+
</link>
|
| 882 |
+
<link name="ankle1_1">
|
| 883 |
+
<inertial>
|
| 884 |
+
<origin xyz="0.00012360094 -0.06274712 -0.0049068453"/>
|
| 885 |
+
<mass value="1.4023368"/>
|
| 886 |
+
<!-- org 3.5, foot un modeled-->
|
| 887 |
+
<inertia ixx="0.0049928829" ixy="5.762355699999999e-06" ixz="1.9606394e-05" iyy="0.0017621464" iyz="0.00045315091" izz="0.0048706328"/>
|
| 888 |
+
</inertial>
|
| 889 |
+
<visual>
|
| 890 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 891 |
+
<geometry>
|
| 892 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/ankle-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 893 |
+
</geometry>
|
| 894 |
+
</visual>
|
| 895 |
+
<collision>
|
| 896 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 897 |
+
<geometry>
|
| 898 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/ankle-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 899 |
+
</geometry>
|
| 900 |
+
</collision>
|
| 901 |
+
</link>
|
| 902 |
+
<link name="ankle2_1">
|
| 903 |
+
<inertial>
|
| 904 |
+
<origin xyz="0.00018512273 0.0017369405000000001 -0.091340683"/>
|
| 905 |
+
<mass value="2.440929"/>
|
| 906 |
+
<!-- org 3.5, foot un modeled-->
|
| 907 |
+
<inertia ixx="0.017711499" ixy="1.0713141e-05" ixz="-2.2094697e-05" iyy="0.014263485" iyz="0.00033426702" izz="0.0080747557"/>
|
| 908 |
+
</inertial>
|
| 909 |
+
<visual>
|
| 910 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 911 |
+
<geometry>
|
| 912 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_ankle-yaw_wheel23.stl" scale="0.001 -0.001 0.001"/>
|
| 913 |
+
</geometry>
|
| 914 |
+
<material name="dark_grey"/>
|
| 915 |
+
</visual>
|
| 916 |
+
<!-- <collision>
|
| 917 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
|
| 918 |
+
<geometry>
|
| 919 |
+
<mesh
|
| 920 |
+
filename="${MESH_PATH}/v2/collision/mesh_ankle-yaw_wheel23.stl"
|
| 921 |
+
scale="0.001 ${mirror*0.001} 0.001" />
|
| 922 |
+
</geometry>
|
| 923 |
+
</collision> -->
|
| 924 |
+
</link>
|
| 925 |
+
<joint name="j_wheel_1" type="continuous">
|
| 926 |
+
<parent link="ankle2_1"/>
|
| 927 |
+
<child link="wheel_1"/>
|
| 928 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 -0.0 -0.14435"/>
|
| 929 |
+
<axis xyz="0 0 -1"/>
|
| 930 |
+
<limit effort="35" velocity="20.0"/>
|
| 931 |
+
<!-- 23 Nm, 1
|
| 932 |
+
rad/s-->
|
| 933 |
+
</joint>
|
| 934 |
+
<link name="wheel_1">
|
| 935 |
+
<inertial>
|
| 936 |
+
<origin xyz="0.0 0.0 0.00015403767"/>
|
| 937 |
+
<mass value="1.8569388"/>
|
| 938 |
+
<inertia ixx="0.008637359099999999" ixy="0.0" ixz="-0.0" iyy="0.0086373644" iyz="-0.0" izz="0.016376551"/>
|
| 939 |
+
</inertial>
|
| 940 |
+
<visual>
|
| 941 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 942 |
+
<geometry>
|
| 943 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_wheel23.stl" scale="0.001 0.001 -0.001"/>
|
| 944 |
+
</geometry>
|
| 945 |
+
<material name="black"/>
|
| 946 |
+
</visual>
|
| 947 |
+
<collision>
|
| 948 |
+
<origin rpy="0 0 0" xyz="0 0 0"/>
|
| 949 |
+
<geometry>
|
| 950 |
+
<cylinder length="0.03" radius="0.124"/>
|
| 951 |
+
</geometry>
|
| 952 |
+
<!-- <geometry>
|
| 953 |
+
<mesh filename="${MESH_PATH}/v2/collision/wheel23_donut.stl"
|
| 954 |
+
scale="0.001 0.001 ${mirror*0.001}" />
|
| 955 |
+
</geometry> -->
|
| 956 |
+
<material name="black"/>
|
| 957 |
+
</collision>
|
| 958 |
+
</link>
|
| 959 |
+
<!-- *********** CONTACT FRAME ******************-->
|
| 960 |
+
<link name="contact_1"/>
|
| 961 |
+
<joint name="contact_joint_1" type="fixed">
|
| 962 |
+
<parent link="ankle2_1"/>
|
| 963 |
+
<child link="contact_1"/>
|
| 964 |
+
<origin rpy="0 0 0" xyz="0 0 -0.26835"/>
|
| 965 |
+
</joint>
|
| 966 |
+
<!-- ******************************** -->
|
| 967 |
+
<joint name="hip_yaw_1" type="revolute">
|
| 968 |
+
<parent link="pelvis"/>
|
| 969 |
+
<child link="hip1_1"/>
|
| 970 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.25 0.125 -0.056600000000000004"/>
|
| 971 |
+
<axis xyz="0 0 -1"/>
|
| 972 |
+
<limit effort="304" lower="-2.03" upper="2.51" velocity="8.8"/>
|
| 973 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 974 |
+
</joint>
|
| 975 |
+
<joint name="hip_pitch_1" type="revolute">
|
| 976 |
+
<parent link="hip1_1"/>
|
| 977 |
+
<child link="hip2_1"/>
|
| 978 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 0.1146 -0.0625"/>
|
| 979 |
+
<axis xyz="0 0 -1"/>
|
| 980 |
+
<limit effort="304" lower="-2.0226" upper="2.02748" velocity="8.8"/>
|
| 981 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 982 |
+
</joint>
|
| 983 |
+
<joint name="knee_pitch_1" type="revolute">
|
| 984 |
+
<parent link="hip2_1"/>
|
| 985 |
+
<child link="knee_1"/>
|
| 986 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 -0.3 0.1182"/>
|
| 987 |
+
<axis xyz="0 0 -1"/>
|
| 988 |
+
<limit effort="304" lower="-2.4056" upper="2.3994" velocity="8.8"/>
|
| 989 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 990 |
+
</joint>
|
| 991 |
+
<joint name="ankle_pitch_1" type="revolute">
|
| 992 |
+
<parent link="knee_1"/>
|
| 993 |
+
<child link="ankle1_1"/>
|
| 994 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 0.2 0.10015"/>
|
| 995 |
+
<axis xyz="0 0 -1"/>
|
| 996 |
+
<limit effort="147" lower="-2.4056" upper="2.3184" velocity="8.1"/>
|
| 997 |
+
<!-- 98 Nm, 1 rad/s-->
|
| 998 |
+
</joint>
|
| 999 |
+
<joint name="ankle_yaw_1" type="revolute">
|
| 1000 |
+
<parent link="ankle1_1"/>
|
| 1001 |
+
<child link="ankle2_1"/>
|
| 1002 |
+
<origin rpy="-1.57079632679 0.0 0.0" xyz="0.0 -0.139 -0.00085"/>
|
| 1003 |
+
<axis xyz="0 0 -1"/>
|
| 1004 |
+
<limit effort="35" lower="-2.5626" upper="2.5384" velocity="20.0"/>
|
| 1005 |
+
<!-- 23 Nm, 1 rad/s-->
|
| 1006 |
+
</joint>
|
| 1007 |
+
<link name="hip1_2">
|
| 1008 |
+
<inertial>
|
| 1009 |
+
<origin xyz="0.0003595855 -0.033338818000000006 -0.059190309"/>
|
| 1010 |
+
<mass value="2.3349153"/>
|
| 1011 |
+
<!-- org 2 -->
|
| 1012 |
+
<inertia ixx="0.0068405374" ixy="-1.8572633e-05" ixz="-4.8325972e-05" iyy="0.0026261815" iyz="-0.0001564273" izz="0.0066933354"/>
|
| 1013 |
+
</inertial>
|
| 1014 |
+
<visual>
|
| 1015 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1016 |
+
<geometry>
|
| 1017 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-yaw.stl" scale="0.001 0.001 0.001"/>
|
| 1018 |
+
</geometry>
|
| 1019 |
+
<material name="dark_grey"/>
|
| 1020 |
+
</visual>
|
| 1021 |
+
<collision>
|
| 1022 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1023 |
+
<geometry>
|
| 1024 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-yaw.stl" scale="0.001 0.001 0.001"/>
|
| 1025 |
+
</geometry>
|
| 1026 |
+
</collision>
|
| 1027 |
+
</link>
|
| 1028 |
+
<link name="hip2_2">
|
| 1029 |
+
<inertial>
|
| 1030 |
+
<origin xyz="-4.6285952e-06 -0.2214019 -0.03316685"/>
|
| 1031 |
+
<mass value="3.4572118"/>
|
| 1032 |
+
<!-- org 4.5 -->
|
| 1033 |
+
<inertia ixx="0.050469853" ixy="-7.784938699999999e-06" ixz="9.220580999999999e-06" iyy="0.008181596999999999" iyz="-0.0059796848" izz="0.048213808999999996"/>
|
| 1034 |
+
</inertial>
|
| 1035 |
+
<visual>
|
| 1036 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1037 |
+
<geometry>
|
| 1038 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1039 |
+
</geometry>
|
| 1040 |
+
</visual>
|
| 1041 |
+
<collision>
|
| 1042 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1043 |
+
<geometry>
|
| 1044 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1045 |
+
</geometry>
|
| 1046 |
+
</collision>
|
| 1047 |
+
</link>
|
| 1048 |
+
<link name="knee_2">
|
| 1049 |
+
<inertial>
|
| 1050 |
+
<origin xyz="0.00012063381 0.14620674 -0.029740711000000003"/>
|
| 1051 |
+
<mass value="2.1199315"/>
|
| 1052 |
+
<!-- org 3.5, foot un modeled-->
|
| 1053 |
+
<inertia ixx="0.018426402999999997" ixy="2.8226635999999997e-05" ixz="2.9204348e-05" iyy="0.0047685615" iyz="0.002640771" izz="0.017793722"/>
|
| 1054 |
+
</inertial>
|
| 1055 |
+
<visual>
|
| 1056 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1057 |
+
<geometry>
|
| 1058 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/knee.stl" scale="0.001 0.001 0.001"/>
|
| 1059 |
+
</geometry>
|
| 1060 |
+
<material name="dark_grey"/>
|
| 1061 |
+
</visual>
|
| 1062 |
+
<collision>
|
| 1063 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1064 |
+
<geometry>
|
| 1065 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/knee.stl" scale="0.001 0.001 0.001"/>
|
| 1066 |
+
</geometry>
|
| 1067 |
+
</collision>
|
| 1068 |
+
</link>
|
| 1069 |
+
<link name="ankle1_2">
|
| 1070 |
+
<inertial>
|
| 1071 |
+
<origin xyz="0.00012360094 -0.06274712 0.0049068453"/>
|
| 1072 |
+
<mass value="1.4023368"/>
|
| 1073 |
+
<!-- org 3.5, foot un modeled-->
|
| 1074 |
+
<inertia ixx="0.0049928829" ixy="5.762355699999999e-06" ixz="-1.9606394e-05" iyy="0.0017621464" iyz="-0.00045315091" izz="0.0048706328"/>
|
| 1075 |
+
</inertial>
|
| 1076 |
+
<visual>
|
| 1077 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1078 |
+
<geometry>
|
| 1079 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/ankle-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1080 |
+
</geometry>
|
| 1081 |
+
</visual>
|
| 1082 |
+
<collision>
|
| 1083 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1084 |
+
<geometry>
|
| 1085 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/ankle-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1086 |
+
</geometry>
|
| 1087 |
+
</collision>
|
| 1088 |
+
</link>
|
| 1089 |
+
<link name="ankle2_2">
|
| 1090 |
+
<inertial>
|
| 1091 |
+
<origin xyz="0.00018512273 -0.0017369405000000001 -0.091340683"/>
|
| 1092 |
+
<mass value="2.440929"/>
|
| 1093 |
+
<!-- org 3.5, foot un modeled-->
|
| 1094 |
+
<inertia ixx="0.017711499" ixy="-1.0713141e-05" ixz="-2.2094697e-05" iyy="0.014263485" iyz="-0.00033426702" izz="0.0080747557"/>
|
| 1095 |
+
</inertial>
|
| 1096 |
+
<visual>
|
| 1097 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1098 |
+
<geometry>
|
| 1099 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_ankle-yaw_wheel23.stl" scale="0.001 0.001 0.001"/>
|
| 1100 |
+
</geometry>
|
| 1101 |
+
<material name="dark_grey"/>
|
| 1102 |
+
</visual>
|
| 1103 |
+
<!-- <collision>
|
| 1104 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
|
| 1105 |
+
<geometry>
|
| 1106 |
+
<mesh
|
| 1107 |
+
filename="${MESH_PATH}/v2/collision/mesh_ankle-yaw_wheel23.stl"
|
| 1108 |
+
scale="0.001 ${mirror*0.001} 0.001" />
|
| 1109 |
+
</geometry>
|
| 1110 |
+
</collision> -->
|
| 1111 |
+
</link>
|
| 1112 |
+
<joint name="j_wheel_2" type="continuous">
|
| 1113 |
+
<parent link="ankle2_2"/>
|
| 1114 |
+
<child link="wheel_2"/>
|
| 1115 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 0.0 -0.14435"/>
|
| 1116 |
+
<axis xyz="0 0 1"/>
|
| 1117 |
+
<limit effort="35" velocity="20.0"/>
|
| 1118 |
+
<!-- 23 Nm, 1
|
| 1119 |
+
rad/s-->
|
| 1120 |
+
</joint>
|
| 1121 |
+
<link name="wheel_2">
|
| 1122 |
+
<inertial>
|
| 1123 |
+
<origin xyz="0.0 0.0 -0.00015403767"/>
|
| 1124 |
+
<mass value="1.8569388"/>
|
| 1125 |
+
<inertia ixx="0.008637359099999999" ixy="0.0" ixz="0.0" iyy="0.0086373644" iyz="0.0" izz="0.016376551"/>
|
| 1126 |
+
</inertial>
|
| 1127 |
+
<visual>
|
| 1128 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1129 |
+
<geometry>
|
| 1130 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_wheel23.stl" scale="0.001 0.001 0.001"/>
|
| 1131 |
+
</geometry>
|
| 1132 |
+
<material name="black"/>
|
| 1133 |
+
</visual>
|
| 1134 |
+
<collision>
|
| 1135 |
+
<origin rpy="0 0 0" xyz="0 0 0"/>
|
| 1136 |
+
<geometry>
|
| 1137 |
+
<cylinder length="0.03" radius="0.124"/>
|
| 1138 |
+
</geometry>
|
| 1139 |
+
<!-- <geometry>
|
| 1140 |
+
<mesh filename="${MESH_PATH}/v2/collision/wheel23_donut.stl"
|
| 1141 |
+
scale="0.001 0.001 ${mirror*0.001}" />
|
| 1142 |
+
</geometry> -->
|
| 1143 |
+
<material name="black"/>
|
| 1144 |
+
</collision>
|
| 1145 |
+
</link>
|
| 1146 |
+
<!-- *********** CONTACT FRAME ******************-->
|
| 1147 |
+
<link name="contact_2"/>
|
| 1148 |
+
<joint name="contact_joint_2" type="fixed">
|
| 1149 |
+
<parent link="ankle2_2"/>
|
| 1150 |
+
<child link="contact_2"/>
|
| 1151 |
+
<origin rpy="0 0 0" xyz="0 0 -0.26835"/>
|
| 1152 |
+
</joint>
|
| 1153 |
+
<!-- ******************************** -->
|
| 1154 |
+
<joint name="hip_yaw_2" type="revolute">
|
| 1155 |
+
<parent link="pelvis"/>
|
| 1156 |
+
<child link="hip1_2"/>
|
| 1157 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.25 -0.125 -0.056600000000000004"/>
|
| 1158 |
+
<axis xyz="0 0 -1"/>
|
| 1159 |
+
<limit effort="304" lower="-2.51" upper="2.03" velocity="8.8"/>
|
| 1160 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1161 |
+
</joint>
|
| 1162 |
+
<joint name="hip_pitch_2" type="revolute">
|
| 1163 |
+
<parent link="hip1_2"/>
|
| 1164 |
+
<child link="hip2_2"/>
|
| 1165 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 -0.1146 -0.0625"/>
|
| 1166 |
+
<axis xyz="0 0 1"/>
|
| 1167 |
+
<limit effort="304" lower="-2.0156" upper="2.0354" velocity="8.8"/>
|
| 1168 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1169 |
+
</joint>
|
| 1170 |
+
<joint name="knee_pitch_2" type="revolute">
|
| 1171 |
+
<parent link="hip2_2"/>
|
| 1172 |
+
<child link="knee_2"/>
|
| 1173 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 -0.3 -0.1182"/>
|
| 1174 |
+
<axis xyz="0 0 1"/>
|
| 1175 |
+
<limit effort="304" lower="-2.4006" upper="2.4034" velocity="8.8"/>
|
| 1176 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1177 |
+
</joint>
|
| 1178 |
+
<joint name="ankle_pitch_2" type="revolute">
|
| 1179 |
+
<parent link="knee_2"/>
|
| 1180 |
+
<child link="ankle1_2"/>
|
| 1181 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 0.2 -0.10015"/>
|
| 1182 |
+
<axis xyz="0 0 1"/>
|
| 1183 |
+
<limit effort="147" lower="-2.3266" upper="2.3914" velocity="8.1"/>
|
| 1184 |
+
<!-- 98 Nm, 1 rad/s-->
|
| 1185 |
+
</joint>
|
| 1186 |
+
<joint name="ankle_yaw_2" type="revolute">
|
| 1187 |
+
<parent link="ankle1_2"/>
|
| 1188 |
+
<child link="ankle2_2"/>
|
| 1189 |
+
<origin rpy="-1.57079632679 0.0 0.0" xyz="0.0 -0.139 0.00085"/>
|
| 1190 |
+
<axis xyz="0 0 -1"/>
|
| 1191 |
+
<limit effort="35" lower="-2.5546" upper="2.5484" velocity="20.0"/>
|
| 1192 |
+
<!-- 23 Nm, 1 rad/s-->
|
| 1193 |
+
</joint>
|
| 1194 |
+
<link name="hip1_3">
|
| 1195 |
+
<inertial>
|
| 1196 |
+
<origin xyz="0.0003595855 0.033338818000000006 -0.059190309"/>
|
| 1197 |
+
<mass value="2.3349153"/>
|
| 1198 |
+
<!-- org 2 -->
|
| 1199 |
+
<inertia ixx="0.0068405374" ixy="1.8572633e-05" ixz="-4.8325972e-05" iyy="0.0026261815" iyz="0.0001564273" izz="0.0066933354"/>
|
| 1200 |
+
</inertial>
|
| 1201 |
+
<visual>
|
| 1202 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1203 |
+
<geometry>
|
| 1204 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-yaw.stl" scale="0.001 -0.001 0.001"/>
|
| 1205 |
+
</geometry>
|
| 1206 |
+
<material name="dark_grey"/>
|
| 1207 |
+
</visual>
|
| 1208 |
+
<collision>
|
| 1209 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1210 |
+
<geometry>
|
| 1211 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-yaw.stl" scale="0.001 -0.001 0.001"/>
|
| 1212 |
+
</geometry>
|
| 1213 |
+
</collision>
|
| 1214 |
+
</link>
|
| 1215 |
+
<link name="hip2_3">
|
| 1216 |
+
<inertial>
|
| 1217 |
+
<origin xyz="-4.6285952e-06 -0.2214019 0.03316685"/>
|
| 1218 |
+
<mass value="3.4572118"/>
|
| 1219 |
+
<!-- org 4.5 -->
|
| 1220 |
+
<inertia ixx="0.050469853" ixy="-7.784938699999999e-06" ixz="-9.220580999999999e-06" iyy="0.008181596999999999" iyz="0.0059796848" izz="0.048213808999999996"/>
|
| 1221 |
+
</inertial>
|
| 1222 |
+
<visual>
|
| 1223 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1224 |
+
<geometry>
|
| 1225 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 1226 |
+
</geometry>
|
| 1227 |
+
</visual>
|
| 1228 |
+
<collision>
|
| 1229 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1230 |
+
<geometry>
|
| 1231 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 1232 |
+
</geometry>
|
| 1233 |
+
</collision>
|
| 1234 |
+
</link>
|
| 1235 |
+
<link name="knee_3">
|
| 1236 |
+
<inertial>
|
| 1237 |
+
<origin xyz="0.00012063381 0.14620674 0.029740711000000003"/>
|
| 1238 |
+
<mass value="2.1199315"/>
|
| 1239 |
+
<!-- org 3.5, foot un modeled-->
|
| 1240 |
+
<inertia ixx="0.018426402999999997" ixy="2.8226635999999997e-05" ixz="-2.9204348e-05" iyy="0.0047685615" iyz="-0.002640771" izz="0.017793722"/>
|
| 1241 |
+
</inertial>
|
| 1242 |
+
<visual>
|
| 1243 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1244 |
+
<geometry>
|
| 1245 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/knee.stl" scale="0.001 0.001 -0.001"/>
|
| 1246 |
+
</geometry>
|
| 1247 |
+
<material name="dark_grey"/>
|
| 1248 |
+
</visual>
|
| 1249 |
+
<collision>
|
| 1250 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1251 |
+
<geometry>
|
| 1252 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/knee.stl" scale="0.001 0.001 -0.001"/>
|
| 1253 |
+
</geometry>
|
| 1254 |
+
</collision>
|
| 1255 |
+
</link>
|
| 1256 |
+
<link name="ankle1_3">
|
| 1257 |
+
<inertial>
|
| 1258 |
+
<origin xyz="0.00012360094 -0.06274712 -0.0049068453"/>
|
| 1259 |
+
<mass value="1.4023368"/>
|
| 1260 |
+
<!-- org 3.5, foot un modeled-->
|
| 1261 |
+
<inertia ixx="0.0049928829" ixy="5.762355699999999e-06" ixz="1.9606394e-05" iyy="0.0017621464" iyz="0.00045315091" izz="0.0048706328"/>
|
| 1262 |
+
</inertial>
|
| 1263 |
+
<visual>
|
| 1264 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1265 |
+
<geometry>
|
| 1266 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/ankle-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 1267 |
+
</geometry>
|
| 1268 |
+
</visual>
|
| 1269 |
+
<collision>
|
| 1270 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1271 |
+
<geometry>
|
| 1272 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/ankle-pitch.stl" scale="0.001 0.001 -0.001"/>
|
| 1273 |
+
</geometry>
|
| 1274 |
+
</collision>
|
| 1275 |
+
</link>
|
| 1276 |
+
<link name="ankle2_3">
|
| 1277 |
+
<inertial>
|
| 1278 |
+
<origin xyz="0.00018512273 0.0017369405000000001 -0.091340683"/>
|
| 1279 |
+
<mass value="2.440929"/>
|
| 1280 |
+
<!-- org 3.5, foot un modeled-->
|
| 1281 |
+
<inertia ixx="0.017711499" ixy="1.0713141e-05" ixz="-2.2094697e-05" iyy="0.014263485" iyz="0.00033426702" izz="0.0080747557"/>
|
| 1282 |
+
</inertial>
|
| 1283 |
+
<visual>
|
| 1284 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1285 |
+
<geometry>
|
| 1286 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_ankle-yaw_wheel23.stl" scale="0.001 -0.001 0.001"/>
|
| 1287 |
+
</geometry>
|
| 1288 |
+
<material name="dark_grey"/>
|
| 1289 |
+
</visual>
|
| 1290 |
+
<!-- <collision>
|
| 1291 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
|
| 1292 |
+
<geometry>
|
| 1293 |
+
<mesh
|
| 1294 |
+
filename="${MESH_PATH}/v2/collision/mesh_ankle-yaw_wheel23.stl"
|
| 1295 |
+
scale="0.001 ${mirror*0.001} 0.001" />
|
| 1296 |
+
</geometry>
|
| 1297 |
+
</collision> -->
|
| 1298 |
+
</link>
|
| 1299 |
+
<joint name="j_wheel_3" type="continuous">
|
| 1300 |
+
<parent link="ankle2_3"/>
|
| 1301 |
+
<child link="wheel_3"/>
|
| 1302 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 -0.0 -0.14435"/>
|
| 1303 |
+
<axis xyz="0 0 -1"/>
|
| 1304 |
+
<limit effort="35" velocity="20.0"/>
|
| 1305 |
+
<!-- 23 Nm, 1
|
| 1306 |
+
rad/s-->
|
| 1307 |
+
</joint>
|
| 1308 |
+
<link name="wheel_3">
|
| 1309 |
+
<inertial>
|
| 1310 |
+
<origin xyz="0.0 0.0 0.00015403767"/>
|
| 1311 |
+
<mass value="1.8569388"/>
|
| 1312 |
+
<inertia ixx="0.008637359099999999" ixy="0.0" ixz="-0.0" iyy="0.0086373644" iyz="-0.0" izz="0.016376551"/>
|
| 1313 |
+
</inertial>
|
| 1314 |
+
<visual>
|
| 1315 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1316 |
+
<geometry>
|
| 1317 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_wheel23.stl" scale="0.001 0.001 -0.001"/>
|
| 1318 |
+
</geometry>
|
| 1319 |
+
<material name="black"/>
|
| 1320 |
+
</visual>
|
| 1321 |
+
<collision>
|
| 1322 |
+
<origin rpy="0 0 0" xyz="0 0 0"/>
|
| 1323 |
+
<geometry>
|
| 1324 |
+
<cylinder length="0.03" radius="0.124"/>
|
| 1325 |
+
</geometry>
|
| 1326 |
+
<!-- <geometry>
|
| 1327 |
+
<mesh filename="${MESH_PATH}/v2/collision/wheel23_donut.stl"
|
| 1328 |
+
scale="0.001 0.001 ${mirror*0.001}" />
|
| 1329 |
+
</geometry> -->
|
| 1330 |
+
<material name="black"/>
|
| 1331 |
+
</collision>
|
| 1332 |
+
</link>
|
| 1333 |
+
<!-- *********** CONTACT FRAME ******************-->
|
| 1334 |
+
<link name="contact_3"/>
|
| 1335 |
+
<joint name="contact_joint_3" type="fixed">
|
| 1336 |
+
<parent link="ankle2_3"/>
|
| 1337 |
+
<child link="contact_3"/>
|
| 1338 |
+
<origin rpy="0 0 0" xyz="0 0 -0.26835"/>
|
| 1339 |
+
</joint>
|
| 1340 |
+
<!-- ******************************** -->
|
| 1341 |
+
<joint name="hip_yaw_3" type="revolute">
|
| 1342 |
+
<parent link="pelvis"/>
|
| 1343 |
+
<child link="hip1_3"/>
|
| 1344 |
+
<origin rpy="0.0 0.0 0.0" xyz="-0.25 0.125 -0.056600000000000004"/>
|
| 1345 |
+
<axis xyz="0 0 -1"/>
|
| 1346 |
+
<limit effort="304" lower="-2.51" upper="2.03" velocity="8.8"/>
|
| 1347 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1348 |
+
</joint>
|
| 1349 |
+
<joint name="hip_pitch_3" type="revolute">
|
| 1350 |
+
<parent link="hip1_3"/>
|
| 1351 |
+
<child link="hip2_3"/>
|
| 1352 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 0.1146 -0.0625"/>
|
| 1353 |
+
<axis xyz="0 0 -1"/>
|
| 1354 |
+
<limit effort="304" lower="-2.0126" upper="2.0384" velocity="8.8"/>
|
| 1355 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1356 |
+
</joint>
|
| 1357 |
+
<joint name="knee_pitch_3" type="revolute">
|
| 1358 |
+
<parent link="hip2_3"/>
|
| 1359 |
+
<child link="knee_3"/>
|
| 1360 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 -0.3 0.1182"/>
|
| 1361 |
+
<axis xyz="0 0 -1"/>
|
| 1362 |
+
<limit effort="304" lower="-2.4056" upper="2.4064" velocity="8.8"/>
|
| 1363 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1364 |
+
</joint>
|
| 1365 |
+
<joint name="ankle_pitch_3" type="revolute">
|
| 1366 |
+
<parent link="knee_3"/>
|
| 1367 |
+
<child link="ankle1_3"/>
|
| 1368 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 0.2 0.10015"/>
|
| 1369 |
+
<axis xyz="0 0 -1"/>
|
| 1370 |
+
<limit effort="147" lower="-2.4696" upper="2.4464" velocity="8.1"/>
|
| 1371 |
+
<!-- 98 Nm, 1 rad/s-->
|
| 1372 |
+
</joint>
|
| 1373 |
+
<joint name="ankle_yaw_3" type="revolute">
|
| 1374 |
+
<parent link="ankle1_3"/>
|
| 1375 |
+
<child link="ankle2_3"/>
|
| 1376 |
+
<origin rpy="-1.57079632679 0.0 0.0" xyz="0.0 -0.139 -0.00085"/>
|
| 1377 |
+
<axis xyz="0 0 -1"/>
|
| 1378 |
+
<limit effort="35" lower="-2.5606" upper="2.5454" velocity="20.0"/>
|
| 1379 |
+
<!-- 23 Nm, 1 rad/s-->
|
| 1380 |
+
</joint>
|
| 1381 |
+
<link name="hip1_4">
|
| 1382 |
+
<inertial>
|
| 1383 |
+
<origin xyz="0.0003595855 -0.033338818000000006 -0.059190309"/>
|
| 1384 |
+
<mass value="2.3349153"/>
|
| 1385 |
+
<!-- org 2 -->
|
| 1386 |
+
<inertia ixx="0.0068405374" ixy="-1.8572633e-05" ixz="-4.8325972e-05" iyy="0.0026261815" iyz="-0.0001564273" izz="0.0066933354"/>
|
| 1387 |
+
</inertial>
|
| 1388 |
+
<visual>
|
| 1389 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1390 |
+
<geometry>
|
| 1391 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-yaw.stl" scale="0.001 0.001 0.001"/>
|
| 1392 |
+
</geometry>
|
| 1393 |
+
<material name="dark_grey"/>
|
| 1394 |
+
</visual>
|
| 1395 |
+
<collision>
|
| 1396 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1397 |
+
<geometry>
|
| 1398 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-yaw.stl" scale="0.001 0.001 0.001"/>
|
| 1399 |
+
</geometry>
|
| 1400 |
+
</collision>
|
| 1401 |
+
</link>
|
| 1402 |
+
<link name="hip2_4">
|
| 1403 |
+
<inertial>
|
| 1404 |
+
<origin xyz="-4.6285952e-06 -0.2214019 -0.03316685"/>
|
| 1405 |
+
<mass value="3.4572118"/>
|
| 1406 |
+
<!-- org 4.5 -->
|
| 1407 |
+
<inertia ixx="0.050469853" ixy="-7.784938699999999e-06" ixz="9.220580999999999e-06" iyy="0.008181596999999999" iyz="-0.0059796848" izz="0.048213808999999996"/>
|
| 1408 |
+
</inertial>
|
| 1409 |
+
<visual>
|
| 1410 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1411 |
+
<geometry>
|
| 1412 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/hip-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1413 |
+
</geometry>
|
| 1414 |
+
</visual>
|
| 1415 |
+
<collision>
|
| 1416 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1417 |
+
<geometry>
|
| 1418 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/hip-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1419 |
+
</geometry>
|
| 1420 |
+
</collision>
|
| 1421 |
+
</link>
|
| 1422 |
+
<link name="knee_4">
|
| 1423 |
+
<inertial>
|
| 1424 |
+
<origin xyz="0.00012063381 0.14620674 -0.029740711000000003"/>
|
| 1425 |
+
<mass value="2.1199315"/>
|
| 1426 |
+
<!-- org 3.5, foot un modeled-->
|
| 1427 |
+
<inertia ixx="0.018426402999999997" ixy="2.8226635999999997e-05" ixz="2.9204348e-05" iyy="0.0047685615" iyz="0.002640771" izz="0.017793722"/>
|
| 1428 |
+
</inertial>
|
| 1429 |
+
<visual>
|
| 1430 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1431 |
+
<geometry>
|
| 1432 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/knee.stl" scale="0.001 0.001 0.001"/>
|
| 1433 |
+
</geometry>
|
| 1434 |
+
<material name="dark_grey"/>
|
| 1435 |
+
</visual>
|
| 1436 |
+
<collision>
|
| 1437 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1438 |
+
<geometry>
|
| 1439 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/knee.stl" scale="0.001 0.001 0.001"/>
|
| 1440 |
+
</geometry>
|
| 1441 |
+
</collision>
|
| 1442 |
+
</link>
|
| 1443 |
+
<link name="ankle1_4">
|
| 1444 |
+
<inertial>
|
| 1445 |
+
<origin xyz="0.00012360094 -0.06274712 0.0049068453"/>
|
| 1446 |
+
<mass value="1.4023368"/>
|
| 1447 |
+
<!-- org 3.5, foot un modeled-->
|
| 1448 |
+
<inertia ixx="0.0049928829" ixy="5.762355699999999e-06" ixz="-1.9606394e-05" iyy="0.0017621464" iyz="-0.00045315091" izz="0.0048706328"/>
|
| 1449 |
+
</inertial>
|
| 1450 |
+
<visual>
|
| 1451 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1452 |
+
<geometry>
|
| 1453 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/ankle-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1454 |
+
</geometry>
|
| 1455 |
+
</visual>
|
| 1456 |
+
<collision>
|
| 1457 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1458 |
+
<geometry>
|
| 1459 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/collision/ankle-pitch.stl" scale="0.001 0.001 0.001"/>
|
| 1460 |
+
</geometry>
|
| 1461 |
+
</collision>
|
| 1462 |
+
</link>
|
| 1463 |
+
<link name="ankle2_4">
|
| 1464 |
+
<inertial>
|
| 1465 |
+
<origin xyz="0.00018512273 -0.0017369405000000001 -0.091340683"/>
|
| 1466 |
+
<mass value="2.440929"/>
|
| 1467 |
+
<!-- org 3.5, foot un modeled-->
|
| 1468 |
+
<inertia ixx="0.017711499" ixy="-1.0713141e-05" ixz="-2.2094697e-05" iyy="0.014263485" iyz="-0.00033426702" izz="0.0080747557"/>
|
| 1469 |
+
</inertial>
|
| 1470 |
+
<visual>
|
| 1471 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1472 |
+
<geometry>
|
| 1473 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_ankle-yaw_wheel23.stl" scale="0.001 0.001 0.001"/>
|
| 1474 |
+
</geometry>
|
| 1475 |
+
<material name="dark_grey"/>
|
| 1476 |
+
</visual>
|
| 1477 |
+
<!-- <collision>
|
| 1478 |
+
<origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
|
| 1479 |
+
<geometry>
|
| 1480 |
+
<mesh
|
| 1481 |
+
filename="${MESH_PATH}/v2/collision/mesh_ankle-yaw_wheel23.stl"
|
| 1482 |
+
scale="0.001 ${mirror*0.001} 0.001" />
|
| 1483 |
+
</geometry>
|
| 1484 |
+
</collision> -->
|
| 1485 |
+
</link>
|
| 1486 |
+
<joint name="j_wheel_4" type="continuous">
|
| 1487 |
+
<parent link="ankle2_4"/>
|
| 1488 |
+
<child link="wheel_4"/>
|
| 1489 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 0.0 -0.14435"/>
|
| 1490 |
+
<axis xyz="0 0 1"/>
|
| 1491 |
+
<limit effort="35" velocity="20.0"/>
|
| 1492 |
+
<!-- 23 Nm, 1
|
| 1493 |
+
rad/s-->
|
| 1494 |
+
</joint>
|
| 1495 |
+
<link name="wheel_4">
|
| 1496 |
+
<inertial>
|
| 1497 |
+
<origin xyz="0.0 0.0 -0.00015403767"/>
|
| 1498 |
+
<mass value="1.8569388"/>
|
| 1499 |
+
<inertia ixx="0.008637359099999999" ixy="0.0" ixz="0.0" iyy="0.0086373644" iyz="0.0" izz="0.016376551"/>
|
| 1500 |
+
</inertial>
|
| 1501 |
+
<visual>
|
| 1502 |
+
<origin rpy="0.0 0.0 0.0" xyz="0.0 0.0 0.0"/>
|
| 1503 |
+
<geometry>
|
| 1504 |
+
<mesh filename="/root/ibrido_ws/src/iit-centauro-ros-pkg/centauro_urdf/meshes/v2/mesh_wheel23.stl" scale="0.001 0.001 0.001"/>
|
| 1505 |
+
</geometry>
|
| 1506 |
+
<material name="black"/>
|
| 1507 |
+
</visual>
|
| 1508 |
+
<collision>
|
| 1509 |
+
<origin rpy="0 0 0" xyz="0 0 0"/>
|
| 1510 |
+
<geometry>
|
| 1511 |
+
<cylinder length="0.03" radius="0.124"/>
|
| 1512 |
+
</geometry>
|
| 1513 |
+
<!-- <geometry>
|
| 1514 |
+
<mesh filename="${MESH_PATH}/v2/collision/wheel23_donut.stl"
|
| 1515 |
+
scale="0.001 0.001 ${mirror*0.001}" />
|
| 1516 |
+
</geometry> -->
|
| 1517 |
+
<material name="black"/>
|
| 1518 |
+
</collision>
|
| 1519 |
+
</link>
|
| 1520 |
+
<!-- *********** CONTACT FRAME ******************-->
|
| 1521 |
+
<link name="contact_4"/>
|
| 1522 |
+
<joint name="contact_joint_4" type="fixed">
|
| 1523 |
+
<parent link="ankle2_4"/>
|
| 1524 |
+
<child link="contact_4"/>
|
| 1525 |
+
<origin rpy="0 0 0" xyz="0 0 -0.26835"/>
|
| 1526 |
+
</joint>
|
| 1527 |
+
<!-- ******************************** -->
|
| 1528 |
+
<joint name="hip_yaw_4" type="revolute">
|
| 1529 |
+
<parent link="pelvis"/>
|
| 1530 |
+
<child link="hip1_4"/>
|
| 1531 |
+
<origin rpy="0.0 0.0 0.0" xyz="-0.25 -0.125 -0.056600000000000004"/>
|
| 1532 |
+
<axis xyz="0 0 -1"/>
|
| 1533 |
+
<limit effort="304" lower="-2.03" upper="2.51" velocity="8.8"/>
|
| 1534 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1535 |
+
</joint>
|
| 1536 |
+
<joint name="hip_pitch_4" type="revolute">
|
| 1537 |
+
<parent link="hip1_4"/>
|
| 1538 |
+
<child link="hip2_4"/>
|
| 1539 |
+
<origin rpy="1.57079632679 0.0 0.0" xyz="0.0 -0.1146 -0.0625"/>
|
| 1540 |
+
<axis xyz="0 0 1"/>
|
| 1541 |
+
<limit effort="304" lower="-2.0326" upper="2.0524" velocity="8.8"/>
|
| 1542 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1543 |
+
</joint>
|
| 1544 |
+
<joint name="knee_pitch_4" type="revolute">
|
| 1545 |
+
<parent link="hip2_4"/>
|
| 1546 |
+
<child link="knee_4"/>
|
| 1547 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 -0.3 -0.1182"/>
|
| 1548 |
+
<axis xyz="0 0 1"/>
|
| 1549 |
+
<limit effort="304" lower="-2.4176" upper="2.3884" velocity="8.8"/>
|
| 1550 |
+
<!-- 200 Nm, 1 rad/s-->
|
| 1551 |
+
</joint>
|
| 1552 |
+
<joint name="ankle_pitch_4" type="revolute">
|
| 1553 |
+
<parent link="knee_4"/>
|
| 1554 |
+
<child link="ankle1_4"/>
|
| 1555 |
+
<origin rpy="3.14159265359 0.0 0.0" xyz="0.0 0.2 -0.10015"/>
|
| 1556 |
+
<axis xyz="0 0 1"/>
|
| 1557 |
+
<limit effort="147" lower="-2.3426" upper="2.3934" velocity="8.1"/>
|
| 1558 |
+
<!-- 98 Nm, 1 rad/s-->
|
| 1559 |
+
</joint>
|
| 1560 |
+
<joint name="ankle_yaw_4" type="revolute">
|
| 1561 |
+
<parent link="ankle1_4"/>
|
| 1562 |
+
<child link="ankle2_4"/>
|
| 1563 |
+
<origin rpy="-1.57079632679 0.0 0.0" xyz="0.0 -0.139 0.00085"/>
|
| 1564 |
+
<axis xyz="0 0 -1"/>
|
| 1565 |
+
<limit effort="35" lower="-2.6046" upper="2.5514" velocity="20.0"/>
|
| 1566 |
+
<!-- 23 Nm, 1 rad/s-->
|
| 1567 |
+
</joint>
|
| 1568 |
+
<!-- ************ Control frames ************ -->
|
| 1569 |
+
</robot>
|
bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/centauro_rhc.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from aug_mpc.controllers.rhc.horizon_based.hybrid_quad_rhc import HybridQuadRhc
|
| 2 |
+
|
| 3 |
+
import numpy as np
|
| 4 |
+
|
| 5 |
+
from typing import Dict
|
| 6 |
+
|
| 7 |
+
from centaurohybridmpc.utils.sysutils import PathsGetter
|
| 8 |
+
|
| 9 |
+
class CentauroRhc(HybridQuadRhc):
|
| 10 |
+
|
| 11 |
+
def __init__(self,
|
| 12 |
+
srdf_path: str,
|
| 13 |
+
urdf_path: str,
|
| 14 |
+
robot_name: str, # used for shared memory namespaces
|
| 15 |
+
codegen_dir: str,
|
| 16 |
+
n_nodes: float = 31,
|
| 17 |
+
dt: float = 0.03,
|
| 18 |
+
injection_node: int = 10,
|
| 19 |
+
max_solver_iter = 1, # defaults to rt-iteration
|
| 20 |
+
open_loop: bool = True,
|
| 21 |
+
close_loop_all: bool = False,
|
| 22 |
+
dtype = np.float32,
|
| 23 |
+
verbose = False,
|
| 24 |
+
debug = False,
|
| 25 |
+
refs_in_hor_frame = True,
|
| 26 |
+
timeout_ms: int = 60000,
|
| 27 |
+
custom_opts: Dict = {}
|
| 28 |
+
):
|
| 29 |
+
|
| 30 |
+
paths = PathsGetter()
|
| 31 |
+
self._files_suffix=""
|
| 32 |
+
if open_loop:
|
| 33 |
+
self._files_suffix="_open"
|
| 34 |
+
|
| 35 |
+
self._add_upper_body=False
|
| 36 |
+
if ("add_upper_body" in custom_opts) and \
|
| 37 |
+
(custom_opts["add_upper_body"]):
|
| 38 |
+
self._add_upper_body=True
|
| 39 |
+
self._files_suffix+="_ub"
|
| 40 |
+
|
| 41 |
+
config_path=paths.RHCCONFIGPATH_NO_WHEELS+self._files_suffix+".yaml"
|
| 42 |
+
|
| 43 |
+
super().__init__(srdf_path=srdf_path,
|
| 44 |
+
urdf_path=urdf_path,
|
| 45 |
+
config_path=config_path,
|
| 46 |
+
robot_name=robot_name, # used for shared memory namespaces
|
| 47 |
+
codegen_dir=codegen_dir,
|
| 48 |
+
n_nodes=n_nodes,
|
| 49 |
+
dt=dt,
|
| 50 |
+
injection_node=injection_node,
|
| 51 |
+
max_solver_iter=max_solver_iter, # defaults to rt-iteration
|
| 52 |
+
open_loop=open_loop,
|
| 53 |
+
close_loop_all=close_loop_all,
|
| 54 |
+
dtype=dtype,
|
| 55 |
+
verbose=verbose,
|
| 56 |
+
debug=debug,
|
| 57 |
+
refs_in_hor_frame=refs_in_hor_frame,
|
| 58 |
+
timeout_ms=timeout_ms,
|
| 59 |
+
custom_opts=custom_opts)
|
| 60 |
+
|
| 61 |
+
self._fail_idx_scale=1e-9
|
| 62 |
+
self._fail_idx_thresh_open_loop=1e0
|
| 63 |
+
self._fail_idx_thresh_close_loop=10
|
| 64 |
+
|
| 65 |
+
if open_loop:
|
| 66 |
+
self._fail_idx_thresh=self._fail_idx_thresh_open_loop
|
| 67 |
+
else:
|
| 68 |
+
self._fail_idx_thresh=self._fail_idx_thresh_close_loop
|
| 69 |
+
|
| 70 |
+
# adding some additional config files for jnt imp control
|
| 71 |
+
self._rhc_fpaths.append(paths.JNT_IMP_CONFIG_XBOT+".yaml")
|
| 72 |
+
self._rhc_fpaths.append(paths.JNT_IMP_CONFIG+".yaml")
|
| 73 |
+
|
| 74 |
+
def _set_rhc_pred_idx(self):
|
| 75 |
+
self._pred_node_idx=round((self._n_nodes-1)*2/3)
|
| 76 |
+
|
| 77 |
+
def _set_rhc_cmds_idx(self):
|
| 78 |
+
self._rhc_cmds_node_idx=2
|
| 79 |
+
|
| 80 |
+
def _config_override(self):
|
| 81 |
+
paths = PathsGetter()
|
| 82 |
+
if ("control_wheels" in self._custom_opts):
|
| 83 |
+
if self._custom_opts["control_wheels"]:
|
| 84 |
+
self.config_path = paths.RHCCONFIGPATH_WHEELS+self._files_suffix+".yaml"
|
| 85 |
+
if ("fix_yaw" in self._custom_opts) and \
|
| 86 |
+
(self._custom_opts["fix_yaw"]):
|
| 87 |
+
self.config_path = paths.RHCCONFIGPATH_WHEELS_NO_YAW+self._files_suffix+".yaml"
|
| 88 |
+
if ("replace_continuous_joints" in self._custom_opts) and \
|
| 89 |
+
(not self._custom_opts["replace_continuous_joints"]):
|
| 90 |
+
# use continuous joints -> different config
|
| 91 |
+
self.config_path = paths.RHCCONFIGPATH_WHEELS_CONTINUOUS+self._files_suffix+".yaml"
|
| 92 |
+
if ("fix_yaw" in self._custom_opts) and \
|
| 93 |
+
(self._custom_opts["fix_yaw"]):
|
| 94 |
+
self.config_path = paths.RHCCONFIGPATH_WHEELS_CONTINUOUS_NO_YAW+self._files_suffix+".yaml"
|
| 95 |
+
|
| 96 |
+
else:
|
| 97 |
+
self._custom_opts["control_wheels"]=False
|
| 98 |
+
|
| 99 |
+
if not self._custom_opts["control_wheels"]:
|
| 100 |
+
self._fixed_jnt_patterns=self._fixed_jnt_patterns+\
|
| 101 |
+
["j_wheel",
|
| 102 |
+
"ankle_yaw"]
|
| 103 |
+
self._custom_opts["replace_continuous_joints"]=True
|
| 104 |
+
|
| 105 |
+
def _init_problem(self):
|
| 106 |
+
|
| 107 |
+
if not self._custom_opts["control_wheels"]:
|
| 108 |
+
self._yaw_vertical_weight=120.0
|
| 109 |
+
else:
|
| 110 |
+
self._yaw_vertical_weight=50.0
|
| 111 |
+
|
| 112 |
+
fixed_jnts_patterns=[
|
| 113 |
+
"d435_head",
|
| 114 |
+
"velodyne_joint",
|
| 115 |
+
"dagana"]
|
| 116 |
+
|
| 117 |
+
if not self._add_upper_body:
|
| 118 |
+
fixed_jnts_patterns.append("j_arm")
|
| 119 |
+
fixed_jnts_patterns.append("torso")
|
| 120 |
+
|
| 121 |
+
if ("fix_yaw" in self._custom_opts) and \
|
| 122 |
+
(self._custom_opts["fix_yaw"]):
|
| 123 |
+
fixed_jnts_patterns.append("ankle_yaw")
|
| 124 |
+
|
| 125 |
+
flight_duration_sec=0.5 # [s]
|
| 126 |
+
flight_duration=int(flight_duration_sec/self._dt)
|
| 127 |
+
post_flight_duration_sec=0.2 # [s]
|
| 128 |
+
post_flight_duration=int(post_flight_duration_sec/self._dt)
|
| 129 |
+
|
| 130 |
+
step_height=0.1
|
| 131 |
+
if ("step_height" in self._custom_opts):
|
| 132 |
+
step_height=self._custom_opts["step_height"]
|
| 133 |
+
|
| 134 |
+
super()._init_problem(fixed_jnt_patterns=fixed_jnts_patterns,
|
| 135 |
+
wheels_patterns=["wheel_"],
|
| 136 |
+
foot_linkname="wheel_1",
|
| 137 |
+
flight_duration=flight_duration,
|
| 138 |
+
post_flight_stance=post_flight_duration,
|
| 139 |
+
step_height=step_height,
|
| 140 |
+
keep_yaw_vert=True,
|
| 141 |
+
yaw_vertical_weight=self._yaw_vertical_weight,
|
| 142 |
+
vertical_landing=True,
|
| 143 |
+
vertical_land_weight=10.0,
|
| 144 |
+
phase_force_reg=5e-2,
|
| 145 |
+
vel_bounds_weight=1.0)
|
bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/centauro_rhc_config_no_wheels_ub.yaml
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
solver:
|
| 2 |
+
type: ilqr
|
| 3 |
+
ipopt.linear_solver: ma57
|
| 4 |
+
ipopt.tol: 0.1
|
| 5 |
+
# ilqr.merit_der_threshold: 1e-3
|
| 6 |
+
# ilqr.defect_norm_threshold: 1e-3
|
| 7 |
+
ipopt.constr_viol_tol: 0.01
|
| 8 |
+
ilqr.constraint_violation_threshold: 1e-2
|
| 9 |
+
# ipopt.hessian_approximation: exact
|
| 10 |
+
ipopt.print_level: 5
|
| 11 |
+
ipopt.suppress_all_output: 'yes'
|
| 12 |
+
ipopt.sb: 'yes'
|
| 13 |
+
ilqr.suppress_all_output: 'yes'
|
| 14 |
+
ilqr.codegen_enabled: true
|
| 15 |
+
ilqr.codegen_workdir: /tmp/tyhio
|
| 16 |
+
ilqr.enable_gn: true
|
| 17 |
+
ilqr.hxx_reg_base: 0.0
|
| 18 |
+
ilqr.n_threads: 0
|
| 19 |
+
print_time: 0
|
| 20 |
+
|
| 21 |
+
constraints:
|
| 22 |
+
- contact_1
|
| 23 |
+
- contact_2
|
| 24 |
+
- contact_3
|
| 25 |
+
- contact_4
|
| 26 |
+
|
| 27 |
+
costs:
|
| 28 |
+
- z_contact_1
|
| 29 |
+
- z_contact_2
|
| 30 |
+
- z_contact_3
|
| 31 |
+
- z_contact_4
|
| 32 |
+
# - vz_contact_1
|
| 33 |
+
# - vz_contact_2
|
| 34 |
+
# - vz_contact_3
|
| 35 |
+
# - vz_contact_4
|
| 36 |
+
- base_lin_velxy
|
| 37 |
+
- base_lin_velz
|
| 38 |
+
- base_omega
|
| 39 |
+
- base_capture
|
| 40 |
+
- joint_posture_capture
|
| 41 |
+
- v_regularization
|
| 42 |
+
- a_regularization
|
| 43 |
+
# - force_regularization
|
| 44 |
+
|
| 45 |
+
#open loop
|
| 46 |
+
.define:
|
| 47 |
+
- &w_base_omega 15.
|
| 48 |
+
- &w_base_vxy 18.
|
| 49 |
+
- &w_base_vz 15.
|
| 50 |
+
- &w_base_z 15.
|
| 51 |
+
- &w_contact_z 200.0
|
| 52 |
+
- &w_contact_vz 250.0
|
| 53 |
+
- &w_base_capture 200.
|
| 54 |
+
- &wheel_radius 0.124
|
| 55 |
+
|
| 56 |
+
base_lin_velxy:
|
| 57 |
+
type: Cartesian
|
| 58 |
+
distal_link: base_link
|
| 59 |
+
indices: [0, 1]
|
| 60 |
+
nodes: ${range(1, N-5)}
|
| 61 |
+
cartesian_type: velocity
|
| 62 |
+
weight: *w_base_vxy
|
| 63 |
+
|
| 64 |
+
base_lin_velz:
|
| 65 |
+
type: Cartesian
|
| 66 |
+
distal_link: base_link
|
| 67 |
+
indices: [2]
|
| 68 |
+
nodes: ${range(1, N-5)}
|
| 69 |
+
cartesian_type: velocity
|
| 70 |
+
weight: *w_base_vz
|
| 71 |
+
|
| 72 |
+
base_omega:
|
| 73 |
+
type: Cartesian
|
| 74 |
+
distal_link: base_link
|
| 75 |
+
indices: [3, 4, 5]
|
| 76 |
+
nodes: ${range(1, N-5)}
|
| 77 |
+
cartesian_type: velocity
|
| 78 |
+
weight: *w_base_omega
|
| 79 |
+
|
| 80 |
+
base_capture:
|
| 81 |
+
type: Cartesian
|
| 82 |
+
distal_link: base_link
|
| 83 |
+
indices: [0, 1, 2, 3, 4, 5]
|
| 84 |
+
nodes: ${range(N-5, N+1)}
|
| 85 |
+
cartesian_type: velocity
|
| 86 |
+
weight: *w_base_capture
|
| 87 |
+
|
| 88 |
+
# ===============================
|
| 89 |
+
|
| 90 |
+
zero_velocity_contact_1:
|
| 91 |
+
type: Cartesian
|
| 92 |
+
base_link: "world"
|
| 93 |
+
distal_link: wheel_1
|
| 94 |
+
indices: [0, 1, 2]
|
| 95 |
+
cartesian_type: velocity
|
| 96 |
+
# offset: *wheel_radius
|
| 97 |
+
|
| 98 |
+
zero_velocity_contact_2:
|
| 99 |
+
type: Cartesian
|
| 100 |
+
base_link: "world"
|
| 101 |
+
distal_link: wheel_2
|
| 102 |
+
indices: [0, 1, 2]
|
| 103 |
+
cartesian_type: velocity
|
| 104 |
+
# offset: *wheel_radius
|
| 105 |
+
|
| 106 |
+
zero_velocity_contact_3:
|
| 107 |
+
type: Cartesian
|
| 108 |
+
base_link: "world"
|
| 109 |
+
distal_link: wheel_3
|
| 110 |
+
indices: [0, 1, 2]
|
| 111 |
+
cartesian_type: velocity
|
| 112 |
+
# offset: *wheel_radius
|
| 113 |
+
|
| 114 |
+
zero_velocity_contact_4:
|
| 115 |
+
type: Cartesian
|
| 116 |
+
base_link: "world"
|
| 117 |
+
distal_link: wheel_4
|
| 118 |
+
indices: [0, 1, 2]
|
| 119 |
+
cartesian_type: velocity
|
| 120 |
+
# offset: *wheel_radius
|
| 121 |
+
|
| 122 |
+
# ==================================
|
| 123 |
+
|
| 124 |
+
interaction_contact_1:
|
| 125 |
+
type: VertexForce
|
| 126 |
+
frame: contact_1
|
| 127 |
+
fn_min: 100.0
|
| 128 |
+
enable_fc: true
|
| 129 |
+
friction_coeff: 0.2
|
| 130 |
+
vertex_frames:
|
| 131 |
+
- wheel_1
|
| 132 |
+
|
| 133 |
+
interaction_contact_2:
|
| 134 |
+
type: VertexForce
|
| 135 |
+
frame: contact_2
|
| 136 |
+
fn_min: 100.0
|
| 137 |
+
enable_fc: true
|
| 138 |
+
friction_coeff: 0.2
|
| 139 |
+
vertex_frames:
|
| 140 |
+
- wheel_2
|
| 141 |
+
|
| 142 |
+
interaction_contact_3:
|
| 143 |
+
type: VertexForce
|
| 144 |
+
frame: contact_3
|
| 145 |
+
fn_min: 100.0
|
| 146 |
+
enable_fc: true
|
| 147 |
+
friction_coeff: 0.2
|
| 148 |
+
vertex_frames:
|
| 149 |
+
- wheel_3
|
| 150 |
+
|
| 151 |
+
interaction_contact_4:
|
| 152 |
+
type: VertexForce
|
| 153 |
+
frame: contact_4
|
| 154 |
+
fn_min: 100.0
|
| 155 |
+
enable_fc: true
|
| 156 |
+
friction_coeff: 0.2
|
| 157 |
+
vertex_frames:
|
| 158 |
+
- wheel_4
|
| 159 |
+
|
| 160 |
+
contact_1:
|
| 161 |
+
type: Contact
|
| 162 |
+
subtask: [interaction_contact_1, zero_velocity_contact_1]
|
| 163 |
+
|
| 164 |
+
contact_2:
|
| 165 |
+
type: Contact
|
| 166 |
+
subtask: [interaction_contact_2, zero_velocity_contact_2]
|
| 167 |
+
|
| 168 |
+
contact_3:
|
| 169 |
+
type: Contact
|
| 170 |
+
subtask: [interaction_contact_3, zero_velocity_contact_3]
|
| 171 |
+
|
| 172 |
+
contact_4:
|
| 173 |
+
type: Contact
|
| 174 |
+
subtask: [interaction_contact_4, zero_velocity_contact_4]
|
| 175 |
+
|
| 176 |
+
joint_posture_capture:
|
| 177 |
+
type: Postural
|
| 178 |
+
weight: [25.0, 10.0, 10.0, 10.0,
|
| 179 |
+
25.0, 10.0, 10.0, 10.0,
|
| 180 |
+
25.0, 10.0, 10.0, 10.0,
|
| 181 |
+
25.0, 10.0, 10.0, 10.0,
|
| 182 |
+
55.0,
|
| 183 |
+
25.0, 25.0, 25.0, 25.0, 25.0, 25.0,
|
| 184 |
+
25.0, 25.0, 25.0, 25.0, 25.0, 25.0]
|
| 185 |
+
indices: [0, 1, 2, 3,
|
| 186 |
+
4, 5, 6, 7,
|
| 187 |
+
8, 9, 10, 11,
|
| 188 |
+
12, 13, 14, 15,
|
| 189 |
+
16,
|
| 190 |
+
17, 18, 19, 20, 21, 22,
|
| 191 |
+
23, 24, 25, 26, 27, 28]
|
| 192 |
+
nodes: ${range(N-5, N+1)}
|
| 193 |
+
|
| 194 |
+
v_regularization:
|
| 195 |
+
type: Regularization
|
| 196 |
+
variable_name: v
|
| 197 |
+
nodes: ${range(0, N+1)}
|
| 198 |
+
indices: [0, 1, 2, 3, 4, 5,
|
| 199 |
+
6, 7, 8, 9,
|
| 200 |
+
10, 11, 12, 13,
|
| 201 |
+
14, 15, 16, 17,
|
| 202 |
+
18, 19, 20, 21,
|
| 203 |
+
22,
|
| 204 |
+
23, 24, 25, 26, 27, 28,
|
| 205 |
+
29, 30, 31, 32, 33, 34]
|
| 206 |
+
weight: [2e-1, 2e-1, 2e-1, 2e-1, 2e-1, 2e-1,
|
| 207 |
+
8e-1, 8e-1, 8e-1, 8e-1,
|
| 208 |
+
8e-1, 8e-1, 8e-1, 8e-1,
|
| 209 |
+
8e-1, 8e-1, 8e-1, 8e-1,
|
| 210 |
+
8e-1, 8e-1, 8e-1, 8e-1,
|
| 211 |
+
8e-1,
|
| 212 |
+
1.2, 1.2, 1.2, 1.2, 1.2, 1.2,
|
| 213 |
+
1.2, 1.2, 1.2, 1.2, 1.2, 1.2]
|
| 214 |
+
|
| 215 |
+
a_regularization:
|
| 216 |
+
type: Regularization
|
| 217 |
+
variable_name: a
|
| 218 |
+
nodes: ${range(0, N+1)}
|
| 219 |
+
indices: [0, 1, 2, 3, 4, 5,
|
| 220 |
+
6, 7, 8, 9,
|
| 221 |
+
10, 11, 12, 13,
|
| 222 |
+
14, 15, 16, 17,
|
| 223 |
+
18, 19, 20, 21,
|
| 224 |
+
22,
|
| 225 |
+
23, 24, 25, 26, 27, 28,
|
| 226 |
+
29, 30, 31, 32, 33, 34]
|
| 227 |
+
weight: [1e-1, 1e-1, 1e-1, 1e-1, 1e-1, 1e-1,
|
| 228 |
+
2e-1, 2e-1, 2e-1, 2e-1,
|
| 229 |
+
2e-1, 2e-1, 2e-1, 2e-1,
|
| 230 |
+
2e-1, 2e-1, 2e-1, 2e-1,
|
| 231 |
+
2e-1, 2e-1, 2e-1, 2e-1,
|
| 232 |
+
2e-1,
|
| 233 |
+
2e-1, 2e-1, 2e-1, 2e-1, 2e-1, 2e-1,
|
| 234 |
+
2e-1, 2e-1, 2e-1, 2e-1, 2e-1, 2e-1]
|
| 235 |
+
|
| 236 |
+
# flight phase traj tracking
|
| 237 |
+
z_contact_1:
|
| 238 |
+
type: Cartesian
|
| 239 |
+
distal_link: contact_1
|
| 240 |
+
indices: [2]
|
| 241 |
+
cartesian_type: position
|
| 242 |
+
weight: *w_contact_z
|
| 243 |
+
|
| 244 |
+
z_contact_2:
|
| 245 |
+
type: Cartesian
|
| 246 |
+
distal_link: contact_2
|
| 247 |
+
indices: [2]
|
| 248 |
+
cartesian_type: position
|
| 249 |
+
weight: *w_contact_z
|
| 250 |
+
|
| 251 |
+
z_contact_3:
|
| 252 |
+
type: Cartesian
|
| 253 |
+
distal_link: contact_3
|
| 254 |
+
indices: [2]
|
| 255 |
+
cartesian_type: position
|
| 256 |
+
weight: *w_contact_z
|
| 257 |
+
|
| 258 |
+
z_contact_4:
|
| 259 |
+
type: Cartesian
|
| 260 |
+
distal_link: contact_4
|
| 261 |
+
indices: [2]
|
| 262 |
+
cartesian_type: position
|
| 263 |
+
weight: *w_contact_z
|
| 264 |
+
|
| 265 |
+
vz_contact_1:
|
| 266 |
+
type: Cartesian
|
| 267 |
+
base_link: base_link
|
| 268 |
+
distal_link: contact_1
|
| 269 |
+
indices: [2]
|
| 270 |
+
cartesian_type: velocity
|
| 271 |
+
weight: *w_contact_vz
|
| 272 |
+
|
| 273 |
+
vz_contact_2:
|
| 274 |
+
type: Cartesian
|
| 275 |
+
base_link: base_link
|
| 276 |
+
distal_link: contact_2
|
| 277 |
+
indices: [2]
|
| 278 |
+
cartesian_type: velocity
|
| 279 |
+
weight: *w_contact_vz
|
| 280 |
+
|
| 281 |
+
vz_contact_3:
|
| 282 |
+
type: Cartesian
|
| 283 |
+
base_link: base_link
|
| 284 |
+
distal_link: contact_3
|
| 285 |
+
indices: [2]
|
| 286 |
+
cartesian_type: velocity
|
| 287 |
+
weight: *w_contact_vz
|
| 288 |
+
|
| 289 |
+
vz_contact_4:
|
| 290 |
+
type: Cartesian
|
| 291 |
+
base_link: base_link
|
| 292 |
+
distal_link: contact_4
|
| 293 |
+
indices: [2]
|
| 294 |
+
cartesian_type: velocity
|
| 295 |
+
weight: *w_contact_vz
|
bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv_model
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3303cf6df03c15e74cc116dd689f2d1593719b4b24c67f22a3a6289b1cd2158a
|
| 3 |
+
size 4452447
|
bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/fake_pos_tracking_env.py
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
from typing import Dict
|
| 4 |
+
|
| 5 |
+
import torch
|
| 6 |
+
|
| 7 |
+
from EigenIPC.PyEigenIPC import VLevel
|
| 8 |
+
|
| 9 |
+
from mpc_hive.utilities.math_utils_torch import world2base_frame
|
| 10 |
+
|
| 11 |
+
from aug_mpc_envs.training_envs.twist_tracking_env import TwistTrackingEnv
|
| 12 |
+
|
| 13 |
+
class FakePosTrackingEnv(TwistTrackingEnv):
|
| 14 |
+
"""Converts random planar position goals into twist references so the agent learns to drive the robot toward targets while managing contact scheduling."""
|
| 15 |
+
|
| 16 |
+
def __init__(self,
|
| 17 |
+
namespace: str,
|
| 18 |
+
actions_dim: int = 10,
|
| 19 |
+
verbose: bool = False,
|
| 20 |
+
vlevel: VLevel = VLevel.V1,
|
| 21 |
+
use_gpu: bool = True,
|
| 22 |
+
dtype: torch.dtype = torch.float32,
|
| 23 |
+
debug: bool = True,
|
| 24 |
+
override_agent_refs: bool = False,
|
| 25 |
+
timeout_ms: int = 60000,
|
| 26 |
+
env_opts: Dict = {}):
|
| 27 |
+
|
| 28 |
+
self._add_env_opt(env_opts, "max_distance", default=5.0) # [m]
|
| 29 |
+
self._add_env_opt(env_opts, "min_distance", default=0.0) # [m]
|
| 30 |
+
self._add_env_opt(env_opts, "max_vref", default=1.0) # [m/s]
|
| 31 |
+
self._add_env_opt(env_opts, "max_dp", default=5.0) # [m] after this, v ref saturates
|
| 32 |
+
self._add_env_opt(env_opts, "max_dt", default=env_opts["max_dp"]/ env_opts["max_vref"])
|
| 33 |
+
|
| 34 |
+
TwistTrackingEnv.__init__(self,
|
| 35 |
+
namespace=namespace,
|
| 36 |
+
actions_dim=actions_dim, # twist + contact flags
|
| 37 |
+
verbose=verbose,
|
| 38 |
+
vlevel=vlevel,
|
| 39 |
+
use_gpu=use_gpu,
|
| 40 |
+
dtype=dtype,
|
| 41 |
+
debug=debug,
|
| 42 |
+
override_agent_refs=override_agent_refs,
|
| 43 |
+
timeout_ms=timeout_ms,
|
| 44 |
+
env_opts=env_opts)
|
| 45 |
+
|
| 46 |
+
def get_file_paths(self):
|
| 47 |
+
paths=TwistTrackingEnv.get_file_paths(self)
|
| 48 |
+
paths.append(os.path.abspath(__file__))
|
| 49 |
+
return paths
|
| 50 |
+
|
| 51 |
+
def _custom_post_init(self):
|
| 52 |
+
TwistTrackingEnv._custom_post_init(self)
|
| 53 |
+
|
| 54 |
+
# position targets to be reached (wrt robot's pos at ep start)
|
| 55 |
+
self._p_trgt_w=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[:, 0:2].detach().clone()
|
| 56 |
+
self._p_delta_w=self._p_trgt_w.detach().clone()
|
| 57 |
+
self._dp_norm=torch.zeros((self._n_envs, 1),dtype=self._dtype,device=self._device)
|
| 58 |
+
self._dp_versor=self._p_trgt_w.detach().clone()
|
| 59 |
+
|
| 60 |
+
self._trgt_d=torch.zeros((self._n_envs, 1),dtype=self._dtype,device=self._device)
|
| 61 |
+
self._trgt_theta=torch.zeros((self._n_envs, 1),dtype=self._dtype,device=self._device)
|
| 62 |
+
|
| 63 |
+
def _update_loc_twist_refs(self):
|
| 64 |
+
# this is called at each env substep
|
| 65 |
+
|
| 66 |
+
self._compute_twist_ref_w()
|
| 67 |
+
|
| 68 |
+
if not self._override_agent_refs:
|
| 69 |
+
agent_p_ref_current=self._agent_refs.rob_refs.root_state.get(data_type="p",
|
| 70 |
+
gpu=self._use_gpu)
|
| 71 |
+
agent_p_ref_current[:, 0:2]=self._p_trgt_w
|
| 72 |
+
|
| 73 |
+
# then convert it to base ref local for the agent
|
| 74 |
+
robot_q = self._robot_state.root_state.get(data_type="q",gpu=self._use_gpu)
|
| 75 |
+
# rotate agent ref from world to robot base
|
| 76 |
+
world2base_frame(t_w=self._agent_twist_ref_current_w, q_b=robot_q,
|
| 77 |
+
t_out=self._agent_twist_ref_current_base_loc)
|
| 78 |
+
# write it to agent refs tensors
|
| 79 |
+
self._agent_refs.rob_refs.root_state.set(data_type="twist", data=self._agent_twist_ref_current_base_loc,
|
| 80 |
+
gpu=self._use_gpu)
|
| 81 |
+
|
| 82 |
+
def _compute_twist_ref_w(self, env_indxs: torch.Tensor = None):
|
| 83 |
+
|
| 84 |
+
# angular refs are not altered
|
| 85 |
+
if env_indxs is None:
|
| 86 |
+
# we update the position error using the current base position
|
| 87 |
+
self._p_delta_w[:, :]=self._p_trgt_w-\
|
| 88 |
+
self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[:, 0:2]
|
| 89 |
+
|
| 90 |
+
self._dp_norm[:, :]=self._p_delta_w.norm(dim=1,keepdim=True)+1e-6
|
| 91 |
+
self._dp_versor[:, :]=self._p_delta_w/self._dp_norm
|
| 92 |
+
|
| 93 |
+
# apply for vref saturation
|
| 94 |
+
to_be_saturated=self._dp_norm[:, :]>self._env_opts["max_dp"]
|
| 95 |
+
self._dp_norm[to_be_saturated.flatten(), :]=self._env_opts["max_dp"]
|
| 96 |
+
|
| 97 |
+
# we compute the twist refs for the agent depending of the position error
|
| 98 |
+
self._agent_twist_ref_current_w[:, 0:2]=self._dp_norm*self._dp_versor/self._env_opts["max_dt"]
|
| 99 |
+
self._agent_twist_ref_current_w[:, 2:3]=0 # no vertical vel
|
| 100 |
+
|
| 101 |
+
# apply pof0 using last value of bernoully coeffs
|
| 102 |
+
self._agent_twist_ref_current_w[:, 0:3] = self._agent_twist_ref_current_w[:, 0:3]*self._bernoulli_coeffs_linvel # linvel
|
| 103 |
+
self._agent_twist_ref_current_w[:, 3:6] = self._agent_twist_ref_current_w[:, 3:6]*self._bernoulli_coeffs_omega # omega
|
| 104 |
+
else:
|
| 105 |
+
self._p_delta_w[env_indxs, :]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[env_indxs, 0:2] -\
|
| 106 |
+
self._p_trgt_w[env_indxs, :]
|
| 107 |
+
|
| 108 |
+
# apply for vref saturation
|
| 109 |
+
to_be_saturated=torch.logical_and((self._dp_norm[:, :]>self._env_opts["max_dp"]).flatten(),env_indxs)
|
| 110 |
+
self._dp_norm[to_be_saturated.flatten(), :]=self._env_opts["max_dp"]
|
| 111 |
+
|
| 112 |
+
self._dp_norm[env_indxs, :]=self._p_delta_w[env_indxs, :].norm(dim=1,keepdim=True)+1e-6
|
| 113 |
+
self._dp_versor[env_indxs, :]=self._p_delta_w[env_indxs, :]/self._dp_norm[env_indxs, :]
|
| 114 |
+
|
| 115 |
+
self._agent_twist_ref_current_w[env_indxs, 0:2]=self._dp_norm[env_indxs, :]*self._dp_versor[env_indxs, :]/self._env_opts["max_dt"]
|
| 116 |
+
self._agent_twist_ref_current_w[env_indxs, 2:3]=0 # no vertical vel
|
| 117 |
+
|
| 118 |
+
# apply pof0 using last value of bernoully coeffs
|
| 119 |
+
self._agent_twist_ref_current_w[env_indxs, 0:3] = self._agent_twist_ref_current_w[env_indxs, 0:3]*self._bernoulli_coeffs_linvel[env_indxs, :]
|
| 120 |
+
self._agent_twist_ref_current_w[env_indxs, 3:6] = self._agent_twist_ref_current_w[env_indxs, 3:6]*self._bernoulli_coeffs_omega[env_indxs, :] # omega
|
| 121 |
+
|
| 122 |
+
def _override_refs(self,
|
| 123 |
+
env_indxs: torch.Tensor = None):
|
| 124 |
+
|
| 125 |
+
# runs at every post_step
|
| 126 |
+
self._agent_refs.rob_refs.root_state.synch_all(read=True,retry=True) # first read from mem
|
| 127 |
+
if self._use_gpu:
|
| 128 |
+
# copies latest refs to GPU
|
| 129 |
+
self._agent_refs.rob_refs.root_state.synch_mirror(from_gpu=False,non_blocking=False)
|
| 130 |
+
|
| 131 |
+
agent_p_ref_current=self._agent_refs.rob_refs.root_state.get(data_type="p",
|
| 132 |
+
gpu=self._use_gpu)
|
| 133 |
+
|
| 134 |
+
agent_yaw_omega_ref_current=self._agent_refs.rob_refs.root_state.get(data_type="omega",
|
| 135 |
+
gpu=self._use_gpu)
|
| 136 |
+
|
| 137 |
+
# self._p_trgt_w[:, :]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[:, 0:2] + \
|
| 138 |
+
# agent_p_ref_current[:, 0:2]
|
| 139 |
+
self._p_trgt_w[:, :]=agent_p_ref_current[:, 0:2] # set p target target from shared mem
|
| 140 |
+
|
| 141 |
+
self._agent_twist_ref_current_w[:, 5:6]=agent_yaw_omega_ref_current[:, 2:3] # set yaw ang. vel target from shared mem
|
| 142 |
+
|
| 143 |
+
def _debug_agent_refs(self):
|
| 144 |
+
if self._use_gpu:
|
| 145 |
+
self._agent_refs.rob_refs.root_state.synch_mirror(from_gpu=True,non_blocking=False)
|
| 146 |
+
self._agent_refs.rob_refs.root_state.synch_all(read=False, retry = True)
|
| 147 |
+
|
| 148 |
+
def _randomize_task_refs(self,
|
| 149 |
+
env_indxs: torch.Tensor = None):
|
| 150 |
+
|
| 151 |
+
# we randomize the target position/omega in world frame
|
| 152 |
+
if env_indxs is None:
|
| 153 |
+
self._trgt_d.uniform_(self._env_opts["min_distance"], self._env_opts["max_distance"])
|
| 154 |
+
self._trgt_theta.uniform_(0.0, 2*torch.pi)
|
| 155 |
+
|
| 156 |
+
self._p_trgt_w[:, :]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[:, 0:2] +\
|
| 157 |
+
torch.cat((self._trgt_d*torch.cos(self._trgt_theta)
|
| 158 |
+
,self._trgt_d*torch.sin(self._trgt_theta)), dim=1)
|
| 159 |
+
|
| 160 |
+
# randomize just omega
|
| 161 |
+
random_uniform=torch.full_like(self._agent_twist_ref_current_w[:, 3:6], fill_value=0.0)
|
| 162 |
+
torch.nn.init.uniform_(random_uniform, a=-1, b=1)
|
| 163 |
+
self._agent_twist_ref_current_w[:, 3:6] = random_uniform*self._twist_ref_scale[:, 3:6] + self._twist_ref_offset[:, 3:6]
|
| 164 |
+
|
| 165 |
+
# sample for all envs pof0
|
| 166 |
+
if self._env_opts["use_pof0"]: # sample from bernoulli distribution and update coefficients
|
| 167 |
+
torch.bernoulli(input=self._pof1_b_linvel,out=self._bernoulli_coeffs_linvel) # by default bernoulli_coeffs are 1 if not self._env_opts["use_pof0"]
|
| 168 |
+
torch.bernoulli(input=self._pof1_b_omega,out=self._bernoulli_coeffs_omega)
|
| 169 |
+
|
| 170 |
+
else:
|
| 171 |
+
|
| 172 |
+
if env_indxs.any():
|
| 173 |
+
integer_idxs=torch.nonzero(env_indxs).flatten()
|
| 174 |
+
|
| 175 |
+
trgt_d_selected=self._trgt_d[integer_idxs, :]
|
| 176 |
+
trgt_d_selected.uniform_(self._env_opts["min_distance"], self._env_opts["max_distance"])
|
| 177 |
+
self._trgt_d[integer_idxs, :]=trgt_d_selected
|
| 178 |
+
|
| 179 |
+
trgt_theta_selected=self._trgt_theta[integer_idxs, :]
|
| 180 |
+
trgt_theta_selected.uniform_(0.0, 2*torch.pi)
|
| 181 |
+
self._trgt_theta[integer_idxs, :]=trgt_theta_selected
|
| 182 |
+
|
| 183 |
+
self._p_trgt_w[integer_idxs, 0:1]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[integer_idxs, 0:1] +\
|
| 184 |
+
self._trgt_d[integer_idxs, :]*torch.cos(self._trgt_theta[integer_idxs, :])
|
| 185 |
+
self._p_trgt_w[integer_idxs, 1:2]=self._robot_state.root_state.get(data_type="p",gpu=self._use_gpu)[integer_idxs, 1:2] +\
|
| 186 |
+
self._trgt_d[integer_idxs, :]*torch.sin(self._trgt_theta[integer_idxs, :])
|
| 187 |
+
|
| 188 |
+
# randomize just omega
|
| 189 |
+
random_uniform=torch.full_like(self._agent_twist_ref_current_w[env_indxs, 3:6], fill_value=0.0)
|
| 190 |
+
torch.nn.init.uniform_(random_uniform, a=-1, b=1)
|
| 191 |
+
self._agent_twist_ref_current_w[env_indxs, 3:6] = random_uniform*self._twist_ref_scale[:, 3:6] + self._twist_ref_offset[:, 3:6]
|
| 192 |
+
|
| 193 |
+
# sample for all envs pof0, then reset to 1 for envs which are not to be randomized
|
| 194 |
+
if self._env_opts["use_pof0"]: # sample from bernoulli distribution and update coefficients
|
| 195 |
+
torch.bernoulli(input=self._pof1_b_linvel,out=self._bernoulli_coeffs_linvel) # by default bernoulli_coeffs are 1 if not self._env_opts["use_pof0"]
|
| 196 |
+
torch.bernoulli(input=self._pof1_b_omega,out=self._bernoulli_coeffs_omega)
|
| 197 |
+
self._bernoulli_coeffs_linvel[~env_indxs, :]=1
|
| 198 |
+
self._bernoulli_coeffs_omega[~env_indxs, :]=1
|
| 199 |
+
|
| 200 |
+
self._compute_twist_ref_w(env_indxs=env_indxs) # update linear vel twist refs based on pos error
|
| 201 |
+
|
| 202 |
+
|
bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/hybrid_quad_rhc.py
ADDED
|
@@ -0,0 +1,1324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from mpc_hive.controllers.rhc import RHController
|
| 2 |
+
|
| 3 |
+
from aug_mpc.controllers.rhc.horizon_based.horizon_imports import *
|
| 4 |
+
|
| 5 |
+
from aug_mpc.controllers.rhc.horizon_based.hybrid_quad_rhc_refs import HybridQuadRhcRefs
|
| 6 |
+
from aug_mpc.controllers.rhc.horizon_based.gait_manager import GaitManager
|
| 7 |
+
|
| 8 |
+
from EigenIPC.PyEigenIPC import VLevel
|
| 9 |
+
from EigenIPC.PyEigenIPC import Journal, LogType
|
| 10 |
+
|
| 11 |
+
import numpy as np
|
| 12 |
+
|
| 13 |
+
import os
|
| 14 |
+
|
| 15 |
+
import time
|
| 16 |
+
|
| 17 |
+
from typing import Dict, List
|
| 18 |
+
|
| 19 |
+
class HybridQuadRhc(RHController):
|
| 20 |
+
|
| 21 |
+
def __init__(self,
|
| 22 |
+
srdf_path: str,
|
| 23 |
+
urdf_path: str,
|
| 24 |
+
config_path: str,
|
| 25 |
+
robot_name: str, # used for shared memory namespaces
|
| 26 |
+
codegen_dir: str,
|
| 27 |
+
n_nodes:float = 25,
|
| 28 |
+
injection_node:int = 10,
|
| 29 |
+
dt: float = 0.02,
|
| 30 |
+
max_solver_iter = 1, # defaults to rt-iteration
|
| 31 |
+
open_loop: bool = True,
|
| 32 |
+
close_loop_all: bool = False,
|
| 33 |
+
dtype = np.float32,
|
| 34 |
+
verbose = False,
|
| 35 |
+
debug = False,
|
| 36 |
+
refs_in_hor_frame = True,
|
| 37 |
+
timeout_ms: int = 60000,
|
| 38 |
+
custom_opts: Dict = {}):
|
| 39 |
+
|
| 40 |
+
self._refs_in_hor_frame = refs_in_hor_frame
|
| 41 |
+
|
| 42 |
+
self._injection_node = injection_node
|
| 43 |
+
|
| 44 |
+
self._open_loop = open_loop
|
| 45 |
+
self._close_loop_all = close_loop_all
|
| 46 |
+
|
| 47 |
+
self._codegen_dir = codegen_dir
|
| 48 |
+
if not os.path.exists(self._codegen_dir):
|
| 49 |
+
os.makedirs(self._codegen_dir)
|
| 50 |
+
# else:
|
| 51 |
+
# # Directory already exists, delete it and recreate
|
| 52 |
+
# shutil.rmtree(self._codegen_dir)
|
| 53 |
+
# os.makedirs(self._codegen_dir)
|
| 54 |
+
|
| 55 |
+
self.step_counter = 0
|
| 56 |
+
self.sol_counter = 0
|
| 57 |
+
|
| 58 |
+
self.max_solver_iter = max_solver_iter
|
| 59 |
+
|
| 60 |
+
self._timer_start = time.perf_counter()
|
| 61 |
+
self._prb_update_time = time.perf_counter()
|
| 62 |
+
self._phase_shift_time = time.perf_counter()
|
| 63 |
+
self._task_ref_update_time = time.perf_counter()
|
| 64 |
+
self._rti_time = time.perf_counter()
|
| 65 |
+
|
| 66 |
+
self.robot_name = robot_name
|
| 67 |
+
|
| 68 |
+
self.config_path = config_path
|
| 69 |
+
|
| 70 |
+
self.urdf_path = urdf_path
|
| 71 |
+
# read urdf and srdf files
|
| 72 |
+
with open(self.urdf_path, 'r') as file:
|
| 73 |
+
self.urdf = file.read()
|
| 74 |
+
self._base_init = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0])
|
| 75 |
+
|
| 76 |
+
self._c_timelines = dict()
|
| 77 |
+
self._f_reg_timelines = dict()
|
| 78 |
+
|
| 79 |
+
self._custom_opts={"replace_continuous_joints": False,
|
| 80 |
+
"use_force_feedback": False,
|
| 81 |
+
"lin_a_feedback": False,
|
| 82 |
+
"is_open_loop": self._open_loop, # fully open (just for db)
|
| 83 |
+
"fully_closed": False, # closed loop with full feedback (just for db)
|
| 84 |
+
"closed_partial": False, # closed loop with partial feedback
|
| 85 |
+
"adaptive_is": True, # closed loop with adaptation
|
| 86 |
+
"estimate_v_root": False, # when adaptive_is or closed_partial, estimate vbase
|
| 87 |
+
"alpha_from_outside": False, # alpha set ext. from shared memory
|
| 88 |
+
"alpha_half": 1.0,
|
| 89 |
+
"only_vel_wheels": True, # whether wheels (if present) are just vel controlled
|
| 90 |
+
"use_jnt_v_feedback": False
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
self._custom_opts.update(custom_opts)
|
| 94 |
+
|
| 95 |
+
self._alpha_half=self._custom_opts["alpha_half"]
|
| 96 |
+
|
| 97 |
+
if self._open_loop:
|
| 98 |
+
self._custom_opts["fully_closed"]=False
|
| 99 |
+
self._custom_opts["adaptive_is"]=False
|
| 100 |
+
self._custom_opts["closed_partial"]=False
|
| 101 |
+
else:
|
| 102 |
+
self._custom_opts["is_open_loop"]=False
|
| 103 |
+
if self._custom_opts["fully_closed"]:
|
| 104 |
+
self._custom_opts["adaptive_is"]=False
|
| 105 |
+
self._custom_opts["closed_partial"]=False
|
| 106 |
+
self._custom_opts["lin_a_feedback"]=False
|
| 107 |
+
if self._custom_opts["closed_partial"]:
|
| 108 |
+
self._custom_opts["adaptive_is"]=False
|
| 109 |
+
self._custom_opts["fully_closed"]=False
|
| 110 |
+
self._custom_opts["lin_a_feedback"]=False
|
| 111 |
+
if self._custom_opts["adaptive_is"]:
|
| 112 |
+
self._custom_opts["closed_partial"]=False
|
| 113 |
+
self._custom_opts["fully_closed"]=False
|
| 114 |
+
|
| 115 |
+
super().__init__(srdf_path=srdf_path,
|
| 116 |
+
n_nodes=n_nodes,
|
| 117 |
+
dt=dt,
|
| 118 |
+
namespace=self.robot_name,
|
| 119 |
+
dtype=dtype,
|
| 120 |
+
verbose=verbose,
|
| 121 |
+
debug=debug,
|
| 122 |
+
timeout_ms=timeout_ms)
|
| 123 |
+
|
| 124 |
+
self._rhc_fpaths.append(self.config_path)
|
| 125 |
+
|
| 126 |
+
def _config_override(self):
|
| 127 |
+
pass
|
| 128 |
+
|
| 129 |
+
def _post_problem_init(self):
|
| 130 |
+
|
| 131 |
+
self.rhc_costs={}
|
| 132 |
+
self.rhc_constr={}
|
| 133 |
+
|
| 134 |
+
self._fail_idx_scale=0.0
|
| 135 |
+
self._expl_idx_window_size=int(1*self._n_nodes)
|
| 136 |
+
self._explosion_idx_buffer=np.zeros((1,self._expl_idx_window_size))
|
| 137 |
+
self._expl_idx_counter=0
|
| 138 |
+
self._expl_idx_buffer_counter=0
|
| 139 |
+
|
| 140 |
+
self._pred_node_idx=self._n_nodes-1
|
| 141 |
+
|
| 142 |
+
self._nq=self.nq()
|
| 143 |
+
self._nq_jnts=self._nq-7# assuming floating base
|
| 144 |
+
self._nv=self.nv()
|
| 145 |
+
self._nv_jnts=self._nv-6
|
| 146 |
+
|
| 147 |
+
self._alphas_q_root=np.zeros((7, 1), dtype=self._dtype)
|
| 148 |
+
self._alphas_q_jnts=np.zeros((self._nq_jnts, 1), dtype=self._dtype)
|
| 149 |
+
self._alphas_twist_root=np.zeros((6, 1), dtype=self._dtype)
|
| 150 |
+
self._alphas_v_jnts=np.zeros((self._nv_jnts, 1), dtype=self._dtype)
|
| 151 |
+
self._alphas_a=np.zeros((self._nv, 1), dtype=self._dtype)
|
| 152 |
+
self._alphas_q_root[:, :]=1.0 # default to all open
|
| 153 |
+
self._alphas_q_jnts[:, :]=1.0
|
| 154 |
+
self._alphas_twist_root[:, :]=1.0
|
| 155 |
+
self._alphas_v_jnts[:, :]=1.0
|
| 156 |
+
self._alphas_a[:, :]=1.0
|
| 157 |
+
|
| 158 |
+
def _init_problem(self,
|
| 159 |
+
fixed_jnt_patterns: List[str] = None,
|
| 160 |
+
wheels_patterns: List[str] = None,
|
| 161 |
+
foot_linkname: str = None,
|
| 162 |
+
flight_duration: int = 10,
|
| 163 |
+
post_flight_stance: int = 3,
|
| 164 |
+
step_height: float = 0.12,
|
| 165 |
+
keep_yaw_vert: bool = False,
|
| 166 |
+
yaw_vertical_weight: float = 2.0,
|
| 167 |
+
vertical_landing: bool = False,
|
| 168 |
+
vertical_land_weight: float = 1.0,
|
| 169 |
+
phase_force_reg: float = 1e-2,
|
| 170 |
+
vel_bounds_weight: float = 1.0):
|
| 171 |
+
|
| 172 |
+
self._fixed_jnt_patterns=fixed_jnt_patterns
|
| 173 |
+
|
| 174 |
+
self._config_override()
|
| 175 |
+
|
| 176 |
+
Journal.log(self.__class__.__name__,
|
| 177 |
+
"_init_problem",
|
| 178 |
+
f" Will use horizon config file at {self.config_path}",
|
| 179 |
+
LogType.INFO,
|
| 180 |
+
throw_when_excep=True)
|
| 181 |
+
|
| 182 |
+
self._vel_bounds_weight=vel_bounds_weight
|
| 183 |
+
self._phase_force_reg=phase_force_reg
|
| 184 |
+
self._yaw_vertical_weight=yaw_vertical_weight
|
| 185 |
+
self._vertical_land_weight=vertical_land_weight
|
| 186 |
+
# overrides parent
|
| 187 |
+
self._prb = Problem(self._n_intervals,
|
| 188 |
+
receding=True,
|
| 189 |
+
casadi_type=cs.SX)
|
| 190 |
+
self._prb.setDt(self._dt)
|
| 191 |
+
|
| 192 |
+
if "replace_continuous_joints" in self._custom_opts:
|
| 193 |
+
# continous joints are parametrized in So2
|
| 194 |
+
if self._custom_opts["replace_continuous_joints"]:
|
| 195 |
+
self.urdf = self.urdf.replace('continuous', 'revolute')
|
| 196 |
+
else:
|
| 197 |
+
self.urdf = self.urdf.replace('continuous', 'revolute')
|
| 198 |
+
|
| 199 |
+
self._kin_dyn = casadi_kin_dyn.CasadiKinDyn(self.urdf) # used for getting joint names
|
| 200 |
+
self._assign_controller_side_jnt_names(jnt_names=self._get_robot_jnt_names())
|
| 201 |
+
|
| 202 |
+
self._init_robot_homer()
|
| 203 |
+
|
| 204 |
+
# handle fixed joints
|
| 205 |
+
fixed_joint_map={}
|
| 206 |
+
if self._fixed_jnt_patterns is not None:
|
| 207 |
+
for jnt_name in self._get_robot_jnt_names():
|
| 208 |
+
for fixed_jnt_pattern in self._fixed_jnt_patterns:
|
| 209 |
+
if fixed_jnt_pattern in jnt_name:
|
| 210 |
+
fixed_joint_map.update({f"{jnt_name}":
|
| 211 |
+
self._homer.get_homing_val(jnt_name=jnt_name)})
|
| 212 |
+
break # do not search for other pattern matches
|
| 213 |
+
|
| 214 |
+
if not len(fixed_joint_map)==0: # we need to recreate kin dyn and homers
|
| 215 |
+
Journal.log(self.__class__.__name__,
|
| 216 |
+
"_init_problem",
|
| 217 |
+
f"Will fix following joints: \n{str(fixed_joint_map)}",
|
| 218 |
+
LogType.INFO,
|
| 219 |
+
throw_when_excep=True)
|
| 220 |
+
# with the fixed joint map
|
| 221 |
+
self._kin_dyn = casadi_kin_dyn.CasadiKinDyn(self.urdf,fixed_joints=fixed_joint_map)
|
| 222 |
+
# assign again controlled joints names
|
| 223 |
+
self._assign_controller_side_jnt_names(jnt_names=self._get_robot_jnt_names())
|
| 224 |
+
# updated robot homer for controlled joints
|
| 225 |
+
self._init_robot_homer()
|
| 226 |
+
|
| 227 |
+
# handle continuous joints (need to change homing and retrieve
|
| 228 |
+
# cont jnts indexes) and homing
|
| 229 |
+
self._continuous_joints=self._get_continuous_jnt_names()
|
| 230 |
+
# reduced
|
| 231 |
+
self._continuous_joints_idxs=[]
|
| 232 |
+
self._continuous_joints_idxs_cos=[]
|
| 233 |
+
self._continuous_joints_idxs_sin=[]
|
| 234 |
+
self._continuous_joints_idxs_red=[]
|
| 235 |
+
self._rev_joints_idxs=[]
|
| 236 |
+
self._rev_joints_idxs_red=[]
|
| 237 |
+
# qfull
|
| 238 |
+
self._continuous_joints_idxs_qfull=[]
|
| 239 |
+
self._continuous_joints_idxs_cos_qfull=[]
|
| 240 |
+
self._continuous_joints_idxs_sin_qfull=[]
|
| 241 |
+
self._continuous_joints_idxs_red_qfull=[]
|
| 242 |
+
self._rev_joints_idxs_qfull=[]
|
| 243 |
+
self._rev_joints_idxs_red_qfull=[]
|
| 244 |
+
jnt_homing=[""]*(len(self._homer.get_homing())+len(self._continuous_joints))
|
| 245 |
+
jnt_names=self._get_robot_jnt_names()
|
| 246 |
+
for i in range(len(jnt_names)):
|
| 247 |
+
jnt=jnt_names[i]
|
| 248 |
+
index=self._get_jnt_id(jnt)# accounting for floating joint
|
| 249 |
+
homing_idx=index-7 # homing is only for actuated joints
|
| 250 |
+
homing_value=self._homer.get_homing_val(jnt)
|
| 251 |
+
if jnt in self._continuous_joints:
|
| 252 |
+
jnt_homing[homing_idx]=np.cos(homing_value).item()
|
| 253 |
+
jnt_homing[homing_idx+1]=np.sin(homing_value).item()
|
| 254 |
+
# just actuated joints
|
| 255 |
+
self._continuous_joints_idxs.append(homing_idx) # cos
|
| 256 |
+
self._continuous_joints_idxs.append(homing_idx+1) # sin
|
| 257 |
+
self._continuous_joints_idxs_cos.append(homing_idx)
|
| 258 |
+
self._continuous_joints_idxs_sin.append(homing_idx+1)
|
| 259 |
+
self._continuous_joints_idxs_red.append(i)
|
| 260 |
+
# q full
|
| 261 |
+
self._continuous_joints_idxs_qfull.append(index) # cos
|
| 262 |
+
self._continuous_joints_idxs_qfull.append(index+1) # sin
|
| 263 |
+
self._continuous_joints_idxs_cos_qfull.append(index)
|
| 264 |
+
self._continuous_joints_idxs_sin_qfull.append(index+1)
|
| 265 |
+
self._continuous_joints_idxs_red_qfull.append(i+7)
|
| 266 |
+
else:
|
| 267 |
+
jnt_homing[homing_idx]=homing_value
|
| 268 |
+
# just actuated joints
|
| 269 |
+
self._rev_joints_idxs.append(homing_idx)
|
| 270 |
+
self._rev_joints_idxs_red.append(i)
|
| 271 |
+
# q full
|
| 272 |
+
self._rev_joints_idxs_qfull.append(index)
|
| 273 |
+
self._rev_joints_idxs_red_qfull.append(i+7)
|
| 274 |
+
|
| 275 |
+
self._jnts_q_reduced=None
|
| 276 |
+
if not len(self._continuous_joints)==0:
|
| 277 |
+
cont_joints=", ".join(self._continuous_joints)
|
| 278 |
+
|
| 279 |
+
Journal.log(self.__class__.__name__,
|
| 280 |
+
"_init_problem",
|
| 281 |
+
f"The following continuous joints were found: \n{cont_joints}",
|
| 282 |
+
LogType.INFO,
|
| 283 |
+
throw_when_excep=True)
|
| 284 |
+
# preallocating data
|
| 285 |
+
self._jnts_q_reduced=np.zeros((1,self.nv()-6),dtype=self._dtype)
|
| 286 |
+
self._jnts_q_expanded=np.zeros((self.nq()-7,1),dtype=self._dtype)
|
| 287 |
+
self._full_q_reduced=np.zeros((7+len(jnt_names), self._n_nodes),dtype=self._dtype)
|
| 288 |
+
self._jnts_q_delta_expanded=np.zeros((self.nq()-7,1),dtype=self._dtype)
|
| 289 |
+
else:
|
| 290 |
+
self._custom_opts["replace_continuous_joints"]=True
|
| 291 |
+
Journal.log(self.__class__.__name__,
|
| 292 |
+
"_init_problem",
|
| 293 |
+
f"No continuous joints were found.",
|
| 294 |
+
LogType.INFO,
|
| 295 |
+
throw_when_excep=True)
|
| 296 |
+
|
| 297 |
+
# retrieve wheels indexes (not considering continuous joints,
|
| 298 |
+
# ok just for v, eff, etc..)
|
| 299 |
+
self._wheel_patterns=wheels_patterns
|
| 300 |
+
self._wheels_idxs_v=self._get_wheels_jnt_v_idxs(wheel_patterns=self._wheel_patterns)
|
| 301 |
+
self._f0 = [0, 0, self._kin_dyn.mass()/4*9.81]
|
| 302 |
+
|
| 303 |
+
# we can create an init for the base
|
| 304 |
+
init = self._base_init.tolist() + jnt_homing
|
| 305 |
+
|
| 306 |
+
if foot_linkname is not None:
|
| 307 |
+
FK = self._kin_dyn.fk(foot_linkname) # just to get robot reference height
|
| 308 |
+
ground_level = FK(q=init)['ee_pos']
|
| 309 |
+
self._base_init[2] = -ground_level[2] # override init
|
| 310 |
+
|
| 311 |
+
self._model = FullModelInverseDynamics(problem=self._prb,
|
| 312 |
+
kd=self._kin_dyn,
|
| 313 |
+
q_init=self._homer.get_homing_map(),
|
| 314 |
+
base_init=self._base_init)
|
| 315 |
+
|
| 316 |
+
self._ti = TaskInterface(prb=self._prb,
|
| 317 |
+
model=self._model,
|
| 318 |
+
max_solver_iter=self.max_solver_iter,
|
| 319 |
+
debug = self._debug,
|
| 320 |
+
verbose = self._verbose,
|
| 321 |
+
codegen_workdir = self._codegen_dir)
|
| 322 |
+
self._ti.setTaskFromYaml(self.config_path)
|
| 323 |
+
|
| 324 |
+
# setting initial base pos ref if exists
|
| 325 |
+
base_pos = self._ti.getTask('base_height')
|
| 326 |
+
if base_pos is not None:
|
| 327 |
+
base_pos.setRef(np.atleast_2d(self._base_init).T)
|
| 328 |
+
|
| 329 |
+
self._pm = pymanager.PhaseManager(self._n_nodes, debug=False) # intervals or nodes?????
|
| 330 |
+
|
| 331 |
+
self._gm = GaitManager(self._ti,
|
| 332 |
+
self._pm,
|
| 333 |
+
self._injection_node,
|
| 334 |
+
keep_yaw_vert=keep_yaw_vert,
|
| 335 |
+
yaw_vertical_weight=self._yaw_vertical_weight,
|
| 336 |
+
vertical_landing=vertical_landing,
|
| 337 |
+
landing_vert_weight=self._vertical_land_weight,
|
| 338 |
+
phase_force_reg=self._phase_force_reg,
|
| 339 |
+
custom_opts=self._custom_opts,
|
| 340 |
+
flight_duration=flight_duration,
|
| 341 |
+
post_flight_stance=post_flight_stance,
|
| 342 |
+
step_height=step_height,
|
| 343 |
+
dh=0.0)
|
| 344 |
+
|
| 345 |
+
self._ti.model.q.setBounds(self._ti.model.q0, self._ti.model.q0, nodes=0)
|
| 346 |
+
self._ti.model.v.setBounds(self._ti.model.v0, self._ti.model.v0, nodes=0)
|
| 347 |
+
self._ti.model.q.setInitialGuess(self._ti.model.q0)
|
| 348 |
+
self._ti.model.v.setInitialGuess(self._ti.model.v0)
|
| 349 |
+
for _, cforces in self._ti.model.cmap.items():
|
| 350 |
+
n_contact_f=len(cforces)
|
| 351 |
+
for c in cforces:
|
| 352 |
+
c.setInitialGuess(np.array(self._f0)/n_contact_f)
|
| 353 |
+
|
| 354 |
+
vel_lims = self._model.kd.velocityLimits()
|
| 355 |
+
import horizon.utils as utils
|
| 356 |
+
self._prb.createResidual('vel_lb_barrier', self._vel_bounds_weight*utils.utils.barrier(vel_lims[7:] - self._model.v[7:]))
|
| 357 |
+
self._prb.createResidual('vel_ub_barrier', self._vel_bounds_weight*utils.utils.barrier1(-1 * vel_lims[7:] - self._model.v[7:]))
|
| 358 |
+
|
| 359 |
+
self._meas_lin_a_par=None
|
| 360 |
+
# if self._custom_opts["lin_a_feedback"]:
|
| 361 |
+
# # acceleration feedback on first node
|
| 362 |
+
# self._meas_lin_a_par=self._prb.createParameter(name="lin_a_feedback",
|
| 363 |
+
# dim=3, nodes=0)
|
| 364 |
+
# base_lin_a_prb=self._prb.getInput().getVars()[0:3]
|
| 365 |
+
# self._prb.createConstraint('lin_acceleration_feedback', base_lin_a_prb - self._meas_lin_a_par,
|
| 366 |
+
# nodes=[0])
|
| 367 |
+
|
| 368 |
+
# if not self._open_loop:
|
| 369 |
+
# # we create a residual cost to be used as an attractor to the measured state on the first node
|
| 370 |
+
# # hard constraints injecting meas. states are pure EVIL!
|
| 371 |
+
# prb_state=self._prb.getState()
|
| 372 |
+
# full_state=prb_state.getVars()
|
| 373 |
+
# state_dim=prb_state.getBounds()[0].shape[0]
|
| 374 |
+
# meas_state=self._prb.createParameter(name="measured_state",
|
| 375 |
+
# dim=state_dim, nodes=0)
|
| 376 |
+
# self._prb.createResidual('meas_state_attractor', meas_state_attractor_weight * (full_state - meas_state),
|
| 377 |
+
# nodes=[0])
|
| 378 |
+
|
| 379 |
+
self._ti.finalize()
|
| 380 |
+
self._ti.bootstrap()
|
| 381 |
+
|
| 382 |
+
self._ti.init_inv_dyn_for_res() # we initialize some objects for sol. postprocessing purposes
|
| 383 |
+
self._ti.load_initial_guess()
|
| 384 |
+
|
| 385 |
+
self.n_dofs = self._get_ndofs() # after loading the URDF and creating the controller we
|
| 386 |
+
# know n_dofs -> we assign it (by default = None)
|
| 387 |
+
|
| 388 |
+
self.n_contacts = len(self._model.cmap.keys())
|
| 389 |
+
|
| 390 |
+
# remove variables bounds (before they were necessary to have a good
|
| 391 |
+
# quality bootstrap solution)
|
| 392 |
+
self._q_inf=np.zeros((self.nq(), 1))
|
| 393 |
+
self._q_inf[:, :]=np.inf
|
| 394 |
+
self._v_inf=np.zeros((self.nv(), 1))
|
| 395 |
+
self._v_inf[:, :]=np.inf
|
| 396 |
+
self._ti.model.q.setBounds(-self._q_inf, self._q_inf, nodes=0)
|
| 397 |
+
self._ti.model.v.setBounds(-self._v_inf, self._v_inf, nodes=0)
|
| 398 |
+
|
| 399 |
+
# self.horizon_anal = analyzer.ProblemAnalyzer(self._prb)
|
| 400 |
+
|
| 401 |
+
def get_file_paths(self):
|
| 402 |
+
# can be overriden by child
|
| 403 |
+
paths = super().get_file_paths()
|
| 404 |
+
return paths
|
| 405 |
+
|
| 406 |
+
def _get_quat_remap(self):
|
| 407 |
+
# overrides parent
|
| 408 |
+
return [1, 2, 3, 0] # mapping from robot quat. to Horizon's quaternion convention
|
| 409 |
+
|
| 410 |
+
def _zmp(self, model):
|
| 411 |
+
|
| 412 |
+
num = cs.SX([0, 0])
|
| 413 |
+
den = cs.SX([0])
|
| 414 |
+
pos_contact = dict()
|
| 415 |
+
force_val = dict()
|
| 416 |
+
|
| 417 |
+
q = cs.SX.sym('q', model.nq)
|
| 418 |
+
v = cs.SX.sym('v', model.nv)
|
| 419 |
+
a = cs.SX.sym('a', model.nv)
|
| 420 |
+
|
| 421 |
+
com = model.kd.centerOfMass()(q=q, v=v, a=a)['com']
|
| 422 |
+
|
| 423 |
+
n = cs.SX([0, 0, 1])
|
| 424 |
+
for c in model.fmap.keys():
|
| 425 |
+
pos_contact[c] = model.kd.fk(c)(q=q)['ee_pos']
|
| 426 |
+
force_val[c] = cs.SX.sym('force_val', 3)
|
| 427 |
+
num += (pos_contact[c][0:2] - com[0:2]) * cs.dot(force_val[c], n)
|
| 428 |
+
den += cs.dot(force_val[c], n)
|
| 429 |
+
|
| 430 |
+
zmp = com[0:2] + (num / den)
|
| 431 |
+
input_list = []
|
| 432 |
+
input_list.append(q)
|
| 433 |
+
input_list.append(v)
|
| 434 |
+
input_list.append(a)
|
| 435 |
+
|
| 436 |
+
for elem in force_val.values():
|
| 437 |
+
input_list.append(elem)
|
| 438 |
+
|
| 439 |
+
f = cs.Function('zmp', input_list, [zmp])
|
| 440 |
+
return f
|
| 441 |
+
|
| 442 |
+
def _add_zmp(self):
|
| 443 |
+
|
| 444 |
+
input_zmp = []
|
| 445 |
+
|
| 446 |
+
input_zmp.append(self._model.q)
|
| 447 |
+
input_zmp.append(self._model.v)
|
| 448 |
+
input_zmp.append(self._model.a)
|
| 449 |
+
|
| 450 |
+
for f_var in self._model.fmap.values():
|
| 451 |
+
input_zmp.append(f_var)
|
| 452 |
+
|
| 453 |
+
c_mean = cs.SX([0, 0, 0])
|
| 454 |
+
for c_name, f_var in self._model.fmap.items():
|
| 455 |
+
fk_c_pos = self._kin_dyn.fk(c_name)(q=self._model.q)['ee_pos']
|
| 456 |
+
c_mean += fk_c_pos
|
| 457 |
+
|
| 458 |
+
c_mean /= len(self._model.cmap.keys())
|
| 459 |
+
|
| 460 |
+
zmp_nominal_weight = 10.
|
| 461 |
+
zmp_fun = self._zmp(self._model)(*input_zmp)
|
| 462 |
+
|
| 463 |
+
if 'wheel_joint_1' in self._model.kd.joint_names():
|
| 464 |
+
zmp_residual = self._prb.createIntermediateResidual('zmp', zmp_nominal_weight * (zmp_fun[0:2] - c_mean[0:2]))
|
| 465 |
+
|
| 466 |
+
def _quaternion_multiply(self,
|
| 467 |
+
q1, q2):
|
| 468 |
+
x1, y1, z1, w1 = q1
|
| 469 |
+
x2, y2, z2, w2 = q2
|
| 470 |
+
w = w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2
|
| 471 |
+
x = w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2
|
| 472 |
+
y = w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2
|
| 473 |
+
z = w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2
|
| 474 |
+
return np.array([x, y, z, w])
|
| 475 |
+
|
| 476 |
+
def _get_continuous_jnt_names(self):
|
| 477 |
+
import xml.etree.ElementTree as ET
|
| 478 |
+
root = ET.fromstring(self.urdf)
|
| 479 |
+
continuous_joints = []
|
| 480 |
+
for joint in root.findall('joint'):
|
| 481 |
+
joint_type = joint.get('type')
|
| 482 |
+
if joint_type == 'continuous':
|
| 483 |
+
joint_name = joint.get('name')
|
| 484 |
+
continuous_joints.append(joint_name)
|
| 485 |
+
return continuous_joints
|
| 486 |
+
|
| 487 |
+
def _get_wheels_jnt_v_idxs(self, wheel_patterns: List[str]):
|
| 488 |
+
jnt_names=self._get_robot_jnt_names()
|
| 489 |
+
wheels_idxs=[]
|
| 490 |
+
for i in range(len(jnt_names)):
|
| 491 |
+
jnt_name=jnt_names[i]
|
| 492 |
+
for wheel_pattern in wheel_patterns:
|
| 493 |
+
if wheel_pattern in jnt_name:
|
| 494 |
+
wheels_idxs.append(i)
|
| 495 |
+
break
|
| 496 |
+
return wheels_idxs
|
| 497 |
+
|
| 498 |
+
def _get_jnt_id(self, jnt_name):
|
| 499 |
+
return self._kin_dyn.joint_iq(jnt_name)
|
| 500 |
+
|
| 501 |
+
def _init_rhc_task_cmds(self):
|
| 502 |
+
|
| 503 |
+
rhc_refs = HybridQuadRhcRefs(gait_manager=self._gm,
|
| 504 |
+
robot_index_shm=self.controller_index,
|
| 505 |
+
robot_index_view=0, # when using optimize_mem the view if always of shape 1x...
|
| 506 |
+
namespace=self.namespace,
|
| 507 |
+
safe=False,
|
| 508 |
+
verbose=self._verbose,
|
| 509 |
+
vlevel=VLevel.V2,
|
| 510 |
+
use_force_feedback=self._custom_opts["use_force_feedback"],
|
| 511 |
+
optimize_mem=True)
|
| 512 |
+
|
| 513 |
+
rhc_refs.run()
|
| 514 |
+
|
| 515 |
+
rhc_refs.rob_refs.set_jnts_remapping(jnts_remapping=self._to_controller)
|
| 516 |
+
rhc_refs.rob_refs.set_q_remapping(q_remapping=self._get_quat_remap())
|
| 517 |
+
|
| 518 |
+
rhc_refs.set_default_refs(p_ref=np.atleast_2d(self._base_init)[:, 0:3],
|
| 519 |
+
q_ref=np.atleast_2d(self._base_init)[:, 3:7])
|
| 520 |
+
|
| 521 |
+
return rhc_refs
|
| 522 |
+
|
| 523 |
+
def get_vertex_fnames_from_ti(self):
|
| 524 |
+
tasks=self._ti.task_list
|
| 525 |
+
contact_f_names=[]
|
| 526 |
+
for task in tasks:
|
| 527 |
+
if isinstance(task, ContactTask):
|
| 528 |
+
interaction_task=task.dynamics_tasks[0]
|
| 529 |
+
contact_f_names.append(interaction_task.vertex_frames[0])
|
| 530 |
+
return contact_f_names
|
| 531 |
+
|
| 532 |
+
def _get_contact_names(self):
|
| 533 |
+
# should get contact names from vertex frames
|
| 534 |
+
# list(self._ti.model.cmap.keys())
|
| 535 |
+
return self.get_vertex_fnames_from_ti()
|
| 536 |
+
|
| 537 |
+
def _get_robot_jnt_names(self):
|
| 538 |
+
|
| 539 |
+
joints_names = self._kin_dyn.joint_names()
|
| 540 |
+
to_be_removed = ["universe",
|
| 541 |
+
"reference",
|
| 542 |
+
"world",
|
| 543 |
+
"floating",
|
| 544 |
+
"floating_base"]
|
| 545 |
+
for name in to_be_removed:
|
| 546 |
+
if name in joints_names:
|
| 547 |
+
joints_names.remove(name)
|
| 548 |
+
|
| 549 |
+
return joints_names
|
| 550 |
+
|
| 551 |
+
def _get_ndofs(self):
|
| 552 |
+
return len(self._model.joint_names)
|
| 553 |
+
|
| 554 |
+
def nq(self):
|
| 555 |
+
return self._kin_dyn.nq()
|
| 556 |
+
|
| 557 |
+
def nv(self):
|
| 558 |
+
return self._kin_dyn.nv()
|
| 559 |
+
|
| 560 |
+
def _get_robot_mass(self):
|
| 561 |
+
|
| 562 |
+
return self._kin_dyn.mass()
|
| 563 |
+
|
| 564 |
+
def _get_root_full_q_from_sol(self, node_idx=1):
|
| 565 |
+
|
| 566 |
+
root_q_full=self._ti.solution['q'][0:7, node_idx].reshape(1, 7).astype(self._dtype)
|
| 567 |
+
|
| 568 |
+
np.nan_to_num(root_q_full, nan=1e3, posinf=1e3, neginf=-1e3, copy=False)
|
| 569 |
+
np.clip(a=root_q_full, a_min=-1e3, a_max=1e3, out=root_q_full)
|
| 570 |
+
|
| 571 |
+
return root_q_full
|
| 572 |
+
|
| 573 |
+
def _get_full_q_from_sol(self, node_idx=1):
|
| 574 |
+
|
| 575 |
+
return self._ti.solution['q'][:, node_idx].reshape(1, -1).astype(self._dtype)
|
| 576 |
+
|
| 577 |
+
def _get_root_twist_from_sol(self, node_idx=1):
|
| 578 |
+
# provided in world frame
|
| 579 |
+
twist_base_local=self._get_v_from_sol()[0:6, node_idx].reshape(1, 6)
|
| 580 |
+
# if world_aligned:
|
| 581 |
+
# q_root_rhc = self._get_root_full_q_from_sol(node_idx=node_idx)[:, 0:4]
|
| 582 |
+
# r_base_rhc=Rotation.from_quat(q_root_rhc.flatten()).as_matrix()
|
| 583 |
+
# twist_base_local[:, 0:3] = r_base_rhc @ twist_base_local[0, 0:3]
|
| 584 |
+
# twist_base_local[:, 3:6] = r_base_rhc @ twist_base_local[0, 3:6]
|
| 585 |
+
return twist_base_local
|
| 586 |
+
|
| 587 |
+
def _get_root_a_from_sol(self, node_idx=0):
|
| 588 |
+
# provided in world frame
|
| 589 |
+
a_base_local=self._get_a_from_sol()[0:6, node_idx].reshape(1, 6)
|
| 590 |
+
# if world_aligned:
|
| 591 |
+
# q_root_rhc = self._get_root_full_q_from_sol(node_idx=node_idx)[:, 0:4]
|
| 592 |
+
# r_base_rhc=Rotation.from_quat(q_root_rhc.flatten()).as_matrix()
|
| 593 |
+
# a_base_local[:, 0:3] = r_base_rhc @ a_base_local[0, 0:3]
|
| 594 |
+
# a_base_local[:, 3:6] = r_base_rhc @ v[0, 3:6]
|
| 595 |
+
return a_base_local
|
| 596 |
+
|
| 597 |
+
def _get_jnt_q_from_sol(self, node_idx=0,
|
| 598 |
+
reduce: bool = True,
|
| 599 |
+
clamp: bool = True):
|
| 600 |
+
|
| 601 |
+
full_jnts_q=self._ti.solution['q'][7:, node_idx:node_idx+1].reshape(1,-1).astype(self._dtype)
|
| 602 |
+
|
| 603 |
+
np.nan_to_num(full_jnts_q, nan=1e3, posinf=1e3, neginf=-1e3, copy=False) # in place
|
| 604 |
+
np.clip(a=full_jnts_q, a_max=1e3, a_min=-1e3, out=full_jnts_q) # in place
|
| 605 |
+
|
| 606 |
+
if self._custom_opts["replace_continuous_joints"] or (not reduce):
|
| 607 |
+
if clamp:
|
| 608 |
+
return np.fmod(full_jnts_q, 2*np.pi)
|
| 609 |
+
else:
|
| 610 |
+
return full_jnts_q
|
| 611 |
+
else:
|
| 612 |
+
cos_sin=full_jnts_q[:,self._continuous_joints_idxs].reshape(-1,2)
|
| 613 |
+
# copy rev joint vals
|
| 614 |
+
self._jnts_q_reduced[:, self._rev_joints_idxs_red]=np.fmod(full_jnts_q[:, self._rev_joints_idxs], 2*np.pi).reshape(1, -1)
|
| 615 |
+
# and continuous
|
| 616 |
+
self._jnts_q_reduced[:, self._continuous_joints_idxs_red]=np.arctan2(cos_sin[:, 1], cos_sin[:, 0]).reshape(1,-1)
|
| 617 |
+
return self._jnts_q_reduced
|
| 618 |
+
|
| 619 |
+
def _get_jnt_v_from_sol(self, node_idx=1):
|
| 620 |
+
|
| 621 |
+
jnt_v_sol=self._get_v_from_sol()[6:, node_idx].reshape(1,
|
| 622 |
+
self._nv_jnts)
|
| 623 |
+
np.nan_to_num(jnt_v_sol, nan=1e5, posinf=1e5, neginf=-1e5, copy=False) # in place
|
| 624 |
+
# np.clip(a=jnt_v_sol, a_max=1e5, a_min=-1e5, out=jnt_v_sol) # in place
|
| 625 |
+
|
| 626 |
+
return jnt_v_sol
|
| 627 |
+
|
| 628 |
+
def _get_jnt_a_from_sol(self, node_idx=1):
|
| 629 |
+
|
| 630 |
+
return self._get_a_from_sol()[6:, node_idx].reshape(1,
|
| 631 |
+
self._nv_jnts)
|
| 632 |
+
|
| 633 |
+
def _get_jnt_eff_from_sol(self, node_idx=0):
|
| 634 |
+
|
| 635 |
+
efforts_on_node = self._ti.eval_efforts_on_node(node_idx=node_idx)
|
| 636 |
+
|
| 637 |
+
# if self._custom_opts["only_vel_wheels"]:
|
| 638 |
+
|
| 639 |
+
jnt_efforts=efforts_on_node[6:, 0]
|
| 640 |
+
|
| 641 |
+
if self._custom_opts["only_vel_wheels"] and self._wheels_idxs_v:
|
| 642 |
+
jnt_efforts[self._wheels_idxs_v]=0.0
|
| 643 |
+
|
| 644 |
+
return jnt_efforts.reshape(1,
|
| 645 |
+
self._nv_jnts).astype(self._dtype)
|
| 646 |
+
|
| 647 |
+
def _get_rhc_cost(self):
|
| 648 |
+
|
| 649 |
+
return self._ti.solution["opt_cost"]
|
| 650 |
+
|
| 651 |
+
def _get_rhc_constr_viol(self):
|
| 652 |
+
|
| 653 |
+
return self._ti.solution["residual_norm"]
|
| 654 |
+
|
| 655 |
+
def _get_rhc_nodes_cost(self):
|
| 656 |
+
|
| 657 |
+
cost = self._ti.solver_rti.getCostValOnNodes()
|
| 658 |
+
return cost.reshape((1, -1))
|
| 659 |
+
|
| 660 |
+
def _get_rhc_nodes_constr_viol(self):
|
| 661 |
+
|
| 662 |
+
constr_viol = self._ti.solver_rti.getConstrValOnNodes()
|
| 663 |
+
return constr_viol.reshape((1, -1))
|
| 664 |
+
|
| 665 |
+
def _get_rhc_niter_to_sol(self):
|
| 666 |
+
|
| 667 |
+
return self._ti.solution["n_iter2sol"]
|
| 668 |
+
|
| 669 |
+
def _set_ig_bootstrap(self,
|
| 670 |
+
q_state: np.ndarray = None,
|
| 671 |
+
v_state: np.ndarray = None):
|
| 672 |
+
|
| 673 |
+
xig = self._ti.solution['x_opt'].copy()
|
| 674 |
+
uig = self._ti.solution['u_opt'].copy()
|
| 675 |
+
|
| 676 |
+
# Normalize and keep quaternion in the same hemisphere as the previous
|
| 677 |
+
# solution to avoid artificial 180-deg jumps in the bootstrap warm start.
|
| 678 |
+
q_state_boot = q_state.copy()
|
| 679 |
+
q_prev = xig[3:7, 0]
|
| 680 |
+
q_now = q_state_boot[3:7, 0]
|
| 681 |
+
|
| 682 |
+
q_now_norm = np.linalg.norm(q_now)
|
| 683 |
+
if q_now_norm > 1e-9:
|
| 684 |
+
q_state_boot[3:7, :] /= q_now_norm
|
| 685 |
+
else:
|
| 686 |
+
q_state_boot[3:7, :] = np.array([[0.0], [0.0], [0.0], [1.0]], dtype=self._dtype)
|
| 687 |
+
|
| 688 |
+
q_prev_norm = np.linalg.norm(q_prev)
|
| 689 |
+
if q_prev_norm > 1e-9:
|
| 690 |
+
q_prev = q_prev / q_prev_norm
|
| 691 |
+
|
| 692 |
+
q_now = q_state_boot[3:7, 0]
|
| 693 |
+
if np.dot(q_prev, q_now) < 0.0:
|
| 694 |
+
q_state_boot[3:7, :] *= -1.0
|
| 695 |
+
|
| 696 |
+
xig[0:self._nq, :] = q_state_boot
|
| 697 |
+
xig[self._nq:self._nq + self._nv, :] = 0.0 # 0 velocity on first nodes
|
| 698 |
+
uig[0:self._nv, :]=0.0 # 0 acceleration
|
| 699 |
+
|
| 700 |
+
# assigning ig
|
| 701 |
+
self._prb.getState().setInitialGuess(xig)
|
| 702 |
+
self._prb.getInput().setInitialGuess(uig)
|
| 703 |
+
# self._prb.getVariables("a").setInitialGuess(np.zeros((self._nv, 1), dtype=self._dtype))
|
| 704 |
+
for _, cforces in self._ti.model.cmap.items():
|
| 705 |
+
n_contact_f = len(cforces)
|
| 706 |
+
if n_contact_f == 0:
|
| 707 |
+
continue
|
| 708 |
+
f_guess = np.array(self._f0, dtype=self._dtype) / n_contact_f
|
| 709 |
+
for c in cforces:
|
| 710 |
+
c.setInitialGuess(f_guess)
|
| 711 |
+
|
| 712 |
+
# print("initial guesses")
|
| 713 |
+
# print(self._nq)
|
| 714 |
+
# print(self._nv)
|
| 715 |
+
# print("q")
|
| 716 |
+
# qig=self._ti.model.q.getInitialGuess()
|
| 717 |
+
# print(qig.shape)
|
| 718 |
+
# print(qig)
|
| 719 |
+
# print("v")
|
| 720 |
+
# print(self._ti.model.v.getInitialGuess())
|
| 721 |
+
# print("a")
|
| 722 |
+
# print(self._ti.model.a.getInitialGuess())
|
| 723 |
+
# for _, cforces in self._ti.model.cmap.items():
|
| 724 |
+
# for c in cforces:
|
| 725 |
+
# print("force")
|
| 726 |
+
# print(c.getInitialGuess())
|
| 727 |
+
|
| 728 |
+
return xig, uig
|
| 729 |
+
|
| 730 |
+
def _set_ig(self):
|
| 731 |
+
|
| 732 |
+
shift_num = -1 # shift data by one node
|
| 733 |
+
|
| 734 |
+
x_opt = self._ti.solution['x_opt']
|
| 735 |
+
u_opt = self._ti.solution['u_opt']
|
| 736 |
+
|
| 737 |
+
# building ig for state
|
| 738 |
+
xig = np.roll(x_opt,
|
| 739 |
+
shift_num, axis=1) # rolling state sol.
|
| 740 |
+
for i in range(abs(shift_num)):
|
| 741 |
+
# state on last node is copied to the elements
|
| 742 |
+
# which are "lost" during the shift operation
|
| 743 |
+
xig[:, -1 - i] = x_opt[:, -1]
|
| 744 |
+
# building ig for inputs
|
| 745 |
+
uig = np.roll(u_opt,
|
| 746 |
+
shift_num, axis=1) # rolling state sol.
|
| 747 |
+
for i in range(abs(shift_num)):
|
| 748 |
+
# state on last node is copied to the elements
|
| 749 |
+
# which are "lost" during the shift operation
|
| 750 |
+
uig[:, -1 - i] = u_opt[:, -1]
|
| 751 |
+
|
| 752 |
+
# assigning ig
|
| 753 |
+
self._prb.getState().setInitialGuess(xig)
|
| 754 |
+
self._prb.getInput().setInitialGuess(uig)
|
| 755 |
+
|
| 756 |
+
return xig, uig
|
| 757 |
+
|
| 758 |
+
def _update_open_loop(self,
|
| 759 |
+
bootstrap: bool = False):
|
| 760 |
+
|
| 761 |
+
q_state, v_state, a_state=self._set_is_open()
|
| 762 |
+
|
| 763 |
+
if not bootstrap:
|
| 764 |
+
self._set_ig()
|
| 765 |
+
else:
|
| 766 |
+
self._set_ig_bootstrap(q_state=q_state, v_state=v_state)
|
| 767 |
+
|
| 768 |
+
# robot_state=xig[:, 0]
|
| 769 |
+
# # open loop update:
|
| 770 |
+
# self._prb.setInitialState(x0=robot_state) # (xig has been shifted, so node 0
|
| 771 |
+
# # is node 1 in the last opt solution)
|
| 772 |
+
|
| 773 |
+
return q_state, v_state, a_state
|
| 774 |
+
|
| 775 |
+
def _update_closed_loop(self,
|
| 776 |
+
bootstrap: bool = False):
|
| 777 |
+
|
| 778 |
+
# set initial state
|
| 779 |
+
q_state=None
|
| 780 |
+
v_state=None
|
| 781 |
+
a_state=None
|
| 782 |
+
if self._custom_opts["adaptive_is"]:
|
| 783 |
+
# adaptive closed loop
|
| 784 |
+
q_state, v_state, a_state=self._set_is_adaptive()
|
| 785 |
+
elif self._custom_opts["fully_closed"]:
|
| 786 |
+
q_state, v_state, a_state=self._set_is_full()
|
| 787 |
+
elif self._custom_opts["closed_partial"]:
|
| 788 |
+
q_state, v_state, a_state=self._set_is_partial()
|
| 789 |
+
else:
|
| 790 |
+
Journal.log(self.__class__.__name__,
|
| 791 |
+
"_update_closed_loop",
|
| 792 |
+
"Neither adaptive_is, fully_closed, or closed_partial.",
|
| 793 |
+
LogType.EXCEP,
|
| 794 |
+
throw_when_excep = False)
|
| 795 |
+
q_state, v_state, a_state=self._set_is()
|
| 796 |
+
|
| 797 |
+
# set initial guess for controller
|
| 798 |
+
if not bootstrap:
|
| 799 |
+
self._set_ig()
|
| 800 |
+
else:
|
| 801 |
+
self._set_ig_bootstrap(q_state=q_state, v_state=v_state)
|
| 802 |
+
|
| 803 |
+
return q_state, v_state, a_state
|
| 804 |
+
|
| 805 |
+
def _set_is_open(self):
|
| 806 |
+
|
| 807 |
+
# overriding states with rhc data
|
| 808 |
+
q_full_root=self._get_root_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 809 |
+
q_jnts=self._get_jnt_q_from_sol(node_idx=1, reduce=False).reshape(-1, 1)
|
| 810 |
+
|
| 811 |
+
twist_root=self._get_root_twist_from_sol(node_idx=1).reshape(-1, 1)
|
| 812 |
+
v_jnts=self._get_jnt_v_from_sol(node_idx=1).reshape(-1, 1)
|
| 813 |
+
|
| 814 |
+
# rhc variables to be set
|
| 815 |
+
q=self._prb.getVariables("q") # .setBounds()
|
| 816 |
+
root_q_full_rhc=q[0:7] # root full q
|
| 817 |
+
jnts_q_rhc=q[7:] # jnts q
|
| 818 |
+
vel=self._prb.getVariables("v")
|
| 819 |
+
root_twist_rhc=vel[0:6] # lin v.
|
| 820 |
+
jnts_v_rhc=vel[6:] # jnts v
|
| 821 |
+
|
| 822 |
+
self.rhc_refs.set_alpha(alpha=1.0) # fully open
|
| 823 |
+
|
| 824 |
+
# close state on known quantities
|
| 825 |
+
root_q_full_rhc.setBounds(lb=q_full_root,
|
| 826 |
+
ub=q_full_root, nodes=0)
|
| 827 |
+
jnts_q_rhc.setBounds(lb=q_jnts,
|
| 828 |
+
ub=q_jnts, nodes=0)
|
| 829 |
+
root_twist_rhc.setBounds(lb=twist_root,
|
| 830 |
+
ub=twist_root, nodes=0)
|
| 831 |
+
jnts_v_rhc.setBounds(lb=v_jnts,
|
| 832 |
+
ub=v_jnts, nodes=0)
|
| 833 |
+
|
| 834 |
+
# return state used for feedback
|
| 835 |
+
q_state=np.concatenate((q_full_root, q_jnts),
|
| 836 |
+
axis=0)
|
| 837 |
+
v_state=np.concatenate((twist_root, v_jnts),
|
| 838 |
+
axis=0)
|
| 839 |
+
|
| 840 |
+
return (q_state, v_state, None)
|
| 841 |
+
|
| 842 |
+
def _set_is_full(self):
|
| 843 |
+
|
| 844 |
+
# measurements
|
| 845 |
+
q_full_root = self.robot_state.root_state.get(data_type="q_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 846 |
+
v_root = self.robot_state.root_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 847 |
+
omega = self.robot_state.root_state.get(data_type="omega", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 848 |
+
a_root = self.robot_state.root_state.get(data_type="a_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 849 |
+
|
| 850 |
+
q_jnts = self.robot_state.jnts_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 851 |
+
v_jnts = self.robot_state.jnts_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 852 |
+
a_jnts = self.robot_state.jnts_state.get(data_type="a", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 853 |
+
|
| 854 |
+
if (not len(self._continuous_joints)==0): # we need do expand some meas. rev jnts to So2
|
| 855 |
+
self._jnts_q_expanded[self._rev_joints_idxs, :]=q_jnts[self._rev_joints_idxs_red ,:]
|
| 856 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_cos, :]=np.cos(q_jnts[self._continuous_joints_idxs_red, :]) # cos
|
| 857 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_sin, :]=np.sin(q_jnts[self._continuous_joints_idxs_red, :]) # sin
|
| 858 |
+
q_jnts=self._jnts_q_expanded.reshape(-1,1)
|
| 859 |
+
|
| 860 |
+
# rhc variables to be set
|
| 861 |
+
q=self._prb.getVariables("q") # .setBounds()
|
| 862 |
+
root_full_q_rhc=q[0:7] # root p
|
| 863 |
+
jnts_q_rhc=q[7:] # jnts q
|
| 864 |
+
vel=self._prb.getVariables("v")
|
| 865 |
+
root_v_rhc=vel[0:3] # lin v.
|
| 866 |
+
root_omega_rhc=vel[3:6] # omega
|
| 867 |
+
jnts_v_rhc=vel[6:] # jnts v
|
| 868 |
+
acc=self._prb.getVariables("a")
|
| 869 |
+
lin_a_prb=acc[0:3] # lin acc
|
| 870 |
+
|
| 871 |
+
self.rhc_refs.set_alpha(alpha=0.0) # non-adaptive
|
| 872 |
+
|
| 873 |
+
root_full_q_rhc.setBounds(lb=q_full_root,
|
| 874 |
+
ub=q_full_root, nodes=0)
|
| 875 |
+
jnts_q_rhc.setBounds(lb=q_jnts,
|
| 876 |
+
ub=q_jnts, nodes=0)
|
| 877 |
+
root_v_rhc.setBounds(lb=v_root,
|
| 878 |
+
ub=v_root, nodes=0) # leaving lin v of the base free (estimated from constraints)
|
| 879 |
+
root_omega_rhc.setBounds(lb=omega,
|
| 880 |
+
ub=omega, nodes=0)
|
| 881 |
+
jnts_v_rhc.setBounds(lb=v_jnts,
|
| 882 |
+
ub=v_jnts, nodes=0)
|
| 883 |
+
if self._custom_opts["lin_a_feedback"]:
|
| 884 |
+
# write base lin 13793197 from meas
|
| 885 |
+
lin_a_prb.setBounds(lb=a_root[0:3, :],
|
| 886 |
+
ub=a_root[0:3, :],
|
| 887 |
+
nodes=0)
|
| 888 |
+
|
| 889 |
+
# return state used for feedback
|
| 890 |
+
q_state=np.concatenate((q_full_root, q_jnts),
|
| 891 |
+
axis=0)
|
| 892 |
+
v_state=np.concatenate((v_root, omega, v_jnts),
|
| 893 |
+
axis=0)
|
| 894 |
+
a_state=np.concatenate((a_root, a_jnts),
|
| 895 |
+
axis=0)
|
| 896 |
+
|
| 897 |
+
return (q_state, v_state, a_state)
|
| 898 |
+
|
| 899 |
+
def _set_is_partial(self):
|
| 900 |
+
|
| 901 |
+
# measurements
|
| 902 |
+
p_root = self.robot_state.root_state.get(data_type="p", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 903 |
+
q_root = self.robot_state.root_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 904 |
+
v_root = self.robot_state.root_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 905 |
+
omega = self.robot_state.root_state.get(data_type="omega", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 906 |
+
a_root = self.robot_state.root_state.get(data_type="a_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 907 |
+
|
| 908 |
+
q_jnts = self.robot_state.jnts_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 909 |
+
v_jnts = self.robot_state.jnts_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 910 |
+
a_jnts = self.robot_state.jnts_state.get(data_type="a", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 911 |
+
|
| 912 |
+
if (not len(self._continuous_joints)==0): # we need do expand some meas. rev jnts to So2
|
| 913 |
+
self._jnts_q_expanded[self._rev_joints_idxs, :]=q_jnts[self._rev_joints_idxs_red ,:]
|
| 914 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_cos, :]=np.cos(q_jnts[self._continuous_joints_idxs_red, :]) # cos
|
| 915 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_sin, :]=np.sin(q_jnts[self._continuous_joints_idxs_red, :]) # sin
|
| 916 |
+
q_jnts=self._jnts_q_expanded.reshape(-1,1)
|
| 917 |
+
|
| 918 |
+
# overriding states with rhc data (-> all overridden state are open looop)
|
| 919 |
+
root_q_full_from_rhc=self._get_root_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 920 |
+
root_p_from_rhc=root_q_full_from_rhc[0:3, :]
|
| 921 |
+
p_root[:, :]=root_p_from_rhc # position is always open loop
|
| 922 |
+
|
| 923 |
+
if not self._custom_opts["estimate_v_root"]:
|
| 924 |
+
v_root[:, :]=self._get_root_twist_from_sol(node_idx=1)[:, 0:3].reshape(-1, 1)
|
| 925 |
+
# override v jnts with the ones from controller
|
| 926 |
+
if not self._custom_opts["use_jnt_v_feedback"]:
|
| 927 |
+
v_jnts[:, :]=self._get_jnt_v_from_sol(node_idx=1).reshape(-1, 1)
|
| 928 |
+
# v_jnts[:, :]=self._get_jnt_v_from_sol(node_idx=1).reshape(-1, 1)
|
| 929 |
+
# root_twist_from_rhc=self._get_root_twist_from_sol(node_idx=1)
|
| 930 |
+
# root_v_from_rhc=root_twist_from_rhc[:, 0:3].reshape(-1, 1)
|
| 931 |
+
# root_omega_from_rhc=root_twist_from_rhc[:, 3:6].reshape(-1, 1)
|
| 932 |
+
# jnt_q_from_rhc=self._get_jnt_q_from_sol(node_idx=1,reduce=False,clamp=False).reshape(-1, 1)
|
| 933 |
+
# jnt_v_from_rhc=self._get_jnt_v_from_sol(node_idx=1).reshape(-1, 1)
|
| 934 |
+
|
| 935 |
+
# rhc variables to be set
|
| 936 |
+
q=self._prb.getVariables("q") # .setBounds()
|
| 937 |
+
root_p_rhc=q[0:3] # root p
|
| 938 |
+
root_q_rhc=q[3:7] # root orientation
|
| 939 |
+
jnts_q_rhc=q[7:] # jnts q
|
| 940 |
+
vel=self._prb.getVariables("v")
|
| 941 |
+
root_v_rhc=vel[0:3] # lin v.
|
| 942 |
+
root_omega_rhc=vel[3:6] # omega
|
| 943 |
+
jnts_v_rhc=vel[6:] # jnts v
|
| 944 |
+
acc=self._prb.getVariables("a")
|
| 945 |
+
lin_a_prb=acc[0:3] # lin acc
|
| 946 |
+
|
| 947 |
+
self.rhc_refs.set_alpha(alpha=0.0) # non-adaptive
|
| 948 |
+
|
| 949 |
+
root_p_rhc.setBounds(lb=p_root,
|
| 950 |
+
ub=p_root, nodes=0)
|
| 951 |
+
root_q_rhc.setBounds(lb=q_root,
|
| 952 |
+
ub=q_root, nodes=0)
|
| 953 |
+
jnts_q_rhc.setBounds(lb=q_jnts,
|
| 954 |
+
ub=q_jnts, nodes=0)
|
| 955 |
+
|
| 956 |
+
if self._custom_opts["estimate_v_root"]:
|
| 957 |
+
root_v_rhc.setBounds(lb=-self._v_inf[0:3],
|
| 958 |
+
ub=self._v_inf[0:3], nodes=0) # leaving lin v of the base free (estimated from constraints)
|
| 959 |
+
else: # get it from controller
|
| 960 |
+
root_v_rhc.setBounds(lb=v_root,
|
| 961 |
+
ub=v_root, nodes=0)
|
| 962 |
+
root_omega_rhc.setBounds(lb=omega,
|
| 963 |
+
ub=omega, nodes=0)
|
| 964 |
+
jnts_v_rhc.setBounds(lb=v_jnts,
|
| 965 |
+
ub=v_jnts, nodes=0)
|
| 966 |
+
if self._custom_opts["lin_a_feedback"]:
|
| 967 |
+
# write base lin 13793197 from meas
|
| 968 |
+
lin_a_prb.setBounds(lb=a_root[0:3, :],
|
| 969 |
+
ub=a_root[0:3, :],
|
| 970 |
+
nodes=0)
|
| 971 |
+
|
| 972 |
+
# return state used for feedback
|
| 973 |
+
q_state=np.concatenate((p_root, q_root, q_jnts),
|
| 974 |
+
axis=0)
|
| 975 |
+
v_state=np.concatenate((v_root, omega, v_jnts),
|
| 976 |
+
axis=0)
|
| 977 |
+
a_state=np.concatenate((a_root, a_jnts),
|
| 978 |
+
axis=0)
|
| 979 |
+
|
| 980 |
+
return (q_state, v_state, a_state)
|
| 981 |
+
|
| 982 |
+
def _set_is_adaptive(self):
|
| 983 |
+
|
| 984 |
+
# measurements
|
| 985 |
+
p_root = self.robot_state.root_state.get(data_type="p", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 986 |
+
q_root = self.robot_state.root_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 987 |
+
v_root = self.robot_state.root_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 988 |
+
omega = self.robot_state.root_state.get(data_type="omega", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 989 |
+
a_root = self.robot_state.root_state.get(data_type="a_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 990 |
+
|
| 991 |
+
q_jnts = self.robot_state.jnts_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 992 |
+
v_jnts = self.robot_state.jnts_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 993 |
+
a_jnts = self.robot_state.jnts_state.get(data_type="a", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 994 |
+
|
| 995 |
+
# rhc variables to be set
|
| 996 |
+
q=self._prb.getVariables("q") # .setBounds()
|
| 997 |
+
root_p_rhc=q[0:3] # root p
|
| 998 |
+
root_q_rhc=q[3:7] # root orientation
|
| 999 |
+
jnts_q_rhc=q[7:] # jnts q
|
| 1000 |
+
vel=self._prb.getVariables("v")
|
| 1001 |
+
root_v_rhc=vel[0:3] # lin v.
|
| 1002 |
+
root_omega_rhc=vel[3:6] # omega
|
| 1003 |
+
jnts_v_rhc=vel[6:] # jnts v
|
| 1004 |
+
acc=self._prb.getVariables("a")
|
| 1005 |
+
lin_a_prb=acc[0:3] # lin acc
|
| 1006 |
+
|
| 1007 |
+
# getting prediction defects
|
| 1008 |
+
root_q_delta=self.rhc_pred_delta.root_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 1009 |
+
jnt_q_delta=self.rhc_pred_delta.jnts_state.get(data_type="q", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 1010 |
+
jnt_v_delta=self.rhc_pred_delta.jnts_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 1011 |
+
v_root_delta = self.rhc_pred_delta.root_state.get(data_type="v", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 1012 |
+
omega_root_delta = self.rhc_pred_delta.root_state.get(data_type="omega", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 1013 |
+
a_root_delta = self.rhc_pred_delta.root_state.get(data_type="a_full", robot_idxs=self.controller_index_np).reshape(-1, 1)
|
| 1014 |
+
|
| 1015 |
+
# close state on known quantities, estimate some (e.g. lin vel) and
|
| 1016 |
+
# open loop if thing start to explode
|
| 1017 |
+
alpha_now=1.0
|
| 1018 |
+
delta=0.0
|
| 1019 |
+
if self._custom_opts["alpha_from_outside"]:
|
| 1020 |
+
alpha_now=self.rhc_refs.get_alpha()
|
| 1021 |
+
else: # "autotuned" alpha
|
| 1022 |
+
if self._custom_opts["estimate_v_root"]: # we copmute delta based on jnt v (since we use meas.)
|
| 1023 |
+
delta=np.max(np.abs(jnt_v_delta))
|
| 1024 |
+
else:
|
| 1025 |
+
delta=np.max(np.abs(omega_root_delta))
|
| 1026 |
+
# fail_idx=self._get_failure_index()
|
| 1027 |
+
# fail_idx=self._get_explosion_idx()/self._fail_idx_thresh
|
| 1028 |
+
alpha_now=(np.tanh(2*self._alpha_half*(delta-self._alpha_half))+1)/2.0
|
| 1029 |
+
|
| 1030 |
+
bound_relaxation=-np.log(1-alpha_now+1e-16) # [~0, ~inf] if alpha_now [0, 1]
|
| 1031 |
+
self.rhc_refs.set_alpha(alpha=alpha_now) # also writes on shared mem for db
|
| 1032 |
+
self.rhc_refs.set_bound_relax(bound_relax=bound_relaxation) # also writes on shared mem for db
|
| 1033 |
+
|
| 1034 |
+
self._alphas_q_root[:]=alpha_now # for now single alpha for everything
|
| 1035 |
+
self._alphas_q_jnts[:]=alpha_now
|
| 1036 |
+
self._alphas_twist_root[:]=alpha_now
|
| 1037 |
+
self._alphas_v_jnts[:]=alpha_now
|
| 1038 |
+
self._alphas_a[:]=alpha_now
|
| 1039 |
+
if not self._custom_opts["estimate_v_root"]:
|
| 1040 |
+
self._alphas_twist_root[0:3]=1.0 # open
|
| 1041 |
+
self._alphas_v_jnts[:]=1.0 # open
|
| 1042 |
+
|
| 1043 |
+
# position is always open loop
|
| 1044 |
+
root_q_full_from_rhc=self._get_root_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 1045 |
+
root_p_from_rhc=root_q_full_from_rhc[0:3, :]
|
| 1046 |
+
p_root[:, :]=root_p_from_rhc
|
| 1047 |
+
|
| 1048 |
+
# expaning meas q if continuous joints
|
| 1049 |
+
if (not len(self._continuous_joints)==0): # we need do expand some meas. rev jnts to So2
|
| 1050 |
+
self._jnts_q_expanded[self._rev_joints_idxs, :]=q_jnts[self._rev_joints_idxs_red ,:]
|
| 1051 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_cos, :]=np.cos(q_jnts[self._continuous_joints_idxs_red, :]) # cos
|
| 1052 |
+
self._jnts_q_expanded[self._continuous_joints_idxs_sin, :]=np.sin(q_jnts[self._continuous_joints_idxs_red, :]) # sin
|
| 1053 |
+
|
| 1054 |
+
# continous joints position is always open loop, but we need a delta vector of matching dimension
|
| 1055 |
+
q_jnts_from_rhc=self._get_jnt_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 1056 |
+
|
| 1057 |
+
self._jnts_q_delta_expanded[self._rev_joints_idxs, :]=jnt_q_delta[self._rev_joints_idxs_red ,:]
|
| 1058 |
+
|
| 1059 |
+
self._jnts_q_delta_expanded[self._continuous_joints_idxs_cos, :]=\
|
| 1060 |
+
np.cos(q_jnts_from_rhc[self._continuous_joints_idxs_red, :]) - \
|
| 1061 |
+
np.cos(q_jnts[self._continuous_joints_idxs_red, :])
|
| 1062 |
+
self._jnts_q_delta_expanded[self._continuous_joints_idxs_sin, :]=\
|
| 1063 |
+
np.sin(q_jnts_from_rhc[self._continuous_joints_idxs_red, :]) - \
|
| 1064 |
+
np.sin(q_jnts[self._continuous_joints_idxs_red, :])
|
| 1065 |
+
|
| 1066 |
+
q_jnts=self._jnts_q_expanded.reshape(-1,1) # overriting with expanded jnts
|
| 1067 |
+
jnt_q_delta=self._jnts_q_delta_expanded.reshape(-1, 1) # overriting with expanded jnts
|
| 1068 |
+
|
| 1069 |
+
self._alphas_q_jnts[self._continuous_joints_idxs_cos, :]=1.0 # open loop
|
| 1070 |
+
self._alphas_q_jnts[self._continuous_joints_idxs_sin, :]=1.0 # open loop
|
| 1071 |
+
|
| 1072 |
+
# self._alphas_v_jnts[self._continuous_joints_idxs_red, :]=0.0 # open loop
|
| 1073 |
+
|
| 1074 |
+
root_p_rhc.setBounds(lb=p_root,
|
| 1075 |
+
ub=p_root, nodes=0)
|
| 1076 |
+
root_q_rhc.setBounds(lb=q_root+self._alphas_q_root[3:7]*root_q_delta,
|
| 1077 |
+
ub=q_root+self._alphas_q_root[3:7]*root_q_delta, nodes=0)
|
| 1078 |
+
jnts_q_rhc.setBounds(lb=q_jnts+self._alphas_q_jnts*jnt_q_delta,
|
| 1079 |
+
ub=q_jnts+self._alphas_q_jnts*jnt_q_delta, nodes=0)
|
| 1080 |
+
if self._custom_opts["estimate_v_root"]:
|
| 1081 |
+
root_v_rhc.setBounds(lb=-self._v_inf[0:3],
|
| 1082 |
+
ub=self._v_inf[0:3], nodes=0)
|
| 1083 |
+
else:
|
| 1084 |
+
root_v_rhc.setBounds(lb=v_root+self._alphas_twist_root[0:3, :]*v_root_delta,
|
| 1085 |
+
ub=v_root+self._alphas_twist_root[0:3, :]*v_root_delta, nodes=0)
|
| 1086 |
+
root_omega_rhc.setBounds(lb=omega+self._alphas_twist_root[3:6, :]*omega_root_delta,
|
| 1087 |
+
ub=omega+self._alphas_twist_root[3:6, :]*omega_root_delta, nodes=0)
|
| 1088 |
+
jnts_v_rhc.setBounds(lb=v_jnts+self._alphas_v_jnts*jnt_v_delta,
|
| 1089 |
+
ub=v_jnts+self._alphas_v_jnts*jnt_v_delta, nodes=0)
|
| 1090 |
+
if self._custom_opts["lin_a_feedback"]:
|
| 1091 |
+
lin_a_prb.setBounds(lb=a_root[0:3, :]+self._alphas_a[0:3]*a_root_delta[0:3, :],
|
| 1092 |
+
ub=a_root[0:3, :]+self._alphas_a[0:3]*a_root_delta[0:3, :],
|
| 1093 |
+
nodes=0)
|
| 1094 |
+
|
| 1095 |
+
# return state used for feedback
|
| 1096 |
+
q_state=np.concatenate((p_root, q_root, q_jnts),
|
| 1097 |
+
axis=0)
|
| 1098 |
+
v_state=np.concatenate((v_root, omega, v_jnts),
|
| 1099 |
+
axis=0)
|
| 1100 |
+
a_state=np.concatenate((a_root, a_jnts),
|
| 1101 |
+
axis=0)
|
| 1102 |
+
|
| 1103 |
+
return (q_state, v_state, a_state)
|
| 1104 |
+
|
| 1105 |
+
def _solve(self):
|
| 1106 |
+
|
| 1107 |
+
if self._debug:
|
| 1108 |
+
return self._db_solve(bootstrap=False)
|
| 1109 |
+
else:
|
| 1110 |
+
return self._min_solve(bootstrap=False)
|
| 1111 |
+
|
| 1112 |
+
def _bootstrap(self):
|
| 1113 |
+
|
| 1114 |
+
if self._debug:
|
| 1115 |
+
return self._db_solve(bootstrap=True)
|
| 1116 |
+
else:
|
| 1117 |
+
return self._min_solve(bootstrap=True)
|
| 1118 |
+
|
| 1119 |
+
def _min_solve(self, bootstrap: bool = False):
|
| 1120 |
+
# minimal solve version -> no debug
|
| 1121 |
+
robot_qstate=None
|
| 1122 |
+
robot_vstate=None
|
| 1123 |
+
robot_astate=None
|
| 1124 |
+
if self._open_loop:
|
| 1125 |
+
robot_qstate, robot_vstate, robot_astate = self._update_open_loop(bootstrap=bootstrap) # updates the TO ig and
|
| 1126 |
+
# initial conditions using data from the solution itself
|
| 1127 |
+
else:
|
| 1128 |
+
robot_qstate, robot_vstate, robot_astate = self._update_closed_loop(bootstrap=bootstrap) # updates the TO ig and
|
| 1129 |
+
# initial conditions using robot measurements
|
| 1130 |
+
|
| 1131 |
+
self._pm.shift() # shifts phases of one dt
|
| 1132 |
+
if self._refs_in_hor_frame:
|
| 1133 |
+
# q_base=self.robot_state.root_state.get(data_type="q",
|
| 1134 |
+
# robot_idxs=self.controller_index).reshape(-1, 1)
|
| 1135 |
+
# q_full=self._get_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 1136 |
+
# using internal base pose from rhc. in case of closed loop, it will be the meas state
|
| 1137 |
+
force_norm=None
|
| 1138 |
+
if self._custom_opts["use_force_feedback"]:
|
| 1139 |
+
contact_forces=self.robot_state.contact_wrenches.get(data_type="f",
|
| 1140 |
+
robot_idxs=self.controller_index_np,
|
| 1141 |
+
contact_name=None).reshape(self.n_contacts,3)
|
| 1142 |
+
force_norm=np.linalg.norm(contact_forces, axis=1)
|
| 1143 |
+
self.rhc_refs.step(qstate=robot_qstate, vstate=robot_vstate,
|
| 1144 |
+
force_norm=force_norm)
|
| 1145 |
+
else:
|
| 1146 |
+
self.rhc_refs.step()
|
| 1147 |
+
|
| 1148 |
+
try:
|
| 1149 |
+
if not bootstrap:
|
| 1150 |
+
converged = self._ti.rti() # RTI step
|
| 1151 |
+
else:
|
| 1152 |
+
converged = self._ti.bootstrap() # full solve (to convergence)
|
| 1153 |
+
self.sol_counter = self.sol_counter + 1
|
| 1154 |
+
return not self._check_rhc_failure()
|
| 1155 |
+
except Exception as e: # fail in case of exceptions
|
| 1156 |
+
return False
|
| 1157 |
+
|
| 1158 |
+
def _db_solve(self, bootstrap: bool = False):
|
| 1159 |
+
|
| 1160 |
+
self._timer_start = time.perf_counter()
|
| 1161 |
+
|
| 1162 |
+
robot_qstate=None
|
| 1163 |
+
robot_vstate=None
|
| 1164 |
+
robot_astate=None
|
| 1165 |
+
if self._open_loop:
|
| 1166 |
+
robot_qstate, robot_vstate, robot_astate = self._update_open_loop(bootstrap=bootstrap) # updates the TO ig and
|
| 1167 |
+
# initial conditions using data from the solution itself
|
| 1168 |
+
else:
|
| 1169 |
+
robot_qstate, robot_vstate, robot_astate = self._update_closed_loop(bootstrap=bootstrap) # updates the TO ig and
|
| 1170 |
+
# initial conditions using robot measurements
|
| 1171 |
+
|
| 1172 |
+
self._prb_update_time = time.perf_counter()
|
| 1173 |
+
self._pm.shift() # shifts phases of one dt
|
| 1174 |
+
self._phase_shift_time = time.perf_counter()
|
| 1175 |
+
|
| 1176 |
+
if self._refs_in_hor_frame:
|
| 1177 |
+
# q_base=self.robot_state.root_state.get(data_type="q",
|
| 1178 |
+
# robot_idxs=self.controller_index).reshape(-1, 1)
|
| 1179 |
+
# q_full=self._get_full_q_from_sol(node_idx=1).reshape(-1, 1)
|
| 1180 |
+
# using internal base pose from rhc. in case of closed loop, it will be the meas state
|
| 1181 |
+
force_norm=None
|
| 1182 |
+
if self._custom_opts["use_force_feedback"]:
|
| 1183 |
+
contact_forces=self.robot_state.contact_wrenches.get(data_type="f",
|
| 1184 |
+
robot_idxs=self.controller_index_np,
|
| 1185 |
+
contact_name=None).reshape(self.n_contacts,3)
|
| 1186 |
+
force_norm=np.linalg.norm(contact_forces, axis=1)
|
| 1187 |
+
self.rhc_refs.step(qstate=robot_qstate, vstate=robot_vstate,
|
| 1188 |
+
force_norm=force_norm)
|
| 1189 |
+
else:
|
| 1190 |
+
self.rhc_refs.step()
|
| 1191 |
+
|
| 1192 |
+
self._task_ref_update_time = time.perf_counter()
|
| 1193 |
+
|
| 1194 |
+
try:
|
| 1195 |
+
if not bootstrap:
|
| 1196 |
+
converged = self._ti.rti() # RTI step
|
| 1197 |
+
else:
|
| 1198 |
+
converged = self._ti.bootstrap() # full solve bootstrap
|
| 1199 |
+
self._rti_time = time.perf_counter()
|
| 1200 |
+
self.sol_counter = self.sol_counter + 1
|
| 1201 |
+
self._update_db_data()
|
| 1202 |
+
return not self._check_rhc_failure()
|
| 1203 |
+
except Exception as e: # fail in case of exceptions
|
| 1204 |
+
if self._verbose:
|
| 1205 |
+
solve_mode = "RTI" if not bootstrap else "Bootstrap"
|
| 1206 |
+
exception = f"{solve_mode}() for controller {self.controller_index} failed" + \
|
| 1207 |
+
f" with exception {type(e).__name__}"
|
| 1208 |
+
Journal.log(self.__class__.__name__,
|
| 1209 |
+
"solve",
|
| 1210 |
+
exception,
|
| 1211 |
+
LogType.EXCEP,
|
| 1212 |
+
throw_when_excep = False)
|
| 1213 |
+
self._update_db_data()
|
| 1214 |
+
return False
|
| 1215 |
+
|
| 1216 |
+
def _get_fail_idx(self):
|
| 1217 |
+
|
| 1218 |
+
self._explosion_idx_buffer[:, self._expl_idx_buffer_counter]=self._get_explosion_idx()
|
| 1219 |
+
self._expl_idx_buffer_counter+=1
|
| 1220 |
+
self._expl_idx_counter+=1
|
| 1221 |
+
if self._expl_idx_counter%self._expl_idx_window_size==0:
|
| 1222 |
+
self._expl_idx_buffer_counter=0 # restart from 0
|
| 1223 |
+
|
| 1224 |
+
running_avrg=np.mean(self._explosion_idx_buffer).item()
|
| 1225 |
+
|
| 1226 |
+
return running_avrg
|
| 1227 |
+
|
| 1228 |
+
def _get_explosion_idx(self):
|
| 1229 |
+
explosion_index = self._get_rhc_constr_viol() + self._get_rhc_cost()*self._fail_idx_scale
|
| 1230 |
+
return explosion_index
|
| 1231 |
+
|
| 1232 |
+
def _update_db_data(self):
|
| 1233 |
+
|
| 1234 |
+
self._profiling_data_dict["problem_update_dt"] = self._prb_update_time - self._timer_start
|
| 1235 |
+
self._profiling_data_dict["phases_shift_dt"] = self._phase_shift_time - self._prb_update_time
|
| 1236 |
+
self._profiling_data_dict["task_ref_update"] = self._task_ref_update_time - self._phase_shift_time
|
| 1237 |
+
self._profiling_data_dict["rti_solve_dt"] = self._rti_time - self._task_ref_update_time
|
| 1238 |
+
self.rhc_costs.update(self._ti.solver_rti.getCostsValues())
|
| 1239 |
+
self.rhc_constr.update(self._ti.solver_rti.getConstraintsValues())
|
| 1240 |
+
|
| 1241 |
+
def _reset(self):
|
| 1242 |
+
|
| 1243 |
+
# reset task interface (ig, solvers, etc..) +
|
| 1244 |
+
# phase manager and sets bootstap as solution
|
| 1245 |
+
self._gm.reset()
|
| 1246 |
+
self._explosion_idx_buffer[:, :]=self._get_explosion_idx() # reset with data from reset solution
|
| 1247 |
+
self._expl_idx_counter=0.0
|
| 1248 |
+
self._expl_idx_buffer_counter=0
|
| 1249 |
+
|
| 1250 |
+
def _get_cost_info(self):
|
| 1251 |
+
|
| 1252 |
+
cost_dict = self._ti.solver_rti.getCostsValues()
|
| 1253 |
+
cost_names = list(cost_dict.keys())
|
| 1254 |
+
cost_dims = [1] * len(cost_names) # costs are always scalar
|
| 1255 |
+
return cost_names, cost_dims
|
| 1256 |
+
|
| 1257 |
+
def _get_constr_info(self):
|
| 1258 |
+
|
| 1259 |
+
constr_dict = self._ti.solver_rti.getConstraintsValues()
|
| 1260 |
+
constr_names = list(constr_dict.keys())
|
| 1261 |
+
constr_dims = [-1] * len(constr_names)
|
| 1262 |
+
i = 0
|
| 1263 |
+
for constr in constr_dict:
|
| 1264 |
+
constr_val = constr_dict[constr]
|
| 1265 |
+
constr_shape = constr_val.shape
|
| 1266 |
+
constr_dims[i] = constr_shape[0]
|
| 1267 |
+
i+=1
|
| 1268 |
+
return constr_names, constr_dims
|
| 1269 |
+
|
| 1270 |
+
def _get_q_from_sol(self):
|
| 1271 |
+
full_q=self._ti.solution['q'].astype(self._dtype)
|
| 1272 |
+
if self._custom_opts["replace_continuous_joints"]:
|
| 1273 |
+
return full_q
|
| 1274 |
+
else:
|
| 1275 |
+
cont_jnts=full_q[self._continuous_joints_idxs_qfull, :]
|
| 1276 |
+
cos=cont_jnts[::2, :]
|
| 1277 |
+
sin=cont_jnts[1::2, :]
|
| 1278 |
+
# copy root
|
| 1279 |
+
self._full_q_reduced[0:7, :]=full_q[0:7, :]
|
| 1280 |
+
# copy rev joint vals
|
| 1281 |
+
self._full_q_reduced[self._rev_joints_idxs_red_qfull, :]=full_q[self._rev_joints_idxs_qfull, :]
|
| 1282 |
+
# and continuous
|
| 1283 |
+
angle=np.arctan2(sin, cos)
|
| 1284 |
+
self._full_q_reduced[self._continuous_joints_idxs_red_qfull, :]=angle
|
| 1285 |
+
return self._full_q_reduced
|
| 1286 |
+
|
| 1287 |
+
def _get_v_from_sol(self):
|
| 1288 |
+
return self._ti.solution['v'].astype(self._dtype)
|
| 1289 |
+
|
| 1290 |
+
def _get_a_from_sol(self):
|
| 1291 |
+
return self._ti.solution['a'].astype(self._dtype)
|
| 1292 |
+
|
| 1293 |
+
def _get_a_dot_from_sol(self):
|
| 1294 |
+
return None
|
| 1295 |
+
|
| 1296 |
+
def _get_f_from_sol(self):
|
| 1297 |
+
# to be overridden by child class
|
| 1298 |
+
contact_names =self._get_contacts() # we use controller-side names
|
| 1299 |
+
try:
|
| 1300 |
+
data=[]
|
| 1301 |
+
for key in contact_names:
|
| 1302 |
+
contact_f=self._ti.solution["f_" + key].astype(self._dtype)
|
| 1303 |
+
np.nan_to_num(contact_f, nan=1e6, posinf=1e6, neginf=-1e6, copy=False)
|
| 1304 |
+
np.clip(a=contact_f, a_max=1e6, a_min=-1e6, out=contact_f)
|
| 1305 |
+
data.append(contact_f)
|
| 1306 |
+
return np.concatenate(data, axis=0)
|
| 1307 |
+
except:
|
| 1308 |
+
return None
|
| 1309 |
+
|
| 1310 |
+
def _get_f_dot_from_sol(self):
|
| 1311 |
+
# to be overridden by child class
|
| 1312 |
+
return None
|
| 1313 |
+
|
| 1314 |
+
def _get_eff_from_sol(self):
|
| 1315 |
+
# to be overridden by child class
|
| 1316 |
+
return None
|
| 1317 |
+
|
| 1318 |
+
def _get_cost_from_sol(self,
|
| 1319 |
+
cost_name: str):
|
| 1320 |
+
return self.rhc_costs[cost_name]
|
| 1321 |
+
|
| 1322 |
+
def _get_constr_from_sol(self,
|
| 1323 |
+
constr_name: str):
|
| 1324 |
+
return self.rhc_constr[constr_name]
|
bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/isaac_world_interface.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/jnt_imp_config.yaml
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
XBotInterface: # just used for retrieving homing in sim with xbot_mujoco
|
| 2 |
+
urdf_path: $PWD/xmj_env_files/centauro.urdf
|
| 3 |
+
srdf_path: $PWD/xmj_env_files/centauro.srdf
|
| 4 |
+
|
| 5 |
+
# defaults
|
| 6 |
+
motor_pd:
|
| 7 |
+
"j_arm*_1": [500, 10]
|
| 8 |
+
"j_arm*_2": [500, 10]
|
| 9 |
+
"j_arm*_3": [500, 10]
|
| 10 |
+
"j_arm*_4": [500, 10]
|
| 11 |
+
"j_arm*_5": [100, 5]
|
| 12 |
+
"j_arm*_6": [100, 5]
|
| 13 |
+
"j_arm*_7": [100, 5]
|
| 14 |
+
"hip_yaw_*": [3000, 30]
|
| 15 |
+
"hip_pitch_*": [3000, 30]
|
| 16 |
+
"knee_pitch_*": [3000, 30]
|
| 17 |
+
"ankle_pitch_*": [1000, 10]
|
| 18 |
+
"ankle_yaw_*": [300, 10]
|
| 19 |
+
"neck_pitch": [10, 1]
|
| 20 |
+
"neck_yaw": [10, 1]
|
| 21 |
+
"torso_yaw": [1000, 30]
|
| 22 |
+
"j_wheel_*": [0, 30]
|
| 23 |
+
"velodyne_*": [10, 1]
|
| 24 |
+
"d435_*": [10, 1]
|
| 25 |
+
"dagana_*": [50, 1]
|
| 26 |
+
|
| 27 |
+
startup_motor_pd: # iannis combo
|
| 28 |
+
"j_arm*_1": [500, 30]
|
| 29 |
+
"j_arm*_2": [500, 30]
|
| 30 |
+
"j_arm*_3": [500, 30]
|
| 31 |
+
"j_arm*_4": [500, 30]
|
| 32 |
+
"j_arm*_5": [100, 5]
|
| 33 |
+
"j_arm*_6": [100, 5]
|
| 34 |
+
"j_arm*_7": [100, 5]
|
| 35 |
+
"hip_yaw_*": [200, 60]
|
| 36 |
+
"hip_pitch_*": [200, 60]
|
| 37 |
+
"knee_pitch_*": [200, 60]
|
| 38 |
+
"ankle_pitch_*": [200, 60]
|
| 39 |
+
"ankle_yaw_*": [120, 30]
|
| 40 |
+
"neck_pitch": [10, 1]
|
| 41 |
+
"neck_yaw": [10, 1]
|
| 42 |
+
"torso_yaw": [1000, 30]
|
| 43 |
+
"j_wheel_*": [0, 30]
|
| 44 |
+
"velodyne_*": [10, 1]
|
| 45 |
+
"d435_*": [10, 1]
|
| 46 |
+
"dagana_*": [50, 1]
|
bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/jnt_imp_config_with_ub.yaml
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
XBotInterface: # just used for retrieving homing in sim with xbot_mujoco
|
| 2 |
+
urdf_path: $PWD/xmj_env_files/centauro.urdf
|
| 3 |
+
srdf_path: $PWD/xmj_env_files/centauro.srdf
|
| 4 |
+
|
| 5 |
+
# defaults
|
| 6 |
+
motor_pd:
|
| 7 |
+
"j_arm*_1": [500, 10]
|
| 8 |
+
"j_arm*_2": [500, 10]
|
| 9 |
+
"j_arm*_3": [500, 10]
|
| 10 |
+
"j_arm*_4": [500, 10]
|
| 11 |
+
"j_arm*_5": [100, 5]
|
| 12 |
+
"j_arm*_6": [100, 5]
|
| 13 |
+
"j_arm*_7": [100, 5]
|
| 14 |
+
"hip_yaw_*": [3000, 30]
|
| 15 |
+
"hip_pitch_*": [3000, 30]
|
| 16 |
+
"knee_pitch_*": [3000, 30]
|
| 17 |
+
"ankle_pitch_*": [1000, 10]
|
| 18 |
+
"ankle_yaw_*": [300, 10]
|
| 19 |
+
"neck_pitch": [10, 1]
|
| 20 |
+
"neck_yaw": [10, 1]
|
| 21 |
+
"torso_yaw": [1000, 30]
|
| 22 |
+
"j_wheel_*": [0, 30]
|
| 23 |
+
"velodyne_*": [10, 1]
|
| 24 |
+
"d435_*": [10, 1]
|
| 25 |
+
"dagana_*": [50, 1]
|
| 26 |
+
|
| 27 |
+
startup_motor_pd: # iannis combo
|
| 28 |
+
"j_arm*_1": [100, 25]
|
| 29 |
+
"j_arm*_2": [100, 25]
|
| 30 |
+
"j_arm*_3": [100, 25]
|
| 31 |
+
"j_arm*_4": [100, 25]
|
| 32 |
+
"j_arm*_5": [20, 8]
|
| 33 |
+
"j_arm*_6": [20, 8]
|
| 34 |
+
"j_arm*_7": [20, 8]
|
| 35 |
+
"hip_yaw_*": [200, 60]
|
| 36 |
+
"hip_pitch_*": [200, 60]
|
| 37 |
+
"knee_pitch_*": [200, 60]
|
| 38 |
+
"ankle_pitch_*": [200, 60]
|
| 39 |
+
"ankle_yaw_*": [120, 30]
|
| 40 |
+
"neck_pitch": [10, 1]
|
| 41 |
+
"neck_yaw": [10, 1]
|
| 42 |
+
"torso_yaw": [400, 60]
|
| 43 |
+
"j_wheel_*": [0, 30]
|
| 44 |
+
"velodyne_*": [10, 1]
|
| 45 |
+
"d435_*": [10, 1]
|
| 46 |
+
"dagana_*": [50, 1]
|
bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/launch_control_cluster.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import argparse
|
| 3 |
+
import multiprocessing as mp
|
| 4 |
+
import importlib.util
|
| 5 |
+
import inspect
|
| 6 |
+
|
| 7 |
+
from aug_mpc.utils.custom_arg_parsing import generate_custom_arg_dict
|
| 8 |
+
|
| 9 |
+
from EigenIPC.PyEigenIPC import Journal, LogType
|
| 10 |
+
|
| 11 |
+
this_script_name = os.path.splitext(os.path.basename(os.path.abspath(__file__)))[0]
|
| 12 |
+
|
| 13 |
+
# Function to dynamically import a module from a specific file path
|
| 14 |
+
def import_env_module(env_path):
|
| 15 |
+
spec = importlib.util.spec_from_file_location("env_module", env_path)
|
| 16 |
+
env_module = importlib.util.module_from_spec(spec)
|
| 17 |
+
spec.loader.exec_module(env_module)
|
| 18 |
+
return env_module
|
| 19 |
+
|
| 20 |
+
if __name__ == "__main__":
|
| 21 |
+
|
| 22 |
+
# Parse command line arguments for CPU affinity
|
| 23 |
+
parser = argparse.ArgumentParser(description="Set CPU affinity for the script.")
|
| 24 |
+
parser.add_argument('--ns', type=str, help='Namespace to be used for cluster shared memory')
|
| 25 |
+
parser.add_argument('--urdf_path', type=str, help='Robot description package path for URDF ')
|
| 26 |
+
parser.add_argument('--srdf_path', type=str, help='Robot description package path for SRDF ')
|
| 27 |
+
parser.add_argument('--size', type=int, help='cluster size', default=1)
|
| 28 |
+
|
| 29 |
+
# Replacing argparse.BooleanOptionalAction with 'store_true' and 'store_false' for compatibility with Python 3.8
|
| 30 |
+
parser.add_argument('--cloop',action='store_true', help='whether to use RHC controllers in closed loop mode')
|
| 31 |
+
parser.add_argument('--cluster_dt', type=float, default=0.05, help='dt used by MPC controllers for discretization')
|
| 32 |
+
parser.add_argument('--n_nodes', type=int, default=31, help='n nodes used by MPC controllers')
|
| 33 |
+
|
| 34 |
+
parser.add_argument('--verbose',action='store_true', help='run in verbose mode')
|
| 35 |
+
|
| 36 |
+
parser.add_argument('--enable_debug',action='store_true', help='enable debug mode for cluster client and all controllers')
|
| 37 |
+
|
| 38 |
+
parser.add_argument('--dmpdir', type=str, help='directory where data is dumped', default="/root/aux_data")
|
| 39 |
+
|
| 40 |
+
parser.add_argument('--no_mp_fork',action='store_true', help='whether to multiprocess with forkserver context')
|
| 41 |
+
|
| 42 |
+
parser.add_argument('--set_affinity',action='store_true', help='set affinity to a core for each controller')
|
| 43 |
+
|
| 44 |
+
parser.add_argument('--comment', type=str, help='Any useful comment associated with this run', default="")
|
| 45 |
+
parser.add_argument('--timeout_ms', type=int, help='connection timeout after which the script self-terminates', default=60000)
|
| 46 |
+
parser.add_argument('--codegen_override_dir', type=str, help='Path to base dir where codegen is to be loaded', default="")
|
| 47 |
+
|
| 48 |
+
parser.add_argument('--custom_args_names', nargs='+', default=None,
|
| 49 |
+
help='list of custom arguments names')
|
| 50 |
+
parser.add_argument('--custom_args_vals', nargs='+', default=None,
|
| 51 |
+
help='list of custom arguments values')
|
| 52 |
+
parser.add_argument('--custom_args_dtype', nargs='+', default=None,
|
| 53 |
+
help='list of custom arguments data types')
|
| 54 |
+
|
| 55 |
+
parser.add_argument('--cluster_client_fname', type=str,
|
| 56 |
+
default="aug_mpc.controllers.rhc.hybrid_quad_client",
|
| 57 |
+
help="cluster client file import pattern (without extension)")
|
| 58 |
+
|
| 59 |
+
args = parser.parse_args()
|
| 60 |
+
|
| 61 |
+
# Ensure custom_args_names and custom_args_vals have the same length
|
| 62 |
+
custom_opts = generate_custom_arg_dict(args=args)
|
| 63 |
+
custom_opts.update({"cloop": args.cloop,
|
| 64 |
+
"cluster_dt": args.cluster_dt,
|
| 65 |
+
"n_nodes": args.n_nodes,
|
| 66 |
+
"codegen_override_dir": args.codegen_override_dir})
|
| 67 |
+
if args.no_mp_fork: # this needs to be in the main
|
| 68 |
+
mp.set_start_method('spawn')
|
| 69 |
+
else:
|
| 70 |
+
# mp.set_start_method('forkserver')
|
| 71 |
+
mp.set_start_method('fork')
|
| 72 |
+
|
| 73 |
+
cluster_module=importlib.import_module(args.cluster_client_fname)
|
| 74 |
+
# Get all classes defined in the module
|
| 75 |
+
classes_in_module = [name for name, obj in inspect.getmembers(cluster_module, inspect.isclass)
|
| 76 |
+
if obj.__module__ == cluster_module.__name__]
|
| 77 |
+
if len(classes_in_module) == 1:
|
| 78 |
+
cluster_classname=classes_in_module[0]
|
| 79 |
+
ClusterClient = getattr(cluster_module, cluster_classname)
|
| 80 |
+
cluster_client = ClusterClient(namespace=args.ns,
|
| 81 |
+
cluster_size=args.size,
|
| 82 |
+
urdf_xacro_path=args.urdf_path,
|
| 83 |
+
srdf_xacro_path=args.srdf_path,
|
| 84 |
+
open_loop=not args.cloop,
|
| 85 |
+
use_mp_fork = not args.no_mp_fork,
|
| 86 |
+
verbose=args.verbose,
|
| 87 |
+
debug=args.enable_debug,
|
| 88 |
+
base_dump_dir=args.dmpdir,
|
| 89 |
+
timeout_ms=args.timeout_ms,
|
| 90 |
+
custom_opts=custom_opts,
|
| 91 |
+
codegen_override=args.codegen_override_dir,
|
| 92 |
+
set_affinity=args.set_affinity)
|
| 93 |
+
cluster_client.run()
|
| 94 |
+
|
| 95 |
+
else:
|
| 96 |
+
class_list_str = ", ".join(classes_in_module)
|
| 97 |
+
Journal.log("launch_control_cluster.py",
|
| 98 |
+
"",
|
| 99 |
+
f"Found more than one class in cluster client file {args.cluster_client_fname}. Found: {class_list_str}",
|
| 100 |
+
LogType.EXCEP,
|
| 101 |
+
throw_when_excep = False)
|
| 102 |
+
exit()
|
| 103 |
+
|
| 104 |
+
# control_cluster_client =
|
| 105 |
+
# control_cluster_client.run() # spawns the controllers on separate processes (blocking)
|
| 106 |
+
|
bundles/centauro/d2026_02_21_h14_m01_s10-CentauroCloopPartialUbNoWheels_FakePosTrackingEnv/launch_train_env.py
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from aug_mpc.utils.determinism import deterministic_run
|
| 2 |
+
|
| 3 |
+
from mpc_hive.utilities.shared_data.sim_data import SharedEnvInfo
|
| 4 |
+
from mpc_hive.utilities.shared_data.cluster_data import SharedClusterInfo
|
| 5 |
+
|
| 6 |
+
from EigenIPC.PyEigenIPC import VLevel, Journal, LogType
|
| 7 |
+
from EigenIPC.PyEigenIPC import StringTensorServer
|
| 8 |
+
|
| 9 |
+
import os, argparse, sys, types, inspect
|
| 10 |
+
|
| 11 |
+
from perf_sleep.pyperfsleep import PerfSleep
|
| 12 |
+
|
| 13 |
+
import importlib.util
|
| 14 |
+
import torch
|
| 15 |
+
import signal
|
| 16 |
+
|
| 17 |
+
algo = None # global to make it accessible by signal handler
|
| 18 |
+
exit_request=False
|
| 19 |
+
dummy_step_exit_req=False
|
| 20 |
+
|
| 21 |
+
def handle_sigint(signum, frame):
|
| 22 |
+
global exit_request, dummy_step_exit_req
|
| 23 |
+
Journal.log("launch_train_env.py",
|
| 24 |
+
"",
|
| 25 |
+
f"Received sigint. Will stop training.",
|
| 26 |
+
LogType.WARN)
|
| 27 |
+
exit_request=True
|
| 28 |
+
dummy_step_exit_req=True # in case dummy_step_loop was used
|
| 29 |
+
|
| 30 |
+
# Function to dynamically import a module from a specific file path
|
| 31 |
+
# def import_env_module(env_path):
|
| 32 |
+
# spec = importlib.util.spec_from_file_location("env_module", env_path)
|
| 33 |
+
# env_module = importlib.util.module_from_spec(spec)
|
| 34 |
+
# spec.loader.exec_module(env_module)
|
| 35 |
+
# return env_module
|
| 36 |
+
|
| 37 |
+
def import_env_module(env_path, local_env_root: str = None):
|
| 38 |
+
"""
|
| 39 |
+
env_path: full path to the child env .py file to exec
|
| 40 |
+
local_env_root: directory where local copies of aug_mpc_envs.training_envs modules live
|
| 41 |
+
"""
|
| 42 |
+
if local_env_root is not None:
|
| 43 |
+
local_env_root = os.path.abspath(local_env_root)
|
| 44 |
+
# override aug_mpc_envs.training_envs package to point to the local_env_root
|
| 45 |
+
pkg_name = "aug_mpc_envs.training_envs"
|
| 46 |
+
if pkg_name not in sys.modules:
|
| 47 |
+
mod = types.ModuleType(pkg_name)
|
| 48 |
+
mod.__path__ = [local_env_root] # tell Python to look here first
|
| 49 |
+
sys.modules[pkg_name] = mod
|
| 50 |
+
else:
|
| 51 |
+
existing = getattr(sys.modules[pkg_name], "__path__", None)
|
| 52 |
+
if existing is None:
|
| 53 |
+
sys.modules[pkg_name].__path__ = [local_env_root]
|
| 54 |
+
elif local_env_root not in existing:
|
| 55 |
+
existing.insert(0, local_env_root)
|
| 56 |
+
|
| 57 |
+
# load the module as usual
|
| 58 |
+
spec = importlib.util.spec_from_file_location("env_module", env_path)
|
| 59 |
+
env_module = importlib.util.module_from_spec(spec)
|
| 60 |
+
spec.loader.exec_module(env_module)
|
| 61 |
+
return env_module
|
| 62 |
+
|
| 63 |
+
def log_env_hierarchy(env_class, env_path, env_type="training"):
|
| 64 |
+
"""
|
| 65 |
+
Logs the env class, its file, and full inheritance hierarchy with file paths.
|
| 66 |
+
env_class: the child env class
|
| 67 |
+
env_path: file path where the child class was loaded from
|
| 68 |
+
env_type: string label, e.g., "training", "evaluation", "resumed_training"
|
| 69 |
+
"""
|
| 70 |
+
def get_bases_recursive(cls):
|
| 71 |
+
"""Recursively get all base classes with their file paths."""
|
| 72 |
+
info = []
|
| 73 |
+
for base in cls.__bases__:
|
| 74 |
+
try:
|
| 75 |
+
file = inspect.getfile(base)
|
| 76 |
+
except TypeError:
|
| 77 |
+
file = "built-in or unknown"
|
| 78 |
+
info.append(f"{base.__name__} (from {file})")
|
| 79 |
+
# Recurse unless it's object
|
| 80 |
+
if base is not object:
|
| 81 |
+
info.extend(get_bases_recursive(base))
|
| 82 |
+
return info
|
| 83 |
+
|
| 84 |
+
hierarchy_info = get_bases_recursive(env_class)
|
| 85 |
+
hierarchy_str = " -> ".join(hierarchy_info) if hierarchy_info else "No parents"
|
| 86 |
+
|
| 87 |
+
Journal.log(
|
| 88 |
+
"launch_train_env.py",
|
| 89 |
+
"",
|
| 90 |
+
f"loading {env_type} env {env_class.__name__} (from {env_path}) "
|
| 91 |
+
f"with hierarchy: {hierarchy_str}",
|
| 92 |
+
LogType.INFO,
|
| 93 |
+
throw_when_excep=True
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
def dummy_step_loop(env):
|
| 97 |
+
global dummy_step_exit_req
|
| 98 |
+
while True:
|
| 99 |
+
if dummy_step_exit_req:
|
| 100 |
+
return True
|
| 101 |
+
step_ok=env.step(action=env.safe_action) # not a busy loop because of MPC in the step
|
| 102 |
+
if not step_ok:
|
| 103 |
+
return False
|
| 104 |
+
|
| 105 |
+
if __name__ == "__main__":
|
| 106 |
+
|
| 107 |
+
signal.signal(signal.SIGINT, handle_sigint)
|
| 108 |
+
|
| 109 |
+
# Parse command line arguments for CPU affinity
|
| 110 |
+
parser = argparse.ArgumentParser(description="Set CPU affinity for the script.")
|
| 111 |
+
|
| 112 |
+
parser.add_argument('--run_name', type=str, default=None, help='Name of training run')
|
| 113 |
+
parser.add_argument('--ns', type=str, help='Namespace to be used for shared memory')
|
| 114 |
+
parser.add_argument('--timeout_ms', type=int, help='Connection timeout after which the script self-terminates', default=60000)
|
| 115 |
+
parser.add_argument('--drop_dir', type=str, help='Directory root where all run data will be dumped')
|
| 116 |
+
parser.add_argument('--comment', type=str, help='Any useful comment associated with this run', default="")
|
| 117 |
+
parser.add_argument('--seed', type=int, help='Seed', default=1)
|
| 118 |
+
parser.add_argument('--use_cpu',action='store_true', help='If set, all the training (data included) will be performed on CPU')
|
| 119 |
+
|
| 120 |
+
parser.add_argument('--db',action='store_true', help='Whether to enable local data logging for the algorithm (reward metrics, etc.)')
|
| 121 |
+
parser.add_argument('--env_db',action='store_true', help='Whether to enable env db data logging on shared mem (e.g. reward metrics are not available for reading anymore)')
|
| 122 |
+
parser.add_argument('--full_env_db',action='store_true', help='Whether to enable detailed episodic data storage (data over single transitions)')
|
| 123 |
+
parser.add_argument('--rmdb',action='store_true', help='Whether to enable remote debug (e.g. data logging on remote servers)')
|
| 124 |
+
|
| 125 |
+
parser.add_argument('--tot_tsteps', type=int, help='Total number of timesteps to be collected', default=int(30e6))
|
| 126 |
+
parser.add_argument('--action_repeat', type=int, help='Frame skipping (1-> no skip)', default=1)
|
| 127 |
+
parser.add_argument('--discount_factor', type=float, help='', default=0.99)
|
| 128 |
+
parser.add_argument('--obs_norm',action='store_true', help='Whether to enable the use of running normalizer in agent')
|
| 129 |
+
parser.add_argument('--obs_rescale',action='store_true', help='Whether to rescale observation depending on their expected range')
|
| 130 |
+
parser.add_argument('--add_weight_norm',action='store_true', help='Whether to add weight normalization to agent interal llayers')
|
| 131 |
+
parser.add_argument('--add_layer_norm',action='store_true', help='Whether to add layer normalization to agent internal llayers')
|
| 132 |
+
parser.add_argument('--add_batch_norm',action='store_true', help='Whether to add batch normalization to agent internal llayers')
|
| 133 |
+
|
| 134 |
+
parser.add_argument('--act_rescale_critic',action='store_true', help='Whether to rescale actions provided to critic (if SAC) to be in range [-1, 1]')
|
| 135 |
+
parser.add_argument('--use_period_resets',action='store_true', help='')
|
| 136 |
+
|
| 137 |
+
parser.add_argument('--sac',action='store_true', help='Use SAC, otherwise PPO, unless dummy is set')
|
| 138 |
+
parser.add_argument('--dummy',action='store_true', help='Use dummy agent (useful for testing and debugging environments)')
|
| 139 |
+
|
| 140 |
+
parser.add_argument('--dump_checkpoints',action='store_true', help='Whether to dump model checkpoints during training')
|
| 141 |
+
|
| 142 |
+
parser.add_argument('--demo_envs_perc', type=float, help='[0, 1]', default=0.0)
|
| 143 |
+
parser.add_argument('--demo_stop_thresh', type=float, default=None,
|
| 144 |
+
help='Performance hreshold above which demonstration envs should be deactivated.')
|
| 145 |
+
|
| 146 |
+
parser.add_argument('--expl_envs_perc', type=float, help='[0, 1]', default=0)
|
| 147 |
+
|
| 148 |
+
parser.add_argument('--use_rnd',action='store_true', help='Whether to use RND for exploration')
|
| 149 |
+
|
| 150 |
+
parser.add_argument('--eval',action='store_true', help='Whether to perform an evaluation run')
|
| 151 |
+
parser.add_argument('--n_eval_timesteps', type=int, help='Total number of timesteps to be evaluated', default=int(1e6))
|
| 152 |
+
parser.add_argument('--det_eval',action='store_true', help='Whether to perform a deterministic eval (only action mean is used). Only valid if --eval.')
|
| 153 |
+
parser.add_argument('--allow_expl_during_eval',action='store_true', help='Whether to allow expl envs during evaluation (useful to tune exploration)')
|
| 154 |
+
|
| 155 |
+
parser.add_argument('--resume',action='store_true', help='Resume a previous training using a checkpoint')
|
| 156 |
+
parser.add_argument('--mpath', type=str, help='Model path to be used for policy evaluation', default=None)
|
| 157 |
+
parser.add_argument('--mname', type=str, help='Model name', default=None)
|
| 158 |
+
parser.add_argument('--override_env',action='store_true', help='Whether to override env when running evaluation')
|
| 159 |
+
|
| 160 |
+
parser.add_argument('--anomaly_detect',action='store_true', help='Whether to enable anomaly detection (useful for debug)')
|
| 161 |
+
|
| 162 |
+
parser.add_argument('--compression_ratio', type=float,
|
| 163 |
+
help='If e.g. 0.8, the fist layer will be of dimension [input_features_size x (input_features_size*compression_ratio)]', default=-1.0)
|
| 164 |
+
parser.add_argument('--actor_lwidth', type=int, help='Actor network layer width', default=128)
|
| 165 |
+
parser.add_argument('--critic_lwidth', type=int, help='Critic network layer width', default=256)
|
| 166 |
+
parser.add_argument('--actor_n_hlayers', type=int, help='Actor network size', default=3)
|
| 167 |
+
parser.add_argument('--critic_n_hlayers', type=int, help='Critic network size', default=4)
|
| 168 |
+
|
| 169 |
+
parser.add_argument('--env_fname', type=str, default="twist_tracking_env", help='Training env file name (without extension)')
|
| 170 |
+
parser.add_argument('--env_classname', type=str, default="TwistTrackingEnv", help='Training env class name')
|
| 171 |
+
parser.add_argument('--override_agent_actions',action='store_true', help='Whether to override agent actions with custom ones from shared mem (useful for db)')
|
| 172 |
+
parser.add_argument('--override_agent_refs',action='store_true', help='Whether to override automatically generated agent refs (useful for debug)')
|
| 173 |
+
|
| 174 |
+
parser.add_argument('--step_while_setup',action='store_true', help='Continue stepping env with default actions while setting up agent, etc..')
|
| 175 |
+
parser.add_argument('--reset_on_init',action='store_true', help='Whether to reset the environment on initialization')
|
| 176 |
+
|
| 177 |
+
args = parser.parse_args()
|
| 178 |
+
args_dict = vars(args)
|
| 179 |
+
|
| 180 |
+
if args.eval and args.resume:
|
| 181 |
+
Journal.log("launch_train_env.py",
|
| 182 |
+
"",
|
| 183 |
+
f"Cannot set both --eval and --resume flags. Exiting.",
|
| 184 |
+
LogType.EXCEP,
|
| 185 |
+
throw_when_excep = True)
|
| 186 |
+
|
| 187 |
+
deterministic_run(seed=args.seed, torch_det_algos=False)
|
| 188 |
+
|
| 189 |
+
anomaly_detect=False
|
| 190 |
+
if args.anomaly_detect:
|
| 191 |
+
torch.autograd.set_detect_anomaly(True)
|
| 192 |
+
|
| 193 |
+
if (not args.mpath is None) and (not args.mname is None):
|
| 194 |
+
mpath_full = os.path.join(args.mpath, args.mname)
|
| 195 |
+
else:
|
| 196 |
+
mpath_full=None
|
| 197 |
+
|
| 198 |
+
env_fname=args.env_fname
|
| 199 |
+
env_classname = args.env_classname
|
| 200 |
+
env_path=""
|
| 201 |
+
env_module=None
|
| 202 |
+
if (not args.eval and not args.resume) or (args.override_env):
|
| 203 |
+
# if starting a fresh traning or overriding env, load from a fresh env from aug_mpc
|
| 204 |
+
env_path = f"aug_mpc_envs.training_envs.{env_fname}"
|
| 205 |
+
env_module = importlib.import_module(env_path)
|
| 206 |
+
else:
|
| 207 |
+
if args.mpath is None:
|
| 208 |
+
Journal.log("launch_train_env.py",
|
| 209 |
+
"",
|
| 210 |
+
f"no mpath provided! Cannot load env. Either provide a mpath or run with --override_env",
|
| 211 |
+
LogType.EXCEP,
|
| 212 |
+
throw_when_excep = True)
|
| 213 |
+
|
| 214 |
+
env_path = os.path.join(args.mpath, env_fname + ".py")
|
| 215 |
+
env_module = import_env_module(env_path, local_env_root=args.mpath)
|
| 216 |
+
|
| 217 |
+
EnvClass = getattr(env_module, env_classname)
|
| 218 |
+
env_type = "training" if not args.eval else "evaluation"
|
| 219 |
+
if args.resume:
|
| 220 |
+
env_type = "resumed_training"
|
| 221 |
+
log_env_hierarchy(EnvClass, env_path, env_type) # db print of env class
|
| 222 |
+
|
| 223 |
+
env = EnvClass(namespace=args.ns,
|
| 224 |
+
verbose=True,
|
| 225 |
+
vlevel=VLevel.V2,
|
| 226 |
+
use_gpu=not args.use_cpu,
|
| 227 |
+
debug=args.env_db,
|
| 228 |
+
override_agent_refs=args.override_agent_refs,
|
| 229 |
+
timeout_ms=args.timeout_ms,
|
| 230 |
+
env_opts=args_dict)
|
| 231 |
+
if not env.is_ready(): # something went wrong
|
| 232 |
+
exit()
|
| 233 |
+
|
| 234 |
+
dummy_step_thread = None
|
| 235 |
+
if args.step_while_setup:
|
| 236 |
+
import threading
|
| 237 |
+
# spawn step thread (we don't true parallelization, thread is fine)
|
| 238 |
+
# start the dummy stepping in a separate thread so setup can continue concurrently
|
| 239 |
+
dummy_step_thread = threading.Thread(target=dummy_step_loop, args=(env,), daemon=True)
|
| 240 |
+
dummy_step_thread.start()
|
| 241 |
+
|
| 242 |
+
# getting some sim info for debugging
|
| 243 |
+
sim_data = {}
|
| 244 |
+
sim_info_shared = SharedEnvInfo(namespace=args.ns,
|
| 245 |
+
is_server=False,
|
| 246 |
+
safe=False)
|
| 247 |
+
sim_info_shared.run()
|
| 248 |
+
sim_info_keys = sim_info_shared.param_keys
|
| 249 |
+
sim_info_data = sim_info_shared.get().flatten()
|
| 250 |
+
for i in range(len(sim_info_keys)):
|
| 251 |
+
sim_data[sim_info_keys[i]] = sim_info_data[i]
|
| 252 |
+
|
| 253 |
+
# getting come cluster info for debugging
|
| 254 |
+
cluster_data={}
|
| 255 |
+
cluste_info_shared = SharedClusterInfo(namespace=args.ns,
|
| 256 |
+
is_server=False,
|
| 257 |
+
safe=False)
|
| 258 |
+
cluste_info_shared.run()
|
| 259 |
+
cluster_info_keys = cluste_info_shared.param_keys
|
| 260 |
+
cluster_info_data = cluste_info_shared.get().flatten()
|
| 261 |
+
for i in range(len(cluster_info_keys)):
|
| 262 |
+
cluster_data[cluster_info_keys[i]] = cluster_info_data[i]
|
| 263 |
+
|
| 264 |
+
custom_args={}
|
| 265 |
+
custom_args["uname_host"]="user_host"
|
| 266 |
+
try:
|
| 267 |
+
username = os.getlogin() # add machine info to db data
|
| 268 |
+
hostname = os.uname().nodename
|
| 269 |
+
user_host = f"{username}@{hostname}"
|
| 270 |
+
custom_args["uname_host"]=user_host
|
| 271 |
+
except:
|
| 272 |
+
pass
|
| 273 |
+
|
| 274 |
+
algo=None
|
| 275 |
+
if not args.dummy:
|
| 276 |
+
if args.sac:
|
| 277 |
+
from aug_mpc.training_algs.sac.sac import SAC
|
| 278 |
+
|
| 279 |
+
algo = SAC(env=env,
|
| 280 |
+
debug=args.db,
|
| 281 |
+
remote_db=args.rmdb,
|
| 282 |
+
seed=args.seed)
|
| 283 |
+
else:
|
| 284 |
+
from aug_mpc.training_algs.ppo.ppo import PPO
|
| 285 |
+
|
| 286 |
+
algo = PPO(env=env,
|
| 287 |
+
debug=args.db,
|
| 288 |
+
remote_db=args.rmdb,
|
| 289 |
+
seed=args.seed)
|
| 290 |
+
else:
|
| 291 |
+
from aug_mpc.training_algs.dummy.dummy import Dummy
|
| 292 |
+
|
| 293 |
+
algo=Dummy(env=env,
|
| 294 |
+
debug=args.db,
|
| 295 |
+
remote_db=args.rmdb,
|
| 296 |
+
seed=args.seed)
|
| 297 |
+
|
| 298 |
+
custom_args.update(args_dict)
|
| 299 |
+
custom_args.update(cluster_data)
|
| 300 |
+
custom_args.update(sim_data)
|
| 301 |
+
|
| 302 |
+
run_name=env_classname if args.run_name is None else args.run_name
|
| 303 |
+
algo.setup(run_name=run_name,
|
| 304 |
+
ns=args.ns,
|
| 305 |
+
verbose=True,
|
| 306 |
+
drop_dir_name=args.drop_dir,
|
| 307 |
+
custom_args=custom_args,
|
| 308 |
+
comment=args.comment,
|
| 309 |
+
eval=args.eval,
|
| 310 |
+
resume=args.resume,
|
| 311 |
+
model_path=mpath_full,
|
| 312 |
+
n_eval_timesteps=args.n_eval_timesteps,
|
| 313 |
+
dump_checkpoints=args.dump_checkpoints,
|
| 314 |
+
norm_obs=args.obs_norm,
|
| 315 |
+
rescale_obs=args.obs_rescale)
|
| 316 |
+
|
| 317 |
+
full_drop_dir=algo.drop_dir()
|
| 318 |
+
shared_drop_dir = StringTensorServer(length=1,
|
| 319 |
+
basename="SharedTrainingDropDir",
|
| 320 |
+
name_space=args.ns,
|
| 321 |
+
verbose=True,
|
| 322 |
+
vlevel=VLevel.V2,
|
| 323 |
+
force_reconnection=True)
|
| 324 |
+
shared_drop_dir.run()
|
| 325 |
+
|
| 326 |
+
while True:
|
| 327 |
+
if not shared_drop_dir.write_vec([full_drop_dir], 0):
|
| 328 |
+
ns=1000000000
|
| 329 |
+
PerfSleep.thread_sleep(ns)
|
| 330 |
+
continue
|
| 331 |
+
else:
|
| 332 |
+
break
|
| 333 |
+
|
| 334 |
+
if args.step_while_setup:
|
| 335 |
+
# stop dummy step thread and give algo authority on step
|
| 336 |
+
dummy_step_exit_req=True
|
| 337 |
+
# wait for thread to join
|
| 338 |
+
if dummy_step_thread is not None:
|
| 339 |
+
dummy_step_thread.join()
|
| 340 |
+
Journal.log("launch_train_env.py",
|
| 341 |
+
"",
|
| 342 |
+
f"Dummy env step thread joined. Moving step authority to algo.",
|
| 343 |
+
LogType.INFO)
|
| 344 |
+
|
| 345 |
+
eval=args.eval
|
| 346 |
+
if args.override_agent_actions:
|
| 347 |
+
eval=True
|
| 348 |
+
if not eval:
|
| 349 |
+
while not exit_request:
|
| 350 |
+
if not algo.learn():
|
| 351 |
+
break
|
| 352 |
+
else: # eval phase
|
| 353 |
+
with torch.no_grad(): # no need for grad computation
|
| 354 |
+
while not exit_request:
|
| 355 |
+
if not algo.eval():
|
| 356 |
+
break
|
| 357 |
+
|
| 358 |
+
algo.done() # make sure to terminate training properly
|