v0.1.17
This commit is contained in:
20
CMD.md
20
CMD.md
@@ -15,6 +15,20 @@ python robogauge/scripts/run.py \
|
|||||||
--num-processes 5 \
|
--num-processes 5 \
|
||||||
--seeds 0 1 2 3 4 \
|
--seeds 0 1 2 3 4 \
|
||||||
--frictions 0.5 1.0 1.5 2.0 2.5 \
|
--frictions 0.5 1.0 1.5 2.0 2.5 \
|
||||||
|
--compress-logs \
|
||||||
|
--headless
|
||||||
|
|
||||||
|
# Terrain with Level, need specify goals (default is target_pos)
|
||||||
|
python robogauge/scripts/run.py \
|
||||||
|
--task go2_moe.slope \
|
||||||
|
--experiment-name debug \
|
||||||
|
--multi \
|
||||||
|
--num-processes 5 \
|
||||||
|
--seeds 0 1 2 3 4 \
|
||||||
|
--frictions 1.0 \
|
||||||
|
--level 3 \
|
||||||
|
--goals max_velocity diagonal_velocity\
|
||||||
|
--compress-logs \
|
||||||
--headless
|
--headless
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -25,8 +39,9 @@ python robogauge/scripts/run.py \
|
|||||||
--task go2_moe.slope \
|
--task go2_moe.slope \
|
||||||
--experiment-name debug \
|
--experiment-name debug \
|
||||||
--search-max-level \
|
--search-max-level \
|
||||||
--seeds 0 1 2 \
|
--seeds 0 1 2 3 4 \
|
||||||
--frictions 1.0 \
|
--frictions 1.0 \
|
||||||
|
--compress-logs \
|
||||||
--headless
|
--headless
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -39,8 +54,9 @@ python robogauge/scripts/run.py \
|
|||||||
--stress-terrain-names flat slope stairs_up stairs_down wave \
|
--stress-terrain-names flat slope stairs_up stairs_down wave \
|
||||||
--stress-num-processes 2 \
|
--stress-num-processes 2 \
|
||||||
--num-processes 3 \
|
--num-processes 3 \
|
||||||
--seeds 0 1 2 \
|
--seeds 0 1 2 3 4 \
|
||||||
--frictions 0.5 1.0 1.5 2.0 2.5 \
|
--frictions 0.5 1.0 1.5 2.0 2.5 \
|
||||||
|
--compress-logs \
|
||||||
--headless
|
--headless
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,14 @@
|
|||||||
| - | - | - |
|
| - | - | - |
|
||||||
| Unitree go2 | 四足 | ✅ |
|
| Unitree go2 | 四足 | ✅ |
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
参考[PyTorch官网](https://pytorch.org/get-started/locally/)安装2.0以上任意版本, 安装本仓库
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/wty-yy/RoboGauge.git
|
||||||
|
pip install -e .
|
||||||
|
```
|
||||||
|
|
||||||
## 目录结构
|
## 目录结构
|
||||||
- `robogauge/scripts`: 启动指标测试程序
|
- `robogauge/scripts`: 启动指标测试程序
|
||||||
- `robogauge/tasks`: 定义测试任务
|
- `robogauge/tasks`: 定义测试任务
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
# UPDATE
|
# UPDATE
|
||||||
|
## 20251227
|
||||||
|
### v0.1.17
|
||||||
|
1. args中添加`goals`配置, 在LevelPipeline和MultiPipeline中指定goals, 修正压力测试中评估的目标不对的问题
|
||||||
|
2. 评估必须使用5个种子, 否则LevelPipeline中的80%通过率就没有意义了, 并且提高5个种子最终的评级影响可能非常大 (moe.stairs_up Friction 2.0从Lv 7->10)
|
||||||
|
3. 在StressPipeline测试中, 不再保存
|
||||||
|
4. 添加obstacles地形
|
||||||
|
5. 优化分数计算方法, 按照`(level-1)*0.1+metric_score`计算
|
||||||
|
6. 加入日志文件夹递归保存, StressPipeline -> LevelPipeline -> MultiPipeline, 加入压缩参数`--compress-logs`, 将日志文件夹压缩为`subtasks.tar.xz`, 日志文件压缩`4M->100kb`
|
||||||
## 20251226
|
## 20251226
|
||||||
### v0.1.16
|
### v0.1.16
|
||||||
1. 基本完成StressPipeline, 加入绘制进度条的线程, 其他进程通过Queue更新主进程的进度条
|
1. 基本完成StressPipeline, 加入绘制进度条的线程, 其他进程通过Queue更新主进程的进度条
|
||||||
|
|||||||
23
resources/terrains/obstacle/obstacle_1.xml
Normal file
23
resources/terrains/obstacle/obstacle_1.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<mujoco model="obstacle_1">
|
||||||
|
<!-- Terrain Type: obstacle, Level: 1, Obstacle height: 0.0730, length: 1.0000, gap: 1.0000 -->
|
||||||
|
<statistic center="0 0 0.1" extent="0.8" />
|
||||||
|
<visual>
|
||||||
|
<headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0" />
|
||||||
|
<rgba haze="0.15 0.25 0.35 1" />
|
||||||
|
<global azimuth="-130" elevation="-20" />
|
||||||
|
</visual>
|
||||||
|
<asset>
|
||||||
|
<texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072" />
|
||||||
|
<texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300" />
|
||||||
|
<material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.0" />
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<light pos="0 0 1.5" dir="0 0 -1" directional="true" />
|
||||||
|
<geom name="floor" size="0 0 0.05" type="plane" material="groundplane" />
|
||||||
|
<geom pos="1.5 0.0 0.036500000000000005" type="box" size="0.5 5.0 0.036500000000000005" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="3.5 0.0 0.036500000000000005" type="box" size="0.5 5.0 0.036500000000000005" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="5.5 0.0 0.036500000000000005" type="box" size="0.5 5.0 0.036500000000000005" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="7.5 0.0 0.036500000000000005" type="box" size="0.5 5.0 0.036500000000000005" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="9.5 0.0 0.036500000000000005" type="box" size="0.5 5.0 0.036500000000000005" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
23
resources/terrains/obstacle/obstacle_10.xml
Normal file
23
resources/terrains/obstacle/obstacle_10.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<mujoco model="obstacle_10">
|
||||||
|
<!-- Terrain Type: obstacle, Level: 10, Obstacle height: 0.2800, length: 1.0000, gap: 1.0000 -->
|
||||||
|
<statistic center="0 0 0.1" extent="0.8" />
|
||||||
|
<visual>
|
||||||
|
<headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0" />
|
||||||
|
<rgba haze="0.15 0.25 0.35 1" />
|
||||||
|
<global azimuth="-130" elevation="-20" />
|
||||||
|
</visual>
|
||||||
|
<asset>
|
||||||
|
<texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072" />
|
||||||
|
<texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300" />
|
||||||
|
<material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.0" />
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<light pos="0 0 1.5" dir="0 0 -1" directional="true" />
|
||||||
|
<geom name="floor" size="0 0 0.05" type="plane" material="groundplane" />
|
||||||
|
<geom pos="1.5 0.0 0.14" type="box" size="0.5 5.0 0.14" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="3.5 0.0 0.14" type="box" size="0.5 5.0 0.14" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="5.5 0.0 0.14" type="box" size="0.5 5.0 0.14" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="7.5 0.0 0.14" type="box" size="0.5 5.0 0.14" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="9.5 0.0 0.14" type="box" size="0.5 5.0 0.14" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
23
resources/terrains/obstacle/obstacle_2.xml
Normal file
23
resources/terrains/obstacle/obstacle_2.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<mujoco model="obstacle_2">
|
||||||
|
<!-- Terrain Type: obstacle, Level: 2, Obstacle height: 0.0960, length: 1.0000, gap: 1.0000 -->
|
||||||
|
<statistic center="0 0 0.1" extent="0.8" />
|
||||||
|
<visual>
|
||||||
|
<headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0" />
|
||||||
|
<rgba haze="0.15 0.25 0.35 1" />
|
||||||
|
<global azimuth="-130" elevation="-20" />
|
||||||
|
</visual>
|
||||||
|
<asset>
|
||||||
|
<texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072" />
|
||||||
|
<texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300" />
|
||||||
|
<material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.0" />
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<light pos="0 0 1.5" dir="0 0 -1" directional="true" />
|
||||||
|
<geom name="floor" size="0 0 0.05" type="plane" material="groundplane" />
|
||||||
|
<geom pos="1.5 0.0 0.048" type="box" size="0.5 5.0 0.048" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="3.5 0.0 0.048" type="box" size="0.5 5.0 0.048" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="5.5 0.0 0.048" type="box" size="0.5 5.0 0.048" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="7.5 0.0 0.048" type="box" size="0.5 5.0 0.048" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="9.5 0.0 0.048" type="box" size="0.5 5.0 0.048" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
23
resources/terrains/obstacle/obstacle_3.xml
Normal file
23
resources/terrains/obstacle/obstacle_3.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<mujoco model="obstacle_3">
|
||||||
|
<!-- Terrain Type: obstacle, Level: 3, Obstacle height: 0.1190, length: 1.0000, gap: 1.0000 -->
|
||||||
|
<statistic center="0 0 0.1" extent="0.8" />
|
||||||
|
<visual>
|
||||||
|
<headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0" />
|
||||||
|
<rgba haze="0.15 0.25 0.35 1" />
|
||||||
|
<global azimuth="-130" elevation="-20" />
|
||||||
|
</visual>
|
||||||
|
<asset>
|
||||||
|
<texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072" />
|
||||||
|
<texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300" />
|
||||||
|
<material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.0" />
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<light pos="0 0 1.5" dir="0 0 -1" directional="true" />
|
||||||
|
<geom name="floor" size="0 0 0.05" type="plane" material="groundplane" />
|
||||||
|
<geom pos="1.5 0.0 0.059500000000000004" type="box" size="0.5 5.0 0.059500000000000004" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="3.5 0.0 0.059500000000000004" type="box" size="0.5 5.0 0.059500000000000004" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="5.5 0.0 0.059500000000000004" type="box" size="0.5 5.0 0.059500000000000004" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="7.5 0.0 0.059500000000000004" type="box" size="0.5 5.0 0.059500000000000004" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="9.5 0.0 0.059500000000000004" type="box" size="0.5 5.0 0.059500000000000004" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
23
resources/terrains/obstacle/obstacle_4.xml
Normal file
23
resources/terrains/obstacle/obstacle_4.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<mujoco model="obstacle_4">
|
||||||
|
<!-- Terrain Type: obstacle, Level: 4, Obstacle height: 0.1420, length: 1.0000, gap: 1.0000 -->
|
||||||
|
<statistic center="0 0 0.1" extent="0.8" />
|
||||||
|
<visual>
|
||||||
|
<headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0" />
|
||||||
|
<rgba haze="0.15 0.25 0.35 1" />
|
||||||
|
<global azimuth="-130" elevation="-20" />
|
||||||
|
</visual>
|
||||||
|
<asset>
|
||||||
|
<texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072" />
|
||||||
|
<texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300" />
|
||||||
|
<material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.0" />
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<light pos="0 0 1.5" dir="0 0 -1" directional="true" />
|
||||||
|
<geom name="floor" size="0 0 0.05" type="plane" material="groundplane" />
|
||||||
|
<geom pos="1.5 0.0 0.07100000000000001" type="box" size="0.5 5.0 0.07100000000000001" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="3.5 0.0 0.07100000000000001" type="box" size="0.5 5.0 0.07100000000000001" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="5.5 0.0 0.07100000000000001" type="box" size="0.5 5.0 0.07100000000000001" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="7.5 0.0 0.07100000000000001" type="box" size="0.5 5.0 0.07100000000000001" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="9.5 0.0 0.07100000000000001" type="box" size="0.5 5.0 0.07100000000000001" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
23
resources/terrains/obstacle/obstacle_5.xml
Normal file
23
resources/terrains/obstacle/obstacle_5.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<mujoco model="obstacle_5">
|
||||||
|
<!-- Terrain Type: obstacle, Level: 5, Obstacle height: 0.1650, length: 1.0000, gap: 1.0000 -->
|
||||||
|
<statistic center="0 0 0.1" extent="0.8" />
|
||||||
|
<visual>
|
||||||
|
<headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0" />
|
||||||
|
<rgba haze="0.15 0.25 0.35 1" />
|
||||||
|
<global azimuth="-130" elevation="-20" />
|
||||||
|
</visual>
|
||||||
|
<asset>
|
||||||
|
<texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072" />
|
||||||
|
<texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300" />
|
||||||
|
<material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.0" />
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<light pos="0 0 1.5" dir="0 0 -1" directional="true" />
|
||||||
|
<geom name="floor" size="0 0 0.05" type="plane" material="groundplane" />
|
||||||
|
<geom pos="1.5 0.0 0.0825" type="box" size="0.5 5.0 0.0825" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="3.5 0.0 0.0825" type="box" size="0.5 5.0 0.0825" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="5.5 0.0 0.0825" type="box" size="0.5 5.0 0.0825" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="7.5 0.0 0.0825" type="box" size="0.5 5.0 0.0825" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="9.5 0.0 0.0825" type="box" size="0.5 5.0 0.0825" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
23
resources/terrains/obstacle/obstacle_6.xml
Normal file
23
resources/terrains/obstacle/obstacle_6.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<mujoco model="obstacle_6">
|
||||||
|
<!-- Terrain Type: obstacle, Level: 6, Obstacle height: 0.1880, length: 1.0000, gap: 1.0000 -->
|
||||||
|
<statistic center="0 0 0.1" extent="0.8" />
|
||||||
|
<visual>
|
||||||
|
<headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0" />
|
||||||
|
<rgba haze="0.15 0.25 0.35 1" />
|
||||||
|
<global azimuth="-130" elevation="-20" />
|
||||||
|
</visual>
|
||||||
|
<asset>
|
||||||
|
<texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072" />
|
||||||
|
<texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300" />
|
||||||
|
<material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.0" />
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<light pos="0 0 1.5" dir="0 0 -1" directional="true" />
|
||||||
|
<geom name="floor" size="0 0 0.05" type="plane" material="groundplane" />
|
||||||
|
<geom pos="1.5 0.0 0.094" type="box" size="0.5 5.0 0.094" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="3.5 0.0 0.094" type="box" size="0.5 5.0 0.094" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="5.5 0.0 0.094" type="box" size="0.5 5.0 0.094" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="7.5 0.0 0.094" type="box" size="0.5 5.0 0.094" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="9.5 0.0 0.094" type="box" size="0.5 5.0 0.094" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
23
resources/terrains/obstacle/obstacle_7.xml
Normal file
23
resources/terrains/obstacle/obstacle_7.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<mujoco model="obstacle_7">
|
||||||
|
<!-- Terrain Type: obstacle, Level: 7, Obstacle height: 0.2110, length: 1.0000, gap: 1.0000 -->
|
||||||
|
<statistic center="0 0 0.1" extent="0.8" />
|
||||||
|
<visual>
|
||||||
|
<headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0" />
|
||||||
|
<rgba haze="0.15 0.25 0.35 1" />
|
||||||
|
<global azimuth="-130" elevation="-20" />
|
||||||
|
</visual>
|
||||||
|
<asset>
|
||||||
|
<texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072" />
|
||||||
|
<texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300" />
|
||||||
|
<material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.0" />
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<light pos="0 0 1.5" dir="0 0 -1" directional="true" />
|
||||||
|
<geom name="floor" size="0 0 0.05" type="plane" material="groundplane" />
|
||||||
|
<geom pos="1.5 0.0 0.10550000000000001" type="box" size="0.5 5.0 0.10550000000000001" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="3.5 0.0 0.10550000000000001" type="box" size="0.5 5.0 0.10550000000000001" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="5.5 0.0 0.10550000000000001" type="box" size="0.5 5.0 0.10550000000000001" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="7.5 0.0 0.10550000000000001" type="box" size="0.5 5.0 0.10550000000000001" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="9.5 0.0 0.10550000000000001" type="box" size="0.5 5.0 0.10550000000000001" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
23
resources/terrains/obstacle/obstacle_8.xml
Normal file
23
resources/terrains/obstacle/obstacle_8.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<mujoco model="obstacle_8">
|
||||||
|
<!-- Terrain Type: obstacle, Level: 8, Obstacle height: 0.2340, length: 1.0000, gap: 1.0000 -->
|
||||||
|
<statistic center="0 0 0.1" extent="0.8" />
|
||||||
|
<visual>
|
||||||
|
<headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0" />
|
||||||
|
<rgba haze="0.15 0.25 0.35 1" />
|
||||||
|
<global azimuth="-130" elevation="-20" />
|
||||||
|
</visual>
|
||||||
|
<asset>
|
||||||
|
<texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072" />
|
||||||
|
<texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300" />
|
||||||
|
<material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.0" />
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<light pos="0 0 1.5" dir="0 0 -1" directional="true" />
|
||||||
|
<geom name="floor" size="0 0 0.05" type="plane" material="groundplane" />
|
||||||
|
<geom pos="1.5 0.0 0.11700000000000002" type="box" size="0.5 5.0 0.11700000000000002" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="3.5 0.0 0.11700000000000002" type="box" size="0.5 5.0 0.11700000000000002" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="5.5 0.0 0.11700000000000002" type="box" size="0.5 5.0 0.11700000000000002" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="7.5 0.0 0.11700000000000002" type="box" size="0.5 5.0 0.11700000000000002" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="9.5 0.0 0.11700000000000002" type="box" size="0.5 5.0 0.11700000000000002" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
23
resources/terrains/obstacle/obstacle_9.xml
Normal file
23
resources/terrains/obstacle/obstacle_9.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<mujoco model="obstacle_9">
|
||||||
|
<!-- Terrain Type: obstacle, Level: 9, Obstacle height: 0.2570, length: 1.0000, gap: 1.0000 -->
|
||||||
|
<statistic center="0 0 0.1" extent="0.8" />
|
||||||
|
<visual>
|
||||||
|
<headlight diffuse="0.6 0.6 0.6" ambient="0.3 0.3 0.3" specular="0 0 0" />
|
||||||
|
<rgba haze="0.15 0.25 0.35 1" />
|
||||||
|
<global azimuth="-130" elevation="-20" />
|
||||||
|
</visual>
|
||||||
|
<asset>
|
||||||
|
<texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072" />
|
||||||
|
<texture type="2d" name="groundplane" builtin="checker" mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3" markrgb="0.8 0.8 0.8" width="300" height="300" />
|
||||||
|
<material name="groundplane" texture="groundplane" texuniform="true" texrepeat="5 5" reflectance="0.0" />
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<light pos="0 0 1.5" dir="0 0 -1" directional="true" />
|
||||||
|
<geom name="floor" size="0 0 0.05" type="plane" material="groundplane" />
|
||||||
|
<geom pos="1.5 0.0 0.1285" type="box" size="0.5 5.0 0.1285" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="3.5 0.0 0.1285" type="box" size="0.5 5.0 0.1285" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="5.5 0.0 0.1285" type="box" size="0.5 5.0 0.1285" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="7.5 0.0 0.1285" type="box" size="0.5 5.0 0.1285" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
<geom pos="9.5 0.0 0.1285" type="box" size="0.5 5.0 0.1285" quat="1.0 0.0 0.0 0.0" />
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
@@ -15,6 +15,7 @@ task_register.register('go2.slope', BasePipeline, MujocoConfig, Go2SlopeGaugeCon
|
|||||||
task_register.register('go2.wave', BasePipeline, MujocoConfig, Go2WaveGaugeConfig, Go2TerrainConfig)
|
task_register.register('go2.wave', BasePipeline, MujocoConfig, Go2WaveGaugeConfig, Go2TerrainConfig)
|
||||||
task_register.register('go2.stairs_up', BasePipeline, MujocoConfig, Go2StairsUpGaugeConfig, Go2TerrainConfig)
|
task_register.register('go2.stairs_up', BasePipeline, MujocoConfig, Go2StairsUpGaugeConfig, Go2TerrainConfig)
|
||||||
task_register.register('go2.stairs_down', BasePipeline, MujocoConfig, Go2StairsDownGaugeConfig, Go2TerrainConfig)
|
task_register.register('go2.stairs_down', BasePipeline, MujocoConfig, Go2StairsDownGaugeConfig, Go2TerrainConfig)
|
||||||
|
task_register.register('go2.obstacle', BasePipeline, MujocoConfig, Go2ObstacleGaugeConfig, Go2TerrainConfig)
|
||||||
|
|
||||||
# Go2 MoE
|
# Go2 MoE
|
||||||
task_register.register('go2_moe.flat', BasePipeline, MujocoConfig, Go2FlatGaugeConfig, Go2MoEConfig)
|
task_register.register('go2_moe.flat', BasePipeline, MujocoConfig, Go2FlatGaugeConfig, Go2MoEConfig)
|
||||||
@@ -22,3 +23,4 @@ task_register.register('go2_moe.slope', BasePipeline, MujocoConfig, Go2SlopeGaug
|
|||||||
task_register.register('go2_moe.wave', BasePipeline, MujocoConfig, Go2WaveGaugeConfig, Go2MoETerrainConfig)
|
task_register.register('go2_moe.wave', BasePipeline, MujocoConfig, Go2WaveGaugeConfig, Go2MoETerrainConfig)
|
||||||
task_register.register('go2_moe.stairs_up', BasePipeline, MujocoConfig, Go2StairsUpGaugeConfig, Go2MoETerrainConfig)
|
task_register.register('go2_moe.stairs_up', BasePipeline, MujocoConfig, Go2StairsUpGaugeConfig, Go2MoETerrainConfig)
|
||||||
task_register.register('go2_moe.stairs_down', BasePipeline, MujocoConfig, Go2StairsDownGaugeConfig, Go2MoETerrainConfig)
|
task_register.register('go2_moe.stairs_down', BasePipeline, MujocoConfig, Go2StairsDownGaugeConfig, Go2MoETerrainConfig)
|
||||||
|
task_register.register('go2_moe.obstacle', BasePipeline, MujocoConfig, Go2ObstacleGaugeConfig, Go2MoETerrainConfig)
|
||||||
|
|||||||
@@ -11,3 +11,4 @@ from .go2_slope_task import Go2SlopeGaugeConfig
|
|||||||
from .go2_wave_task import Go2WaveGaugeConfig
|
from .go2_wave_task import Go2WaveGaugeConfig
|
||||||
from .go2_stairs_up_task import Go2StairsUpGaugeConfig
|
from .go2_stairs_up_task import Go2StairsUpGaugeConfig
|
||||||
from .go2_stairs_down_task import Go2StairsDownGaugeConfig
|
from .go2_stairs_down_task import Go2StairsDownGaugeConfig
|
||||||
|
from .go2_obstacle_task import Go2ObstacleGaugeConfig
|
||||||
|
|||||||
19
robogauge/tasks/custom/go2/go2_obstacle_task.py
Normal file
19
robogauge/tasks/custom/go2/go2_obstacle_task.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
@File : go2_obstacle_task.py
|
||||||
|
@Time : 2025/12/27 14:32:22
|
||||||
|
@Author : wty-yy
|
||||||
|
@Version : 1.0
|
||||||
|
@Blog : https://wty-yy.github.io/
|
||||||
|
@Desc : Go2 Obstacle Task Configuration
|
||||||
|
'''
|
||||||
|
from robogauge.tasks.robots import Go2Config, Go2MoEConfig
|
||||||
|
from robogauge.tasks.gauge import ObstacleGaugeConfig
|
||||||
|
from robogauge.tasks.simulator.mujoco_config import MujocoConfig
|
||||||
|
|
||||||
|
class Go2ObstacleGaugeConfig(ObstacleGaugeConfig):
|
||||||
|
class metrics(ObstacleGaugeConfig.metrics):
|
||||||
|
class dof_limits(ObstacleGaugeConfig.metrics.dof_limits):
|
||||||
|
enabled = True
|
||||||
|
soft_dof_limit_ratio = 0.7
|
||||||
|
dof_names = ['hip', 'thigh'] # List of DOF names to monitor, None for all
|
||||||
@@ -5,3 +5,4 @@ from .gauge_configs.slope_gauge_config import SlopeGaugeConfig
|
|||||||
from .gauge_configs.wave_gauge_config import WaveGaugeConfig
|
from .gauge_configs.wave_gauge_config import WaveGaugeConfig
|
||||||
from .gauge_configs.stairs_up_gauge_config import StairsUpGaugeConfig
|
from .gauge_configs.stairs_up_gauge_config import StairsUpGaugeConfig
|
||||||
from .gauge_configs.stairs_down_gauge_config import StairsDownGaugeConfig
|
from .gauge_configs.stairs_down_gauge_config import StairsDownGaugeConfig
|
||||||
|
from .gauge_configs.obstacle_gauge_config import ObstacleGaugeConfig
|
||||||
|
|||||||
32
robogauge/tasks/gauge/gauge_configs/obstacle_gauge_config.py
Normal file
32
robogauge/tasks/gauge/gauge_configs/obstacle_gauge_config.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
@File : obstacle_gauge_config.py
|
||||||
|
@Time : 2025/12/27 14:33:14
|
||||||
|
@Author : wty-yy
|
||||||
|
@Version : 1.0
|
||||||
|
@Blog : https://wty-yy.github.io/
|
||||||
|
@Desc : Obstacle Gauge Configuration
|
||||||
|
'''
|
||||||
|
from robogauge.tasks.gauge.base_gauge_config import BaseGaugeConfig
|
||||||
|
|
||||||
|
class ObstacleGaugeConfig(BaseGaugeConfig):
|
||||||
|
gauge_class = 'BaseGauge'
|
||||||
|
|
||||||
|
class assets(BaseGaugeConfig.assets):
|
||||||
|
terrain_name = "obstacle"
|
||||||
|
terrain_level = 10 # 1-10
|
||||||
|
terrain_xmls = [
|
||||||
|
'{ROBOGAUGE_ROOT_DIR}/resources/terrains/obstacle/obstacle_10.xml',
|
||||||
|
'{ROBOGAUGE_ROOT_DIR}/resources/terrains/wall/10x10_wall.xml',
|
||||||
|
]
|
||||||
|
terrain_spawn_pos = [0.5, 2.0, 0.0] # x y z [m], robot freejoint spawn position on the terrain
|
||||||
|
|
||||||
|
class goals(BaseGaugeConfig.goals):
|
||||||
|
class target_pos_velocity: # goal to reach a target position by velocity command
|
||||||
|
enabled = True
|
||||||
|
target_pos = [6.5, -2.0, 0.3] # x y z [m], target position in the environment, used for target position goal
|
||||||
|
lin_vel_x = 0.8 # +/- m/s
|
||||||
|
lin_vel_y = 1.0 # +/- m/s
|
||||||
|
ang_vel_yaw = 1.5 # +/- rad/s
|
||||||
|
max_cmd_duration = 30.0 # [s] maximum duration to reach the target position
|
||||||
|
reach_threshold = 0.1
|
||||||
@@ -87,6 +87,9 @@ class TerrainSearchLevelsConfig(Config):
|
|||||||
[1.1, 3.0, 7],
|
[1.1, 3.0, 7],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
class obstacle:
|
||||||
|
levels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||||
|
|
||||||
class TerrainEvalLevelsConfig(Config):
|
class TerrainEvalLevelsConfig(Config):
|
||||||
class slope:
|
class slope:
|
||||||
levels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
levels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class WaveGaugeConfig(BaseGaugeConfig):
|
|||||||
]
|
]
|
||||||
terrain_spawn_pos = [1.5, 1.25, 0.0] # x y z [m], robot freejoint spawn position on the terrain
|
terrain_spawn_pos = [1.5, 1.25, 0.0] # x y z [m], robot freejoint spawn position on the terrain
|
||||||
|
|
||||||
class goals:
|
class goals(BaseGaugeConfig.goals):
|
||||||
class target_pos_velocity: # goal to reach a target position by velocity command
|
class target_pos_velocity: # goal to reach a target position by velocity command
|
||||||
enabled = True
|
enabled = True
|
||||||
target_pos = [6.5, -2.65, 0.8] # x y z [m], target position in the environment, used for target position goal
|
target_pos = [6.5, -2.65, 0.8] # x y z [m], target position in the environment, used for target position goal
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import yaml
|
|||||||
from robogauge.tasks.pipeline.multi_pipeline import MultiPipeline
|
from robogauge.tasks.pipeline.multi_pipeline import MultiPipeline
|
||||||
from robogauge.utils.logger import Logger
|
from robogauge.utils.logger import Logger
|
||||||
from robogauge.utils.progress_monitor import report_progress, ProgressTypes, ProgressData
|
from robogauge.utils.progress_monitor import report_progress, ProgressTypes, ProgressData
|
||||||
|
from robogauge.utils.file_utils import compress_directory
|
||||||
|
|
||||||
level_logger = Logger() # LevelPipeline logger
|
level_logger = Logger() # LevelPipeline logger
|
||||||
|
|
||||||
@@ -21,7 +22,11 @@ class LevelPipeline:
|
|||||||
self.seeds = args.seeds
|
self.seeds = args.seeds
|
||||||
self.console_output = console_output
|
self.console_output = console_output
|
||||||
self.progress_data = progress_data
|
self.progress_data = progress_data
|
||||||
level_logger.create(args.experiment_name+'_level', args.run_name, console_output=console_output)
|
parent_log_dir = getattr(args, 'parent_log_dir', None)
|
||||||
|
level_logger.create(args.experiment_name+'_level', args.run_name, console_output=console_output, parent_log_dir=parent_log_dir)
|
||||||
|
self.args.parent_log_dir = str(level_logger.log_dir / "subtasks")
|
||||||
|
self.compress_logs = args.compress_logs
|
||||||
|
args.compress_logs = False # Disable child log compression
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
level_logger.info(f"🚀 Starting Level Searcher for '{self.args.experiment_name}'.")
|
level_logger.info(f"🚀 Starting Level Searcher for '{self.args.experiment_name}'.")
|
||||||
@@ -53,6 +58,9 @@ class LevelPipeline:
|
|||||||
level_logger.info(f"❌ No valid level found [1-10].")
|
level_logger.info(f"❌ No valid level found [1-10].")
|
||||||
with open(level_logger.log_dir / "level_search_results.yaml", 'w') as f:
|
with open(level_logger.log_dir / "level_search_results.yaml", 'w') as f:
|
||||||
yaml.dump(level_results, f, allow_unicode=True, sort_keys=False)
|
yaml.dump(level_results, f, allow_unicode=True, sort_keys=False)
|
||||||
|
level_logger.logger.info(f"📂 Level search results saved to: {level_logger.log_dir / 'level_search_results.yaml'}")
|
||||||
|
if self.compress_logs:
|
||||||
|
compress_directory(level_logger.log_dir / "subtasks", delete_original=True, logger=level_logger)
|
||||||
return level, level_results
|
return level, level_results
|
||||||
|
|
||||||
def test_level(self, level: int):
|
def test_level(self, level: int):
|
||||||
@@ -63,7 +71,7 @@ class LevelPipeline:
|
|||||||
success_mean = float(aggregated_results['summary']['success']['mean'].split(' ')[0])
|
success_mean = float(aggregated_results['summary']['success']['mean'].split(' ')[0])
|
||||||
all_success = success_mean >= 0.8
|
all_success = success_mean >= 0.8
|
||||||
if all_success:
|
if all_success:
|
||||||
level_logger.info(f"✅ Level {level} passed all tests.")
|
level_logger.info(f"✅ Level {level} passed all tests, success mean: {success_mean}.")
|
||||||
else:
|
else:
|
||||||
level_logger.info(f"❌ Level {level} failed some tests.")
|
level_logger.info(f"❌ Level {level} failed some tests, success mean: {success_mean}.")
|
||||||
return all_success, aggregated_results
|
return all_success, aggregated_results
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ from robogauge.utils.task_register import task_register
|
|||||||
from robogauge.utils.logger import Logger
|
from robogauge.utils.logger import Logger
|
||||||
from robogauge.utils.process_utils import NoDaemonPool
|
from robogauge.utils.process_utils import NoDaemonPool
|
||||||
from robogauge.utils.progress_monitor import report_progress, ProgressTypes, ProgressData
|
from robogauge.utils.progress_monitor import report_progress, ProgressTypes, ProgressData
|
||||||
|
from robogauge.utils.file_utils import compress_directory
|
||||||
|
|
||||||
multi_logger = Logger() # MultiPipeline logger
|
multi_logger = Logger() # MultiPipeline logger
|
||||||
|
|
||||||
@@ -38,7 +39,8 @@ def run_single_process(args, data):
|
|||||||
logger.create(
|
logger.create(
|
||||||
experiment_name=local_args.experiment_name,
|
experiment_name=local_args.experiment_name,
|
||||||
run_name=run_name,
|
run_name=run_name,
|
||||||
console_output=False
|
console_output=False,
|
||||||
|
parent_log_dir=args.parent_log_dir
|
||||||
)
|
)
|
||||||
pipeline = task_register.make_pipeline(args=local_args, create_logger=False)
|
pipeline = task_register.make_pipeline(args=local_args, create_logger=False)
|
||||||
results, warning, error = pipeline.run()
|
results, warning, error = pipeline.run()
|
||||||
@@ -73,7 +75,10 @@ class MultiPipeline:
|
|||||||
self.progress_data = progress_data
|
self.progress_data = progress_data
|
||||||
self.num_processes = args.num_processes
|
self.num_processes = args.num_processes
|
||||||
self.static_info = {}
|
self.static_info = {}
|
||||||
multi_logger.create(args.experiment_name+'_multi', args.run_name+'_multi', console_output=console_output)
|
parent_log_dir = getattr(args, 'parent_log_dir', None)
|
||||||
|
multi_logger.create(args.experiment_name+'_multi', args.run_name+'_multi', console_output=console_output, parent_log_dir=parent_log_dir)
|
||||||
|
self.args.parent_log_dir = str(multi_logger.log_dir / "subtasks")
|
||||||
|
self.compress_logs = args.compress_logs
|
||||||
|
|
||||||
def add_static_info(self, key: str, value):
|
def add_static_info(self, key: str, value):
|
||||||
if key not in self.static_info:
|
if key not in self.static_info:
|
||||||
@@ -153,6 +158,8 @@ class MultiPipeline:
|
|||||||
multi_logger.info("✅ Aggregated execution finished.")
|
multi_logger.info("✅ Aggregated execution finished.")
|
||||||
multi_logger.info(f"📁 Aggregated results saved to: {save_path}")
|
multi_logger.info(f"📁 Aggregated results saved to: {save_path}")
|
||||||
|
|
||||||
|
if self.compress_logs:
|
||||||
|
compress_directory(multi_logger.log_dir / "subtasks", delete_original=True, logger=multi_logger)
|
||||||
# multi_logger.info(
|
# multi_logger.info(
|
||||||
# f"""\n{'='*20} Multi-Run Summary {'='*20}\n"""
|
# f"""\n{'='*20} Multi-Run Summary {'='*20}\n"""
|
||||||
# f"""{yaml.dump(summary, allow_unicode=True)}"""
|
# f"""{yaml.dump(summary, allow_unicode=True)}"""
|
||||||
|
|||||||
@@ -7,6 +7,12 @@
|
|||||||
@Blog : https://wty-yy.github.io/
|
@Blog : https://wty-yy.github.io/
|
||||||
@Desc : Stress Pipeline for Robogauge
|
@Desc : Stress Pipeline for Robogauge
|
||||||
'''
|
'''
|
||||||
|
# MuJoCo/XLA warnings suppression
|
||||||
|
import os
|
||||||
|
os.environ['ABSL_LOG_LEVEL'] = 'error'
|
||||||
|
import absl.logging
|
||||||
|
absl.logging.set_verbosity(absl.logging.ERROR)
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
import traceback
|
import traceback
|
||||||
import functools
|
import functools
|
||||||
@@ -22,9 +28,15 @@ from robogauge.utils.process_utils import NoDaemonPool
|
|||||||
from robogauge.utils.progress_monitor import report_progress, ProgressTypes, start_progress_monitor_thread, ProgressData
|
from robogauge.utils.progress_monitor import report_progress, ProgressTypes, start_progress_monitor_thread, ProgressData
|
||||||
from robogauge.tasks.pipeline import MultiPipeline, LevelPipeline
|
from robogauge.tasks.pipeline import MultiPipeline, LevelPipeline
|
||||||
from robogauge.tasks.gauge.gauge_configs.terrain_levels_config import TerrainSearchLevelsConfig
|
from robogauge.tasks.gauge.gauge_configs.terrain_levels_config import TerrainSearchLevelsConfig
|
||||||
|
from robogauge.utils.file_utils import compress_directory
|
||||||
|
|
||||||
stress_logger = Logger() # StressPipeline logger
|
stress_logger = Logger() # StressPipeline logger
|
||||||
|
|
||||||
|
GOALS = {
|
||||||
|
'level_pipeline': ['target_pos_velocity'],
|
||||||
|
'multi_pipeline': ['max_velocity', 'diagonal_velocity']
|
||||||
|
}
|
||||||
|
|
||||||
def run_pipeline(args, progress_queue, data):
|
def run_pipeline(args, progress_queue, data):
|
||||||
args = deepcopy(args)
|
args = deepcopy(args)
|
||||||
task_id = data['task_id']
|
task_id = data['task_id']
|
||||||
@@ -44,6 +56,7 @@ def run_pipeline(args, progress_queue, data):
|
|||||||
args.base_masses = [data['base_mass']]
|
args.base_masses = [data['base_mass']]
|
||||||
args.task_name = f"{data['task_robot_model']}.{data['terrain_name']}"
|
args.task_name = f"{data['task_robot_model']}.{data['terrain_name']}"
|
||||||
args.experiment_name = f"{args.experiment_name}_{data['terrain_name']}_M{data['base_mass']}_F{data['friction']}"
|
args.experiment_name = f"{args.experiment_name}_{data['terrain_name']}_M{data['base_mass']}_F{data['friction']}"
|
||||||
|
args.goals = GOALS['level_pipeline']
|
||||||
|
|
||||||
level, level_results = LevelPipeline(args, console_output=False, progress_data=progress_data).run()
|
level, level_results = LevelPipeline(args, console_output=False, progress_data=progress_data).run()
|
||||||
if level == 0: # no valid level found
|
if level == 0: # no valid level found
|
||||||
@@ -63,6 +76,7 @@ def run_pipeline(args, progress_queue, data):
|
|||||||
args.experiment_name = f"{args.experiment_name}_{data['terrain_name']}"
|
args.experiment_name = f"{args.experiment_name}_{data['terrain_name']}"
|
||||||
|
|
||||||
args.level = level
|
args.level = level
|
||||||
|
args.goals = GOALS['multi_pipeline']
|
||||||
results = {
|
results = {
|
||||||
'success': True,
|
'success': True,
|
||||||
'results': MultiPipeline(args, console_output=False, progress_data=progress_data).run(),
|
'results': MultiPipeline(args, console_output=False, progress_data=progress_data).run(),
|
||||||
@@ -81,6 +95,9 @@ class StressPipeline:
|
|||||||
args.experiment_name = self.task_robot_model + '_stress' + ('' if args.cli_experiment_name is None else '_' + args.cli_experiment_name)
|
args.experiment_name = self.task_robot_model + '_stress' + ('' if args.cli_experiment_name is None else '_' + args.cli_experiment_name)
|
||||||
self.static_info = {}
|
self.static_info = {}
|
||||||
stress_logger.create(args.experiment_name, args.run_name)
|
stress_logger.create(args.experiment_name, args.run_name)
|
||||||
|
self.args.parent_log_dir = str(stress_logger.log_dir / "subtasks")
|
||||||
|
self.compress_logs = args.compress_logs
|
||||||
|
args.compress_logs = False # Disable child log compression
|
||||||
|
|
||||||
def add_static_info(self, key: str, value):
|
def add_static_info(self, key: str, value):
|
||||||
if key not in self.static_info:
|
if key not in self.static_info:
|
||||||
@@ -183,7 +200,9 @@ class StressPipeline:
|
|||||||
|
|
||||||
for metric, means in result['results']['summary'].items():
|
for metric, means in result['results']['summary'].items():
|
||||||
for mean_name, mean_value in means.items():
|
for mean_name, mean_value in means.items():
|
||||||
value_collections[metric][mean_name].append(float(mean_value.split(' ')[0]))
|
value = float(mean_value.split(' ')[0])
|
||||||
|
value += (terrain_level - 1) * 0.1 if terrain_level is not None else 0.0
|
||||||
|
value_collections[metric][mean_name].append(value)
|
||||||
|
|
||||||
for metric, means in value_collections.items():
|
for metric, means in value_collections.items():
|
||||||
summary['summary'][metric] = {}
|
summary['summary'][metric] = {}
|
||||||
@@ -196,4 +215,7 @@ class StressPipeline:
|
|||||||
yaml.dump(summary, file, allow_unicode=True, sort_keys=False)
|
yaml.dump(summary, file, allow_unicode=True, sort_keys=False)
|
||||||
stress_logger.info(f"✅ Stress benchmark aggregated execution finished.")
|
stress_logger.info(f"✅ Stress benchmark aggregated execution finished.")
|
||||||
stress_logger.info(f"📁 Stress benchmark results saved to: {save_path}")
|
stress_logger.info(f"📁 Stress benchmark results saved to: {save_path}")
|
||||||
|
|
||||||
|
if self.compress_logs:
|
||||||
|
compress_directory(stress_logger.log_dir / "subtasks", delete_original=True, logger=stress_logger)
|
||||||
return summary
|
return summary
|
||||||
|
|||||||
57
robogauge/utils/file_utils.py
Normal file
57
robogauge/utils/file_utils.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
@File : file_utils.py
|
||||||
|
@Time : 2025/12/27 17:14:29
|
||||||
|
@Author : wty-yy
|
||||||
|
@Version : 1.0
|
||||||
|
@Blog : https://wty-yy.github.io/
|
||||||
|
@Desc : Common File Utilities
|
||||||
|
'''
|
||||||
|
import tarfile
|
||||||
|
import shutil
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import logging
|
||||||
|
|
||||||
|
def log_msg(logger: logging.Logger, msg: str, level: str):
|
||||||
|
if logger:
|
||||||
|
getattr(logger, level)(msg)
|
||||||
|
else:
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
def compress_directory(source_dir, output_filename=None, delete_original=True, logger: logging.Logger=None):
|
||||||
|
"""
|
||||||
|
Compress a directory into a .tar.xz file using LZMA compression.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
source_dir (str | Path): Path to the directory to compress.
|
||||||
|
output_filename (str | Path, optional): Output path. Defaults to source_dir + ".tar.xz".
|
||||||
|
delete_original (bool): Whether to delete the source directory after successful compression.
|
||||||
|
"""
|
||||||
|
source_dir = Path(source_dir)
|
||||||
|
if not source_dir.exists():
|
||||||
|
log_msg(logger, f"⚠️ Source directory for compression not found: {source_dir}", "warning")
|
||||||
|
return
|
||||||
|
|
||||||
|
if output_filename is None:
|
||||||
|
output_filename = source_dir.with_suffix('.tar.xz')
|
||||||
|
else:
|
||||||
|
output_filename = Path(output_filename)
|
||||||
|
|
||||||
|
log_msg(logger, f"📦 Compressing logs: {source_dir.name} -> {output_filename.name} ...", "info")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with tarfile.open(output_filename, "w:xz") as tar:
|
||||||
|
tar.add(source_dir, arcname=source_dir.name)
|
||||||
|
|
||||||
|
log_msg(logger, f"✅ Compression finished: {output_filename}", "info")
|
||||||
|
|
||||||
|
if delete_original:
|
||||||
|
shutil.rmtree(source_dir)
|
||||||
|
log_msg(logger, f"🗑️ Deleted original directory: {source_dir}", "info")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log_msg(logger, f"❌ Failed to compress directory {source_dir}: {e}", "error")
|
||||||
|
# If compression failed, ensure we don't leave a half-baked file
|
||||||
|
if output_filename.exists():
|
||||||
|
os.remove(output_filename)
|
||||||
@@ -76,6 +76,7 @@ def parse_args():
|
|||||||
{"name": "--base-mass", "type": float, "default": 0.0, "help": "Set the base mass of the robot."},
|
{"name": "--base-mass", "type": float, "default": 0.0, "help": "Set the base mass of the robot."},
|
||||||
{"name": "--friction", "type": float, "default": 1.0, "help": "Set the ground friction coefficient."},
|
{"name": "--friction", "type": float, "default": 1.0, "help": "Set the ground friction coefficient."},
|
||||||
{"name": "--level", "type": int, "help": "Set the difficulty level of the environment, range 1-10 (flat is 0)."},
|
{"name": "--level", "type": int, "help": "Set the difficulty level of the environment, range 1-10 (flat is 0)."},
|
||||||
|
{"name": "--goals", "type": str, "nargs": "+", "help": "List of goal names to evaluate."},
|
||||||
|
|
||||||
# Multiprocessing parameters, with different seeds
|
# Multiprocessing parameters, with different seeds
|
||||||
{"name": "--multi", "action": "store_true", "default": False, "help": "Enable multiprocessing."},
|
{"name": "--multi", "action": "store_true", "default": False, "help": "Enable multiprocessing."},
|
||||||
@@ -91,6 +92,8 @@ def parse_args():
|
|||||||
{"name": "--stress-benchmark", "action": "store_true", "default": False, "help": "Use stress pipeline to benchmark model robustness."},
|
{"name": "--stress-benchmark", "action": "store_true", "default": False, "help": "Use stress pipeline to benchmark model robustness."},
|
||||||
{"name": "--stress-terrain-names", "type": str, "nargs": "+", "default": ["flat", "slope", "wave", "stairs_up", "stairs_down"], "help": "List of terrain names for stress benchmark."},
|
{"name": "--stress-terrain-names", "type": str, "nargs": "+", "default": ["flat", "slope", "wave", "stairs_up", "stairs_down"], "help": "List of terrain names for stress benchmark."},
|
||||||
{"name": "--stress-num-processes", "type": int, "default": 2, "help": "Number of parallel processes for stress benchmark."},
|
{"name": "--stress-num-processes", "type": int, "default": 2, "help": "Number of parallel processes for stress benchmark."},
|
||||||
|
|
||||||
|
{"name": "--compress-logs", "action": "store_true", "default": False, "help": "Compress and delete logs after run."},
|
||||||
]
|
]
|
||||||
for param in parameters:
|
for param in parameters:
|
||||||
parser.add_argument(param['name'], **{k: v for k, v in param.items() if k != 'name'})
|
parser.add_argument(param['name'], **{k: v for k, v in param.items() if k != 'name'})
|
||||||
|
|||||||
@@ -58,7 +58,8 @@ class Logger:
|
|||||||
experiment_name,
|
experiment_name,
|
||||||
run_name,
|
run_name,
|
||||||
console_output=True, color_output=True,
|
console_output=True, color_output=True,
|
||||||
log_level=logging.DEBUG, save_file_mode='a'
|
log_level=logging.DEBUG, save_file_mode='a',
|
||||||
|
parent_log_dir=None
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Create customed Logger
|
Create customed Logger
|
||||||
@@ -69,6 +70,7 @@ class Logger:
|
|||||||
color_output (bool, optional): Whether use color output. Defaults to True.
|
color_output (bool, optional): Whether use color output. Defaults to True.
|
||||||
log_level (int, optional): Defaults to logging.DEBUG.
|
log_level (int, optional): Defaults to logging.DEBUG.
|
||||||
save_file_mode (str, optional): The mode of saving to path_log_file
|
save_file_mode (str, optional): The mode of saving to path_log_file
|
||||||
|
parent_log_dir (Path | str, optional): If specified, log_dir will be created under this directory.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
logging.Logger: logger
|
logging.Logger: logger
|
||||||
@@ -102,7 +104,11 @@ class Logger:
|
|||||||
sh.setFormatter(console_formatter)
|
sh.setFormatter(console_formatter)
|
||||||
self.logger.addHandler(sh)
|
self.logger.addHandler(sh)
|
||||||
|
|
||||||
self.log_dir = Path(ROBOGAUGE_LOGS_DIR) / experiment_name / self.tag
|
if parent_log_dir:
|
||||||
|
baes_dir = Path(parent_log_dir)
|
||||||
|
else:
|
||||||
|
baes_dir = Path(ROBOGAUGE_LOGS_DIR)
|
||||||
|
self.log_dir = baes_dir / experiment_name / self.tag
|
||||||
self.log_dir.mkdir(parents=True, exist_ok=True)
|
self.log_dir.mkdir(parents=True, exist_ok=True)
|
||||||
path_log_file = self.log_dir / "stdout.log"
|
path_log_file = self.log_dir / "stdout.log"
|
||||||
if path_log_file:
|
if path_log_file:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
'''
|
'''
|
||||||
from robogauge import ROBOGAUGE_ROOT_DIR
|
from robogauge import ROBOGAUGE_ROOT_DIR
|
||||||
from robogauge.utils.logger import logger
|
from robogauge.utils.logger import logger
|
||||||
from robogauge.utils.helpers import parse_args, set_seed
|
from robogauge.utils.helpers import parse_args, set_seed, class_to_dict
|
||||||
from robogauge.tasks.gauge.gauge_configs.terrain_levels_config import TerrainSearchLevelsConfig
|
from robogauge.tasks.gauge.gauge_configs.terrain_levels_config import TerrainSearchLevelsConfig
|
||||||
|
|
||||||
class TaskRegister():
|
class TaskRegister():
|
||||||
@@ -73,14 +73,23 @@ class TaskRegister():
|
|||||||
if args.level is not None:
|
if args.level is not None:
|
||||||
gauger_cfg.assets.terrain_level = args.level
|
gauger_cfg.assets.terrain_level = args.level
|
||||||
levels_cfg = TerrainSearchLevelsConfig()
|
levels_cfg = TerrainSearchLevelsConfig()
|
||||||
cfg = getattr(levels_cfg, gauger_cfg.assets.terrain_name)
|
cfg = getattr(levels_cfg, gauger_cfg.assets.terrain_name, None)
|
||||||
assert cfg is not None, f"Level {args.level} configuration not found in TerrainLevelsConfig."
|
assert cfg is not None, f"Level {args.level} configuration not found in TerrainLevelsConfig."
|
||||||
assert args.level in cfg.levels, f"Level must be in {cfg.levels}."
|
assert args.level in cfg.levels, f"Level must be in {cfg.levels}."
|
||||||
|
if hasattr(cfg, 'targets'):
|
||||||
gauger_cfg.goals.target_pos_velocity.target_pos = cfg.targets[cfg.levels.index(args.level)]
|
gauger_cfg.goals.target_pos_velocity.target_pos = cfg.targets[cfg.levels.index(args.level)]
|
||||||
if hasattr(cfg, 'spawns'):
|
if hasattr(cfg, 'spawns'):
|
||||||
gauger_cfg.assets.terrain_spawn_pos = cfg.spawns[cfg.levels.index(args.level)]
|
gauger_cfg.assets.terrain_spawn_pos = cfg.spawns[cfg.levels.index(args.level)]
|
||||||
xml = gauger_cfg.assets.terrain_xmls[0]
|
xml = gauger_cfg.assets.terrain_xmls[0]
|
||||||
xml = xml.rsplit('/', 1)[0] + f"/{gauger_cfg.assets.terrain_name}_{args.level}.xml"
|
xml = xml.rsplit('/', 1)[0] + f"/{gauger_cfg.assets.terrain_name}_{args.level}.xml"
|
||||||
gauger_cfg.assets.terrain_xmls[0] = xml
|
gauger_cfg.assets.terrain_xmls[0] = xml
|
||||||
|
if args.goals is not None:
|
||||||
|
keys = class_to_dict(gauger_cfg.goals).keys()
|
||||||
|
enable_count = 0
|
||||||
|
for key in keys:
|
||||||
|
flag = key in args.goals
|
||||||
|
getattr(gauger_cfg.goals, key).enabled = flag
|
||||||
|
enable_count += int(flag)
|
||||||
|
assert enable_count > 0, f"At least one goal must be enabled from '{args.goals}', available goals are {list(keys)}."
|
||||||
|
|
||||||
task_register = TaskRegister()
|
task_register = TaskRegister()
|
||||||
|
|||||||
14
setup.py
14
setup.py
@@ -10,14 +10,12 @@ setup(
|
|||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
install_requires=[
|
install_requires=[
|
||||||
"numpy>=1.20.0",
|
"numpy>=1.20.0",
|
||||||
"mujoco>=3.0.0", # 必须依赖
|
"mujoco>=3.0.0",
|
||||||
"dm_control>=1.0.14", # 之前推荐用来组合地形的库
|
"dm_control>=1.0.14",
|
||||||
"scipy", # 计算信号处理、统计指标常用
|
"scipy",
|
||||||
"matplotlib", # 用于画出评估图表
|
"matplotlib",
|
||||||
"pandas", # 用于生成评估报告表格
|
"tqdm",
|
||||||
"tqdm", # 显示评估进度条
|
"imageio[ffmpeg]",
|
||||||
# "gymnasium", # 如果你的接口兼容 gym
|
|
||||||
# "torch", # 如果你需要加载 pytorch 模型
|
|
||||||
],
|
],
|
||||||
python_requires=">=3.8",
|
python_requires=">=3.8",
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user