Skip to content

feat(robot): add FrankaPandaCfg and dual-arm coordinated placement tutorial#362

Merged
yuecideng merged 21 commits into
mainfrom
feat/franka-panda-dual-arm
Jul 10, 2026
Merged

feat(robot): add FrankaPandaCfg and dual-arm coordinated placement tutorial#362
yuecideng merged 21 commits into
mainfrom
feat/franka-panda-dual-arm

Conversation

@yuecideng

Copy link
Copy Markdown
Contributor

Description

This PR adds Franka Emika Panda robot support to the dual-arm framework and a coordinated placement tutorial demonstrating dual-arm Franka operation with PytorchSolver.

Changes

  • FrankaPandaCfg (embodichain/lab/sim/robots/franka_panda.py): Single-arm Franka config with PandaWithHand URDF (7-DOF arm Joint1–Joint7 + 2 finger joints), using PytorchSolverCfg with Franka TCP (45° Z-rotation, 0.1034m Z-offset). Default init_qpos from Isaac Lab reference.

  • Dual-arm registry (embodichain/lab/sim/robots/dual_arm.py): Register "franka" in _BASE_ROBOT_REGISTRY so DualArmRobotCfg.from_dict({"base_robot": "franka", ...}) works.

  • Coordinated placement tutorial (scripts/tutorials/atomic_action/coordinated_placement_franka.py): Demonstrates dual-arm Franka coordinated placement with bread/pan meshes, following the same structure as the existing UR5 version.

  • Exports (embodichain/lab/sim/robots/__init__.py): Export FrankaPandaCfg.

Type of change

  • New feature (non-breaking change which adds functionality)

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.

yuecideng added 8 commits July 4, 2026 22:46
…torial

Add FrankaPandaCfg for Franka Emika Panda with PandaWithHand URDF,
register it in the dual-arm framework, and create a coordinated
placement tutorial script demonstrating dual-arm Franka operation
with PytorchSolver.

- Add FrankaPandaCfg: 7-DOF arm + 2 finger joints, PytorchSolverCfg
  with Franka TCP (45 deg Z-rotation, 0.1034m Z-offset)
- Register 'franka' in DualArmRobotCfg._BASE_ROBOT_REGISTRY
- Add coordinated_placement_franka.py tutorial script
- Export FrankaPandaCfg from robots __init__.py
Copilot AI review requested due to automatic review settings July 5, 2026 15:44
@yuecideng yuecideng added robot Module related to robot solver Robot kinematics solver atomic action atomic action related functionality 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 adds Franka Emika Panda support to EmbodiChain’s dual-arm robot composition framework and introduces a new dual-arm coordinated placement tutorial that mirrors the existing UR5 demo structure.

Changes:

  • Added a new single-arm FrankaPandaCfg robot configuration using a Panda-with-hand URDF and PytorchSolverCfg.
  • Extended the dual-arm base robot registry to support base_robot="franka" via DualArmRobotCfg.from_dict(...).
  • Added a new tutorial script demonstrating dual-arm coordinated placement with Franka arms and bread/pan meshes, and exported FrankaPandaCfg from the robots package.

Reviewed changes

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

File Description
scripts/tutorials/atomic_action/coordinated_placement_franka.py New tutorial/demo for dual-arm Franka coordinated placement planning/execution.
embodichain/lab/sim/robots/franka_panda.py Introduces FrankaPandaCfg (URDF wiring, control parts, solver cfg, defaults).
embodichain/lab/sim/robots/dual_arm.py Registers "franka" in _BASE_ROBOT_REGISTRY so dual-arm composition can resolve Franka.
embodichain/lab/sim/robots/init.py Exports FrankaPandaCfg from the robots package.

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

