Skip to content

Go2 Speed vs Precision testing#2138

Draft
mustafab0 wants to merge 11 commits into
mainfrom
mustafa/task/go2-controller-tuning
Draft

Go2 Speed vs Precision testing#2138
mustafab0 wants to merge 11 commits into
mainfrom
mustafa/task/go2-controller-tuning

Conversation

@mustafab0
Copy link
Copy Markdown
Contributor

@mustafab0 mustafab0 commented May 18, 2026

Problem

Tuning the Go2 base controller was guesswork: the FOPDT plant fit and feedforward gains were hand-vendored, with no single artifact telling an operator "for tolerance X cm, run at speed Y."

Issue: #921


Solution

Two CLI tools producing one versioned config artifact. go2_characterization runs a space-cheap velocity-step system-ID, fits FOPDT per axis (vx/vy/wz), and derives feedforward + a curvature velocity profile; go2_benchmark sweeps the hardcoded baseline controller across a speed ladder and writes back the operating-point map + tolerance→max-safe-speed inversion. One SI harness, sim vs hardware is just which plant the steps drive. Carries only the minimal verified dependency closure from the R&D branch (R&D archived off-repo).


Breaking Changes

None


How to Test

  1. uv run pytest dimos/utils/benchmarking/test_tuning.py -q → 16 pass.
  2. uv run python -m dimos.utils.benchmarking.characterization --mode self-test → artifact, valid_for_tuning=false.
  3. uv run python -m dimos.utils.benchmarking.benchmark --config <self-test artifact> --mode sim --speeds 0.5 → sim pre-check map.
  4. Run dimos run unitree-go2-webrtc-keyboard-teleop to position robot before each test

@codecov
Copy link
Copy Markdown

codecov Bot commented May 18, 2026

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
1839 1 1838 28
View the top 1 failed test(s) by shortest run time
dimos.project.test_no_sections::test_no_section_markers
Stack Traces | 0.523s run time
def test_no_section_markers():
        """
        Fail if any file contains section-style comment markers.
    
        If a file is too complicated to be understood without sections, then the
        sections should be files. We don't need "subfiles".
        """
        violations = find_section_markers()
        if violations:
            report_lines = [
                f"Found {len(violations)} section marker(s). "
                "If a file is too complicated to be understood without sections, "
                'then the sections should be files. We don\'t need "subfiles".',
                "",
            ]
            for path, lineno, text in violations:
                report_lines.append(f"  {path}:{lineno}: {text.strip()}")
>           raise AssertionError("\n".join(report_lines))
E           AssertionError: Found 56 section marker(s). If a file is too complicated to be understood without sections, then the sections should be files. We don't need "subfiles".
E           
E             .../drive_trains/fopdt_sim_base/adapter.py:75: # =========================================================================
E             .../drive_trains/fopdt_sim_base/adapter.py:77: # =========================================================================
E             .../drive_trains/fopdt_sim_base/adapter.py:91: # =========================================================================
E             .../drive_trains/fopdt_sim_base/adapter.py:93: # =========================================================================
E             .../drive_trains/fopdt_sim_base/adapter.py:98: # =========================================================================
E             .../drive_trains/fopdt_sim_base/adapter.py:100: # =========================================================================
E             .../drive_trains/fopdt_sim_base/adapter.py:110: # =========================================================================
E             .../drive_trains/fopdt_sim_base/adapter.py:112: # =========================================================================
E             .../drive_trains/fopdt_sim_base/adapter.py:130: # =========================================================================
E             .../drive_trains/fopdt_sim_base/adapter.py:132: # =========================================================================
E             .../drive_trains/fopdt_sim_base/adapter.py:141: # =========================================================================
E             .../drive_trains/fopdt_sim_base/adapter.py:143: # =========================================================================
E             .../control/tasks/velocity_profiler.py:79: # ------------------------------------------------------------------
E             .../control/tasks/velocity_profiler.py:81: # ------------------------------------------------------------------
E             .../control/tasks/baseline_path_follower_task.py:123: # ------------------------------------------------------------------
E             .../control/tasks/baseline_path_follower_task.py:125: # ------------------------------------------------------------------
E             .../control/tasks/baseline_path_follower_task.py:178: # ------------------------------------------------------------------
E             .../control/tasks/baseline_path_follower_task.py:180: # ------------------------------------------------------------------
E             .../control/tasks/baseline_path_follower_task.py:254: # ------------------------------------------------------------------
E             .../control/tasks/baseline_path_follower_task.py:256: # ------------------------------------------------------------------
E             .../utils/characterization/trajectories.py:75: # ---------------------------------------------------------------------------
E             .../utils/characterization/trajectories.py:77: # ---------------------------------------------------------------------------
E             .../utils/characterization/trajectories.py:290: # ---------------------------------------------------------------------------
E             .../utils/characterization/trajectories.py:292: # ---------------------------------------------------------------------------
E             .../utils/characterization/trajectories.py:329: # ---------------------------------------------------------------------------
E             .../utils/characterization/trajectories.py:331: # ---------------------------------------------------------------------------
E             .../utils/characterization/trajectories.py:357: # ---------------------------------------------------------------------------
E             .../utils/benchmarking/test_tuning.py:50: # --- DERIVE ---------------------------------------------------------------
E             .../utils/benchmarking/test_tuning.py:137: # --- artifact round-trip --------------------------------------------------
E             .../utils/benchmarking/test_tuning.py:160: # --- tolerance -> max-safe-speed inversion --------------------------------
E             .../utils/benchmarking/plant.py:120: # --- Vendored fitted FOPDT plant for the Go2 base ------------------------
E             .../utils/benchmarking/plant.py:147: # --- Per-robot profile (single source of truth for robot specifics) -----
E             .../utils/benchmarking/characterization.py:86: # --- self-test (in-process FOPDT plant; NOT robot-valid) -----------------
E             .../utils/benchmarking/characterization.py:152: # --- fit-quality graph (the human-facing deliverable) -------------------
E             .../utils/benchmarking/characterization.py:198: # --- hardware SI (real robot over LCM, operator-gated, safe) -------------
E             .../utils/benchmarking/paths.py:78: # ---------------------------------------------------------------------------
E             .../utils/benchmarking/paths.py:80: # ---------------------------------------------------------------------------
E             .../utils/benchmarking/paths.py:190: # ---------------------------------------------------------------------------
E             .../utils/benchmarking/paths.py:192: # ---------------------------------------------------------------------------
E             .../utils/benchmarking/paths.py:284: # ---------------------------------------------------------------------------
E             .../utils/benchmarking/paths.py:286: # ---------------------------------------------------------------------------
E             .../utils/benchmarking/scoring.py:82: # ---------------------------------------------------------------------------
E             .../utils/benchmarking/scoring.py:84: # ---------------------------------------------------------------------------
E             .../utils/benchmarking/scoring.py:129: # ---------------------------------------------------------------------------
E             .../utils/benchmarking/scoring.py:131: # ---------------------------------------------------------------------------
E             .../utils/benchmarking/scoring.py:199: # ---------------------------------------------------------------------------
E             .../utils/benchmarking/scoring.py:201: # ---------------------------------------------------------------------------
E             .../utils/benchmarking/benchmark.py:107: # --- inlined baseline sim harness (was runner.py + sim_blueprint.py) -----
E             .../utils/benchmarking/benchmark.py:279: # --- hw harness (real robot over LCM; closed-loop baseline) -------------
E             .../utils/benchmarking/benchmark.py:441: # --- benchmark ----------------------------------------------------------
E             .../utils/benchmarking/tuning.py:53: # --- DERIVE tunable constants (documented; single source of truth) -------
E             .../utils/benchmarking/tuning.py:86: # --- Artifact schema -----------------------------------------------------
E             .../utils/benchmarking/tuning.py:214: # --- serialization ---
E             .../utils/benchmarking/tuning.py:264: # --- helpers -------------------------------------------------------------
E             .../utils/benchmarking/tuning.py:313: # --- DERIVE: pure model -> config ---------------------------------------
E             .../utils/benchmarking/tuning.py:398: # --- tolerance -> max-safe-speed inversion (pure) ------------------------

lineno     = 398
path       = '.../utils/benchmarking/tuning.py'
report_lines = ['Found 56 section marker(s). If a file is too complicated to be understood without sections, then the sections should...trains/fopdt_sim_base/adapter.py:93: # =========================================================================', ...]
text       = '# --- tolerance -> max-safe-speed inversion (pure) ------------------------'
violations = [('.../drive_trains/fopdt_sim_base/adapter.py', 75, '    # ================================================...pdt_sim_base/adapter.py', 100, '    # ========================================================================='), ...]

dimos/project/test_no_sections.py:145: AssertionError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@mustafab0 mustafab0 force-pushed the mustafa/task/go2-controller-tuning branch from 2fb6967 to bfe69aa Compare May 20, 2026 00:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant