Skip to content

fix(dexforce_w1): merge PytorchSolver and SRSSolver defaults, fix solver_cfg merge#363

Merged
yuecideng merged 3 commits into
mainfrom
fix/solver-cfg-merge-and-dexforce-w1-defaults
Jul 6, 2026
Merged

fix(dexforce_w1): merge PytorchSolver and SRSSolver defaults, fix solver_cfg merge#363
yuecideng merged 3 commits into
mainfrom
fix/solver-cfg-merge-and-dexforce-w1-defaults

Conversation

@yuecideng

Copy link
Copy Markdown
Contributor

Description

This PR fixes the default solver_cfg construction for DexforceW1 and rewrites the merge_robot_cfg solver merge to support general custom control-part + solver addition.

Problem

  1. DexforceW1 _build_defaults() only produced SRSSolverCfg entries for left_arm/right_arm, discarding the PytorchSolverCfg entries needed for whole-body IK. The build_dexforce_w1_solver_cfg() utility existed but was never called.

  2. merge_robot_cfg had broken solver merging: when a user passed solver_cfg without class_type (attribute-only overrides like {"tcp": ...}), the old code replaced the entire base_cfg.solver_cfg dict — silently dropping other solver parts. The loop mixed per-part and whole-dict logic in the same iteration.

  3. No clean mechanism for adding custom control parts + solvers: users could pass control_parts and solver_cfg via init_dict, but the merge was fragile and undocumented.

Changes

embodichain/lab/sim/robots/dexforce_w1/cfg.py_build_defaults() now calls build_dexforce_w1_solver_cfg() for PytorchSolver entries (full_body), then overlays SRSSolver entries via dict.update(). SRSSolver takes precedence for arm keys (DH-based, more precise for 7-DoF arms).

embodichain/lab/sim/robots/dexforce_w1/utils.pybuild_dexforce_w1_solver_cfg():

  • Uses control_parts-aligned keys ("left_arm", "right_arm") instead of type-aligned keys ("left_arm1", "left_arm2") that never matched any control part
  • Fixed enum .value usage for dict keys (raw enum members break regex matching in init_solver)
  • Updated return type annotation to Dict[str, SolverCfg]

embodichain/lab/sim/utility/cfg_utils.py — Rewrote merge_robot_cfg solver_cfg merge with three clean per-part modes:

  • class_type present → new/replacement solver (deserialized via RobotCfg.from_dict)
  • No class_type, part exists → merge individual attribute overrides in-place (preserves other parts)
  • No class_type, part unknown → warn and skip

Result

Default DexforceW1 solver_cfg now has all needed entries:

  • left_arm → SRSSolverCfg (DH-based, precise)
  • right_arm → SRSSolverCfg (DH-based, precise)
  • full_body → PytorchSolverCfg (URDF-based, whole-body IK) — NEW

Users can now reliably add custom control parts + solvers:

DexforceW1Cfg.from_dict({
    "control_parts": {"my_custom": ["LEFT_J1", "LEFT_J2"]},
    "solver_cfg": {"my_custom": {"class_type": "PytorchSolver", ...}},
})

Fixes #120

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Checklist

  • I have run the black . command to format the code base.
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • Dependencies have been updated, if applicable.

…ver_cfg merge

The _build_defaults() only set solver_cfg to SRSSolver entries for
left_arm/right_arm, discarding PytorchSolver entries needed for whole-body
IK. Now builds both families and merges with SRSSolver taking precedence
for the 7-DoF arms.

Also rewrites merge_robot_cfg's solver_cfg merge to use per-part logic
instead of whole-dict replacement, fixing a bug where attribute-only
overrides could silently drop other solver parts. Users can now reliably
add custom control_parts and solver_cfg entries via init_dict.

Fixes #120

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 5, 2026 16:51
@yuecideng yuecideng added bug Something isn't working enhancement New feature or request solver Robot kinematics solver robot Module related to robot labels Jul 5, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes DexforceW1’s default IK solver configuration so whole-body PytorchSolver entries are preserved alongside per-arm SRSSolver defaults, and it rewrites merge_robot_cfg’s solver_cfg merge logic to support safe per-part replacement vs. in-place attribute overrides.

Changes:

  • DexforceW1 defaults now build PytorchSolver solver entries (including full_body) and then overlay SRSSolver entries for left_arm/right_arm.
  • build_dexforce_w1_solver_cfg() now keys solver entries by control-part-aligned string names (and uses enum .value where appropriate).
  • merge_robot_cfg() now merges solver_cfg per-part with explicit handling for class_type (replace/add) vs. attribute-only overrides (in-place).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
embodichain/lab/sim/utility/cfg_utils.py Reworks solver_cfg merging to be per-part and preserve unrelated solver entries.
embodichain/lab/sim/robots/dexforce_w1/utils.py Aligns solver_cfg dict keys with control part names and fixes enum-key usage.
embodichain/lab/sim/robots/dexforce_w1/cfg.py Builds merged default solver_cfg (PytorchSolver + SRSSolver overlay) instead of overwriting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 106 to 110
provided_solver_cfg = override_cfg_dict.get("solver_cfg")
if provided_solver_cfg:
if provided_solver_cfg and isinstance(provided_solver_cfg, dict):
if base_cfg.solver_cfg is None:
base_cfg.solver_cfg = {}
for part, item in provided_solver_cfg.items():
Comment on lines +133 to +134
if hasattr(target, attr_name):
setattr(target, attr_name, attr_val)
Comment on lines +130 to +137
pytorch_entries = build_dexforce_w1_solver_cfg(
arm_kind=self.arm_kind,
urdf_cfg=self.urdf_cfg,
)
srs_entries = self._build_default_solver_cfg(arm_kind=self.arm_kind)
# Merge: SRSSolver takes precedence for arm keys
pytorch_entries.update(srs_entries)
self.solver_cfg = pytorch_entries
Comment on lines +111 to +121
if isinstance(item, dict) and "class_type" in item:
# New or replacement solver part — use the deserialized
# SolverCfg object produced by RobotCfg.from_dict.
parsed = (
robot_cfg.solver_cfg.get(part)
if isinstance(robot_cfg.solver_cfg, dict)
else None
)
if parsed is not None:
base_cfg.solver_cfg[part] = parsed
else:
@yuecideng yuecideng merged commit 87fc0cc into main Jul 6, 2026
5 checks passed
@yuecideng yuecideng deleted the fix/solver-cfg-merge-and-dexforce-w1-defaults branch July 6, 2026 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request robot Module related to robot solver Robot kinematics solver

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Proposal] Optimization of default built solver_cfg for dexforceW1

2 participants