Comment thread embodichain/lab/sim/robots/franka_panda.py
Comment on lines 76 to 81
#: Registry mapping a ``base_robot`` key to ``(single-arm cfg class, init dict)``.
#: Adding a new single-arm robot here is all that is needed to make it
#: dual-arm-able: e.g. ``"franka": (FrankaRobotCfg, {})``.
#: dual-arm-able: e.g. ``"franka": (FrankaPandaCfg, {"robot_type": "panda"})``.
_BASE_ROBOT_REGISTRY: Dict[str, tuple] = {
"franka": (FrankaPandaCfg, {"robot_type": "panda"}),
"ur3": (URRobotCfg, {"robot_type": "ur3"}),
Comment on lines +76 to +90
@configclass
class FrankaPandaCfg(RobotCfg):
"""Configuration for the Franka Emika Panda robot with Panda hand.

The PandaWithHand URDF includes both the 7-DOF arm and the parallel-jaw
gripper in a single file. The solver defaults to
:class:`~embodichain.lab.sim.solvers.PytorchSolverCfg`.

Example:

cfg = FrankaPandaCfg.from_dict({"robot_type": "panda"})
robot = sim.add_robot(cfg=cfg)
"""

robot_type: str = "panda"
Copilot AI review requested due to automatic review settings July 9, 2026 12:37

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

Copilot reviewed 6 out of 6 changed files in this pull request and generated 9 comments.

Comment on lines +742 to +749
full[:, :n_approach, arm_joint_ids] = approach_arm
full[:, :n_approach, hand_joint_ids] = hand_open
full[:, n_approach : n_approach + n_close, arm_joint_ids] = (
grasp_arm_qpos.unsqueeze(1)
)
full[:, n_approach : n_approach + n_close, hand_joint_ids] = hand_close_path
full[:, n_approach + n_close :, arm_joint_ids] = lift_arm
full[:, n_approach + n_close :, hand_joint_ids] = hand_close
# ------------------------------------------------------------------ #
sim = initialize_simulation(args)
robot = create_robot(sim)
print("**********tcp xpos:\n", robot._solvers["arm"].tcp_xpos)
Comment on lines +125 to +129
self.control_parts = {
"arm": [f"fr3_joint{i}" for i in range(1, 8)],
"hand": ["fr3_finger_joint1", "fr3_finger_joint2"],
}

Comment on lines +135 to +139
[1, 0, 0.0, 0.0],
[0, 1, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
],
Comment thread embodichain/lab/sim/robots/franka_panda.py
Comment on lines +60 to +64
@configclass
class FrankaPandaCfg(RobotCfg):
"""Configuration for the Franka Emika Panda robot with Panda hand.

The PandaWithHand URDF includes both the 7-DOF arm and the parallel-jaw
Comment on lines 76 to +80
#: Registry mapping a ``base_robot`` key to ``(single-arm cfg class, init dict)``.
#: Adding a new single-arm robot here is all that is needed to make it
#: dual-arm-able: e.g. ``"franka": (FrankaRobotCfg, {})``.
#: dual-arm-able: e.g. ``"franka": (FrankaPandaCfg, {"robot_type": "panda"})``.
_BASE_ROBOT_REGISTRY: Dict[str, tuple] = {
"franka": (FrankaPandaCfg, {"robot_type": "panda"}),
Comment on lines 357 to 362
Franka/
Panda/
Panda.urdf
PandaHand.urdf
PandaWithHand.urdf
FR3/
fr3.urdf
Comment thread embodichain/data/assets/robot_assets.py Outdated
Copilot AI review requested due to automatic review settings July 9, 2026 14:43

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

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Comment on lines +125 to +142
self.control_parts = {
"arm": [f"fr3_joint{i}" for i in range(1, 8)],
"hand": ["fr3_finger_joint1", "fr3_finger_joint2"],
}

self.solver_cfg = {
"arm": PytorchSolverCfg(
end_link_name="fr3_hand_tcp",
root_link_name="base",
tcp=[
[1, 0, 0.0, 0.0],
[0, 1, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
],
num_samples=30,
),
}
Comment on lines +144 to +157
self.drive_pros = JointDrivePropertiesCfg(
stiffness={
"fr3_joint[1-7]": 1e4,
"fr3_finger_joint[1-2]": 1e3,
},
damping={
"fr3_joint[1-7]": 1e3,
"fr3_finger_joint[1-2]": 1e2,
},
max_effort={
"fr3_joint[1-7]": 1e5,
"fr3_finger_joint[1-2]": 1e4,
},
)
Comment on lines +181 to +186
chain = create_pk_serial_chain(
urdf_path=self._pk_urdf_path,
device=device,
end_link_name="fr3_hand_tcp",
root_link_name="base",
)
Comment on lines 76 to +80
#: Registry mapping a ``base_robot`` key to ``(single-arm cfg class, init dict)``.
#: Adding a new single-arm robot here is all that is needed to make it
#: dual-arm-able: e.g. ``"franka": (FrankaRobotCfg, {})``.
#: dual-arm-able: e.g. ``"franka": (FrankaPandaCfg, {"robot_type": "panda"})``.
_BASE_ROBOT_REGISTRY: Dict[str, tuple] = {
"franka": (FrankaPandaCfg, {"robot_type": "panda"}),
# ------------------------------------------------------------------ #
sim = initialize_simulation(args)
robot = create_robot(sim)
print("**********tcp xpos:\n", robot._solvers["arm"].tcp_xpos)
Comment on lines +62 to +66
"""Configuration for the Franka Emika Panda robot with Panda hand.

The PandaWithHand URDF includes both the 7-DOF arm and the parallel-jaw
gripper in a single file. The solver defaults to
:class:`~embodichain.lab.sim.solvers.PytorchSolverCfg`.
Comment on lines 357 to 361
Franka/
Panda/
Panda.urdf
PandaHand.urdf
PandaWithHand.urdf
FR3/
Copilot AI review requested due to automatic review settings July 10, 2026 06:36

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

Copilot reviewed 6 out of 6 changed files in this pull request and generated 8 comments.

Comment on lines +25 to +30
from embodichain.lab.sim.cfg import (
JointDrivePropertiesCfg,
RigidBodyAttributesCfg,
RobotCfg,
URDFCfg,
)
Comment on lines +125 to +129
self.control_parts = {
"arm": [f"fr3_joint{i}" for i in range(1, 8)],
"hand": ["fr3_finger_joint1", "fr3_finger_joint2"],
}

Comment on lines +130 to +142
self.solver_cfg = {
"arm": PytorchSolverCfg(
end_link_name="fr3_hand_tcp",
root_link_name="base",
tcp=[
[1, 0, 0.0, 0.0],
[0, 1, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
],
num_samples=30,
),
}
Comment on lines +144 to +157
self.drive_pros = JointDrivePropertiesCfg(
stiffness={
"fr3_joint[1-7]": 1e4,
"fr3_finger_joint[1-2]": 1e3,
},
damping={
"fr3_joint[1-7]": 1e3,
"fr3_finger_joint[1-2]": 1e2,
},
max_effort={
"fr3_joint[1-7]": 1e5,
"fr3_finger_joint[1-2]": 1e4,
},
)
Comment on lines +181 to +187
chain = create_pk_serial_chain(
urdf_path=self._pk_urdf_path,
device=device,
end_link_name="fr3_hand_tcp",
root_link_name="base",
)
return {"arm": chain}
Comment on lines +78 to 81
#: dual-arm-able: e.g. ``"franka": (FrankaPandaCfg, {"robot_type": "panda"})``.
_BASE_ROBOT_REGISTRY: Dict[str, tuple] = {
"franka": (FrankaPandaCfg, {"robot_type": "panda"}),
"ur3": (URRobotCfg, {"robot_type": "ur3"}),
Comment on lines 357 to 362
Franka/
Panda/
Panda.urdf
PandaHand.urdf
PandaWithHand.urdf
FR3/
fr3.urdf
Comment on lines +60 to +74
@configclass
class FrankaPandaCfg(RobotCfg):
"""Configuration for the Franka Emika Panda robot with Panda hand.

The PandaWithHand URDF includes both the 7-DOF arm and the parallel-jaw
gripper in a single file. The solver defaults to
:class:`~embodichain.lab.sim.solvers.PytorchSolverCfg`.

Example:

cfg = FrankaPandaCfg.from_dict({"robot_type": "panda"})
robot = sim.add_robot(cfg=cfg)
"""

robot_type: str = "panda"
Copilot AI review requested due to automatic review settings July 10, 2026 07:50
@yuecideng yuecideng merged commit 944e5a9 into main Jul 10, 2026
2 checks passed
@yuecideng yuecideng deleted the feat/franka-panda-dual-arm branch July 10, 2026 07:51

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

Copilot reviewed 7 out of 7 changed files in this pull request and generated 8 comments.

Comment on lines +125 to +128
self.control_parts = {
"arm": [f"fr3_joint{i}" for i in range(1, 8)],
"hand": ["fr3_finger_joint1", "fr3_finger_joint2"],
}
Comment on lines +130 to +142
self.solver_cfg = {
"arm": PytorchSolverCfg(
end_link_name="fr3_hand_tcp",
root_link_name="base",
tcp=[
[1, 0, 0.0, 0.0],
[0, 1, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
],
num_samples=30,
),
}
Comment on lines +144 to +157
self.drive_pros = JointDrivePropertiesCfg(
stiffness={
"fr3_joint[1-7]": 1e4,
"fr3_finger_joint[1-2]": 1e3,
},
damping={
"fr3_joint[1-7]": 1e3,
"fr3_finger_joint[1-2]": 1e2,
},
max_effort={
"fr3_joint[1-7]": 1e5,
"fr3_finger_joint[1-2]": 1e4,
},
)
Comment on lines +181 to +186
chain = create_pk_serial_chain(
urdf_path=self._pk_urdf_path,
device=device,
end_link_name="fr3_hand_tcp",
root_link_name="base",
)
Comment on lines +25 to +30
from embodichain.lab.sim.cfg import (
JointDrivePropertiesCfg,
RigidBodyAttributesCfg,
RobotCfg,
URDFCfg,
)
Comment on lines +60 to +72
@configclass
class FrankaPandaCfg(RobotCfg):
"""Configuration for the Franka Emika Panda robot with Panda hand.

The PandaWithHand URDF includes both the 7-DOF arm and the parallel-jaw
gripper in a single file. The solver defaults to
:class:`~embodichain.lab.sim.solvers.PytorchSolverCfg`.

Example:

cfg = FrankaPandaCfg.from_dict({"robot_type": "panda"})
robot = sim.add_robot(cfg=cfg)
"""
Comment on lines +68 to +72
Example:

cfg = FrankaPandaCfg.from_dict({"robot_type": "panda"})
robot = sim.add_robot(cfg=cfg)
"""
Comment on lines 375 to +377
data_descriptor = o3d.data.DataDescriptor(
os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "FrankaV2.zip"),
"f0675b9da98126bc3d4e18c98ef5e06c",
os.path.join(EMBODICHAIN_DOWNLOAD_PREFIX, robot_assets, "FrankaV3.zip"),
"ec53536615ddc1c44660f2d66fdf82ae",
skywhite1024 pushed a commit that referenced this pull request Jul 10, 2026
…torial (#362)

Co-authored-by: Chen Jian <mtfl1996@outlook.com>
Co-authored-by: matafela <chenjian@dexforce.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

atomic action atomic action related functionality robot Module related to robot solver Robot kinematics solver

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants