From 11908747cefc1a6fbe0f47f3ee50b732c97f3304 Mon Sep 17 00:00:00 2001 From: wty-yy <993660140@qq.com> Date: Thu, 25 Dec 2025 00:02:43 +0800 Subject: [PATCH] v0.1.14; add wave terrain; finish LevelPipeline --- .vscode/launch.json | 22 ++++++- CMD.md | 14 ++++- UPDATE.md | 6 +- resources/terrains/wave/wave.png | Bin 0 -> 27036 bytes resources/terrains/wave/wave_1.xml | 20 ++++++ resources/terrains/wave/wave_10.xml | 20 ++++++ resources/terrains/wave/wave_2.xml | 20 ++++++ resources/terrains/wave/wave_3.xml | 20 ++++++ resources/terrains/wave/wave_4.xml | 20 ++++++ resources/terrains/wave/wave_5.xml | 20 ++++++ resources/terrains/wave/wave_6.xml | 20 ++++++ resources/terrains/wave/wave_7.xml | 20 ++++++ resources/terrains/wave/wave_8.xml | 20 ++++++ resources/terrains/wave/wave_9.xml | 20 ++++++ .../gauge_configs/terrain_levels_config.py | 13 +++- .../gauge/gauge_configs/wave_gauge_config.py | 8 +-- robogauge/tasks/pipeline/base_pipeline.py | 2 +- robogauge/tasks/pipeline/level_pipeline.py | 30 +++++---- robogauge/tasks/pipeline/multi_pipeline.py | 58 +++++++----------- 19 files changed, 296 insertions(+), 57 deletions(-) create mode 100644 resources/terrains/wave/wave.png create mode 100644 resources/terrains/wave/wave_1.xml create mode 100644 resources/terrains/wave/wave_10.xml create mode 100644 resources/terrains/wave/wave_2.xml create mode 100644 resources/terrains/wave/wave_3.xml create mode 100644 resources/terrains/wave/wave_4.xml create mode 100644 resources/terrains/wave/wave_5.xml create mode 100644 resources/terrains/wave/wave_6.xml create mode 100644 resources/terrains/wave/wave_7.xml create mode 100644 resources/terrains/wave/wave_8.xml create mode 100644 resources/terrains/wave/wave_9.xml diff --git a/.vscode/launch.json b/.vscode/launch.json index abad633..a47b4fc 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,16 +5,34 @@ "version": "0.2.0", "configurations": [ { - "name": "Python 调试程序: run.py", + "name": "go2 moe flat single pipeline", "type": "debugpy", "request": "launch", "program": "${workspaceFolder}/robogauge/scripts/run.py", "args": [ "--task", "go2_moe_flat", "--experiment-name", "debug", + "--seed", "0", + "--friction", "1.6", "--headless" ], "console": "integratedTerminal" - } + }, + { + "name": "go2 moe slope level pipeline", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/robogauge/scripts/run.py", + "args": [ + "--task", "go2_moe_slope", + "--experiment-name", "debug", + "--seed", "0", + "--search-max-level", + "--seeds", "0", "1", "2", + "--frictions", "1", + "--headless" + ], + "console": "integratedTerminal" + }, ] } diff --git a/CMD.md b/CMD.md index e52fa8e..977ece8 100644 --- a/CMD.md +++ b/CMD.md @@ -1,4 +1,4 @@ -# Single Run +# Single Pipeline ```bash python robogauge/scripts/run.py \ --task go2_moe_flat \ @@ -6,7 +6,7 @@ python robogauge/scripts/run.py \ --headless ``` -# Multi Run +# Multi Pipeline ```bash python robogauge/scripts/run.py \ --task go2_moe_flat \ @@ -23,6 +23,16 @@ python robogauge/scripts/run.py \ --headless ``` +# Level Pipeline +```bash +python robogauge/scripts/run.py \ + --task go2_slope \ + --experiment-name debug \ + --seed 0 \ + --headless \ + --search-max-level --seeds 0 1 2 --frictions 1 +``` + # Radar/Bar Plot 将Multi Run结果绘制在雷达图中 ```bash diff --git a/UPDATE.md b/UPDATE.md index 58763d1..25cd7e0 100644 --- a/UPDATE.md +++ b/UPDATE.md @@ -1,5 +1,9 @@ # UPDATE -TODO: 处理LevelPipeline返回的result信息 +## 20251224 +### v0.1.14 +1. 处理LevelPipeline返回的result信息, 保存最高等级可通过地形返回的aggregated_results和level等级 +2. 完成wave地形的LevelPipeline支持 +3. 各种Pipeline的run直接返回dict信息, 不再是路径 ## 20251222 ### v0.1.13 1. 即使模型崩溃也要继续测完后续的goals, 但是跳过当前的sub goals diff --git a/resources/terrains/wave/wave.png b/resources/terrains/wave/wave.png new file mode 100644 index 0000000000000000000000000000000000000000..80d6ddba00b63e4a3fb9ec1d8e1464a23e2ce26a GIT binary patch literal 27036 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 WB_nBi2m0Bib!#`RiC?wr)c*m+gp&aP literal 0 HcmV?d00001 diff --git a/resources/terrains/wave/wave_1.xml b/resources/terrains/wave/wave_1.xml new file mode 100644 index 0000000..6d5a73f --- /dev/null +++ b/resources/terrains/wave/wave_1.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/terrains/wave/wave_10.xml b/resources/terrains/wave/wave_10.xml new file mode 100644 index 0000000..b4b3861 --- /dev/null +++ b/resources/terrains/wave/wave_10.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/terrains/wave/wave_2.xml b/resources/terrains/wave/wave_2.xml new file mode 100644 index 0000000..e557a54 --- /dev/null +++ b/resources/terrains/wave/wave_2.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/terrains/wave/wave_3.xml b/resources/terrains/wave/wave_3.xml new file mode 100644 index 0000000..5fc39c0 --- /dev/null +++ b/resources/terrains/wave/wave_3.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/terrains/wave/wave_4.xml b/resources/terrains/wave/wave_4.xml new file mode 100644 index 0000000..e622e68 --- /dev/null +++ b/resources/terrains/wave/wave_4.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/terrains/wave/wave_5.xml b/resources/terrains/wave/wave_5.xml new file mode 100644 index 0000000..675b2fd --- /dev/null +++ b/resources/terrains/wave/wave_5.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/terrains/wave/wave_6.xml b/resources/terrains/wave/wave_6.xml new file mode 100644 index 0000000..0ea2785 --- /dev/null +++ b/resources/terrains/wave/wave_6.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/terrains/wave/wave_7.xml b/resources/terrains/wave/wave_7.xml new file mode 100644 index 0000000..48f5dce --- /dev/null +++ b/resources/terrains/wave/wave_7.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/terrains/wave/wave_8.xml b/resources/terrains/wave/wave_8.xml new file mode 100644 index 0000000..b62af90 --- /dev/null +++ b/resources/terrains/wave/wave_8.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/terrains/wave/wave_9.xml b/resources/terrains/wave/wave_9.xml new file mode 100644 index 0000000..4822108 --- /dev/null +++ b/resources/terrains/wave/wave_9.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/robogauge/tasks/gauge/gauge_configs/terrain_levels_config.py b/robogauge/tasks/gauge/gauge_configs/terrain_levels_config.py index 10f7418..49f6676 100644 --- a/robogauge/tasks/gauge/gauge_configs/terrain_levels_config.py +++ b/robogauge/tasks/gauge/gauge_configs/terrain_levels_config.py @@ -22,5 +22,16 @@ class TerrainLevelsConfig(Config): class wave: levels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - targets = [] + targets = [ + [6.5, 0.0, 0.08], + [6.5, 0.0, 0.16], + [6.5, 0.0, 0.24], + [6.5, 0.0, 0.32], + [6.5, 0.0, 0.40], + [6.5, 0.0, 0.48], + [6.5, 0.0, 0.56], + [6.5, 0.0, 0.64], + [6.5, 0.0, 0.72], + [6.5, 0.0, 0.80], + ] diff --git a/robogauge/tasks/gauge/gauge_configs/wave_gauge_config.py b/robogauge/tasks/gauge/gauge_configs/wave_gauge_config.py index 461c474..3f84555 100644 --- a/robogauge/tasks/gauge/gauge_configs/wave_gauge_config.py +++ b/robogauge/tasks/gauge/gauge_configs/wave_gauge_config.py @@ -14,14 +14,14 @@ class WaveGaugeConfig(BaseGaugeConfig): class assets(BaseGaugeConfig.assets): terrain_name = "wave" - terrain_level = 1 # 1-10 - terrain_xml = '{ROBOGAUGE_ROOT_DIR}/resources/terrains/wave/wave_1.xml' - terrain_spawn_pos = [1.5, 0, 1] # x y z [m], robot freejoint spawn position on the terrain + terrain_level = 10 # 1-10 + terrain_xml = '{ROBOGAUGE_ROOT_DIR}/resources/terrains/wave/wave_10.xml' + terrain_spawn_pos = [1.5, 1.25, 1.0] # x y z [m], robot freejoint spawn position on the terrain class goals: class target_pos_velocity: # goal to reach a target position by velocity command enabled = True - target_pos = [4, 0, 1.0] # x y z [m], target position in the environment, used for target position goal + target_pos = [6.5, 0.0, 0.8] # x y z [m], target position in the environment, used for target position goal lin_vel_x = 1.0 # +/- m/s lin_vel_y = 1.0 # +/- m/s ang_vel_yaw = 1.5 # +/- rad/s diff --git a/robogauge/tasks/pipeline/base_pipeline.py b/robogauge/tasks/pipeline/base_pipeline.py index ad6fb7d..bb9029b 100644 --- a/robogauge/tasks/pipeline/base_pipeline.py +++ b/robogauge/tasks/pipeline/base_pipeline.py @@ -117,7 +117,7 @@ class BasePipeline: logger.info("✅ Pipeline execution finished.") logger.info(f"📁 Logging saved at: {logger.log_dir}") - return logger.log_dir, error + return self.gauge.results, error def reset_sim_and_robot(self, sim_data: SimData): self.sim.reset() diff --git a/robogauge/tasks/pipeline/level_pipeline.py b/robogauge/tasks/pipeline/level_pipeline.py index c9c1b66..cb56126 100644 --- a/robogauge/tasks/pipeline/level_pipeline.py +++ b/robogauge/tasks/pipeline/level_pipeline.py @@ -16,7 +16,6 @@ class LevelPipeline: def __init__(self, args): self.args = args self.seeds = args.seeds - self.model_path = None logger.create(args.experiment_name+'_level', args.run_name) def run(self): @@ -25,30 +24,39 @@ class LevelPipeline: # binary search levels l, r = 0, 10 + all_level_results = {} while l < r: level = (l + r + 1) // 2 - if self.test_level(level): + all_success, results = self.test_level(level) + all_level_results[level] = results + if all_success: l = level else: r = level - 1 - if l >= 1: - logger.info(f"🏆 Found maximum level: {l}") + level = l + level_results = all_level_results.get(l, { + 'model_path': results['model_path'], + 'terrain_name': results['terrain_name'], + 'terrain_level': 0, + }) + if level >= 1: + logger.info(f"🏆 Found maximum level: {level}") else: logger.info(f"❌ No valid level found [1-10].") + with open(logger.log_dir / "level_search_results.yaml", 'w') as f: + yaml.dump(level_results, f, allow_unicode=True, sort_keys=False) + return level, level_results + def test_level(self, level: int) -> bool: logger.info(f"🔍 Testing level {level}...") self.args.level = level multi_pipeline = MultiPipeline(self.args) - log_dir = multi_pipeline.run() - # load results.yaml - with open(log_dir / "aggregated_results.yaml", 'r') as f: - results = yaml.safe_load(f) - self.model_path = results['model_path'] - success_mean = float(results['success']['mean'].split(' ')[0]) + aggregated_results = multi_pipeline.run() + success_mean = float(aggregated_results['success']['mean'].split(' ')[0]) all_success = success_mean == 1.0 if all_success: logger.info(f"✅ Level {level} passed all tests.") else: logger.info(f"❌ Level {level} failed some tests.") - return all_success + return all_success, aggregated_results \ No newline at end of file diff --git a/robogauge/tasks/pipeline/multi_pipeline.py b/robogauge/tasks/pipeline/multi_pipeline.py index b64d0ae..7c88437 100644 --- a/robogauge/tasks/pipeline/multi_pipeline.py +++ b/robogauge/tasks/pipeline/multi_pipeline.py @@ -36,18 +36,19 @@ def run_single_process(args, data): console_output=False ) pipeline = task_register.make_pipeline(args=local_args, create_logger=False) - log_dir, error = pipeline.run() + results, error = pipeline.run() if error is None: ret = { 'status': 'success', - 'log_dir': log_dir, + 'results': results, 'model_path': pipeline.robot_cfg.control.model_path, } else: logger.error(f"❌ Process with seed={seed}, base_mass={base_mass}, friction={friction} failed with error: {error}") ret = { 'status': 'error', - 'log_dir': log_dir, + 'results': results, + 'model_path': pipeline.robot_cfg.control.model_path, 'data': data, 'error_msg': str(error), 'traceback': traceback.format_exc() @@ -61,8 +62,14 @@ class MultiPipeline: self.frictions = args.frictions self.base_masses = args.base_masses self.num_processes = args.num_processes - self.model_path = None + self.static_info = {} logger.create(args.experiment_name+'_multi', args.run_name+'_multi') + + def add_static_info(self, key: str, value): + if key not in self.static_info: + self.static_info[key] = value + else: + assert self.static_info[key] == value, f"Static info key '{key}' has conflicting values: {self.static_info[key]} vs {value}" def run(self): logger.info(f"🚀 Starting Multi-Process Evaluation with {self.num_processes} processes.") @@ -71,32 +78,30 @@ class MultiPipeline: workers_data = list(product(self.seeds, self.base_masses, self.frictions)) ctx = multiprocessing.get_context('spawn') worker_func = functools.partial(run_single_process, self.args) - result_log_dirs = [] + results_list = [] success_flags = [] with ctx.Pool(processes=self.num_processes) as pool: iterator = pool.imap_unordered(worker_func, workers_data) for results in tqdm(iterator, total=len(workers_data), desc="Evaluation"): success_flags.append(results['status'] == 'success') - result_log_dirs.append(results['log_dir']) - if results['status'] == 'success': - if self.model_path is None: - self.model_path = results['model_path'] - else: - assert self.model_path == results['model_path'], "Model paths do not match across runs." - else: + results_list.append(results['results']) + self.add_static_info('model_path', results['model_path']) + self.add_static_info('terrain_name', results['results']['terrain_name']) + self.add_static_info('terrain_level', results['results']['terrain_level']) + if results['status'] != 'success': data = results['data'] logger.error(f"❌ Process with seed={data[0]}, base_mass={data[1]}, friction={data[2]} failed with error: {results['error_msg']}") logger.info("✅ Multi-Process Evaluation Completed.") - self.aggregate_results(result_log_dirs, success_flags, workers_data) - return logger.log_dir + aggregated_results = self.aggregate_results(results_list, success_flags, workers_data) + return aggregated_results - def aggregate_results(self, log_dirs, success_flags, workers_data): - """ Process results.yaml from each log_dir """ + def aggregate_results(self, all_results, success_flags, workers_data): + """ Process results from all processes and aggregate them. """ logger.info("📊 Aggregating Results from all runs...") - summary = {'model_path': self.model_path, 'success': {}} + summary = {'success': {}, **self.static_info} finish_msg = ( f"""\n{'='*20} Run Finish Summary {'='*20}\n""" f"""{'Seed':^10}{'Base Mass':^15}{'Friction':^15}{'Status':^10}\n""" @@ -109,27 +114,9 @@ class MultiPipeline: finish_msg += f"""{'='*88}""" logger.info(finish_msg) - all_results = [] - all_yaml_paths = [] - for path in log_dirs: - yaml_path = Path(path) / "results.yaml" - if not yaml_path.exists(): - logger.warning(f"Results file not found: {yaml_path}, skipping.") - continue - with open(yaml_path, 'r') as file: - data = yaml.safe_load(file) - if data: - all_results.append(data) - all_yaml_paths.append(yaml_path) if not all_results: logger.error("No results to aggregate.") return - yaml_paths_str = '\n'.join([str(p) for p in all_yaml_paths]) - logger.info( - f"""\n{'='*20} Results Files {'='*20}\n""" - f"""{yaml_paths_str}\n""" - f"""{'='*56}""" - ) value_collections = defaultdict(lambda: defaultdict(list)) for result in all_results: @@ -156,3 +143,4 @@ class MultiPipeline: f"""{yaml.dump(summary, allow_unicode=True)}""" f"""{'='*60}""" ) + return summary