Skip to content

fix(robot): preserve link topology when copying robots - #732

Open
huxiaoyi-ovo wants to merge 5 commits into
petercorke:mainfrom
huxiaoyi-ovo:fix/copy-link-parent-topology
Open

huxiaoyi-ovo wants to merge 5 commits into
petercorke:mainfrom
huxiaoyi-ovo:fix/copy-link-parent-topology

Conversation

@huxiaoyi-ovo

Copy link
Copy Markdown
Contributor

Summary

Fixes #730.

Copied URDF/ETS robots can retain references to links in the original robot, causing copy().rne() to fail. The same problem affects coriolis() because nofriction() replaces the copied robot's links with another set of disconnected copies.

This PR addresses both root causes:

  • Rebuild parent/child relationships during BaseRobot.__deepcopy__() using the existing parent-name resolution mechanism.
  • Modify friction parameters directly on the copied robot's links instead of replacing nf._links.
  • Add a regression test with two joints separated by a static link.

The test verifies correct parent/child references, unchanged original topology, matching inverse dynamics results, and successful coriolis() calculations.

Validation

Validated commit fbc9474 in [fork CI PR #2](huxiaoyi-ovo#2).

  • Python 3.10–3.14 on Ubuntu, Windows and macOS: all passed.
  • Core tests and aggregate test gate: passed.
  • Coverage and documentation builds: passed.
  • 19 successful jobs, 1 conditional skip, 0 failures.

Only three files changed. No public API signatures or inverse dynamics equations were modified.

@codacy-production

codacy-production Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 0 complexity · -2 duplication

Metric Results
Complexity 0
Duplication -2

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@codecov

codecov Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 0.00%. Comparing base (31d99a9) to head (b5fa99b).

Files with missing lines Patch % Lines
src/roboticstoolbox/robot/Link.py 0.00% 16 Missing ⚠️
src/roboticstoolbox/robot/BaseRobot.py 0.00% 8 Missing ⚠️
src/roboticstoolbox/robot/Dynamics.py 0.00% 6 Missing ⚠️
Additional details and impacted files
@@          Coverage Diff          @@
##            main    #732   +/-   ##
=====================================
  Coverage   0.00%   0.00%           
=====================================
  Files        146     146           
  Lines      17295   17304    +9     
=====================================
- Misses     17295   17304    +9     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@petercorke

Copy link
Copy Markdown
Owner

Thank you for this, and for the careful test. I reproduced the problem: on main, copy() leaves each link tied to the original robot's links, and fkine on a copy fails. Your change fixes that. Before I merge it I'd like the fix made at its root rather than patched from outside. Three requests:

  • Make Link.__deepcopy__ respect its memo argument, the dictionary that copy.deepcopy passes along, which maps each original object to the copy already made. Use it for the references, for example deepcopy(self.parent, memo) instead of self.parent, and record the new link in memo before copying them, since parent and child refer to each other. BaseRobot.__deepcopy__ then copies all the links with one shared memo, and the changes to _children, _parent_name and _parent can go.
  • In nofriction, use Link.nofriction rather than setting B and Tc again by hand.
  • Copy the grippers too. At the moment the copy of a Panda has no gripper, so fkine ends at a different frame from the original. Gripper modeling is being reconsidered in Rethink how grippers are modeled, and pause gripper-related changes #884, so keep that part small.

A test that copy().fkine(q) equals fkine(q) for a robot with a gripper would catch this.

Use one deepcopy memo for all arm and gripper links. Register each link
before copying its parent, leaving the child graph to be reconstructed
by the robot constructor. Restore the gripper tool and joint state.

Preserve nofriction topology while delegating coefficient changes to
Link.nofriction. Add a Panda gripper and FK regression test.

Co-Authored-By: ChatGPT (GPT-6) <chatgpt@openai.com>
@huxiaoyi-ovo
huxiaoyi-ovo force-pushed the fix/copy-link-parent-topology branch from 5a6b0b8 to 328a616 Compare October 22, 2026 10:24
huxiaoyi-ovo and others added 2 commits October 22, 2026 06:27
Preserve current main's typing and maintenance updates. Reapply only the
memo-based graph copy, gripper state, friction and targeted tests.

Co-Authored-By: ChatGPT (GPT-6) <chatgpt@openai.com>
mypy reports three unused-ignore errors after the graph-copy update.
Remove only these obsolete annotations; there is no runtime change.

Co-Authored-By: ChatGPT (GPT-6) <chatgpt@openai.com>
@huxiaoyi-ovo

Copy link
Copy Markdown
Contributor Author

Hi @petercorke, thanks for the detailed review.

I've updated the branch to address all three points: shared deepcopy memo handling for link topology, reusing Link.nofriction() without replacing links, and preserving the gripper links, tool transform and joint state.

I also added regression tests for the parent graph, RNE/Coriolis and Panda gripper FK consistency.

The revised head is b5fa99b. The [fork CI run](huxiaoyi-ovo#2) has passed the core suite (2,310 passed), and the remaining platform checks are still running.

ChatGPT assisted with code review and test preparation.

This branch has not been deployed

No deployments
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.

coriolis() and Robot.copy().rne() fail for URDF/ETS robots: copied links keep their original parent

2 participants