-
-
Notifications
You must be signed in to change notification settings - Fork 624
Panda models
RTB ships four Franka-Emika Panda-related models — DH-based DH.Panda, and the URDF-based Panda, Frankie, FrankieOmni — and they don't all load the same underlying data. This page explains why, and what tradeoffs that implies.
| Model | Source | Inertial data | Collision geometry |
|---|---|---|---|
DH.Panda() |
hand-coded DH parameters; m/r/I ported from MATLAB RTB's mdl_panda.m (PR #294) |
real (see caveat below) | none — DH models carry no collision primitives at all |
Panda() (default) |
bundled qut_frankie_description xacro |
none — every link is massless | hand-built capsule approximation |
Panda(use_robot_descriptions=True) |
robot_descriptions | real (0.63–4.97 kg per arm link) | plain meshes |
Frankie() |
robot_descriptions |
real | plain meshes |
FrankieOmni() |
bundled qut_frankie_description xacro (arm) + bundled clearpath_ridgeback_description xacro (base) |
none on the arm | hand-built capsule approximation |
If you need correct dynamics (rne(), inertia(), coriolis(), gravload()) from a Panda model, use Frankie(), or Panda(use_robot_descriptions=True). If you need fast real-time collision checking against the robot's own geometry (reactive avoidance, link_collision_damper(), examples/neo.py-style control loops), the default Panda() is faster.
RTB bundles its own copy of a Panda arm xacro (qut_frankie_description, rtb-data/rtbdata/xacro/qut_frankie_description/) — originally vendored to support FrankieOmni, RTB's model of a real QUT lab robot (a Panda arm mounted on a Robotnik-style omnidirectional mobile base), which needs to splice a Panda arm onto a mobile base xacro that no public package provides pre-combined. Panda() reused that same bundled arm file opportunistically, since it was already sitting there — not because it needed anything specific from it.
That bundled xacro has real, hand-built collision geometry: each link is approximated as a capsule (a cylinder with sphere caps at each end), which is fast and numerically well-behaved to collision-check against. It also has a safety_distance macro parameter that could pad every collision shape's radius with a margin — but the currently-shipped file instantiates it at 0.00, so it's dormant, not actually doing anything today. What it does not have is any <inertial> tag anywhere in the package — confirmed by grepping the whole tree. It was built for geometry (visual + collision), not dynamics.
robot_descriptions (a third-party package for fetching robot description files on demand) has its own Panda entry, sourced from example-robot-data. It carries real inertial parameters — masses matching DH.Panda()'s own dynamics data almost exactly, suggesting a common manufacturer-data lineage — and real collision geometry too, but as plain meshes (one per link, plus box primitives for the fingers) rather than hand-tuned capsules.
Frankie() already loads the robot_descriptions Panda directly (super().__init__("panda", ...)), and has done so in production for a while — it's not a hypothetical, it's a working precedent that this source is solid.
This isn't the first time a "Panda has no inertial data" report has come up — issue #278 raised exactly this for DH.Panda() back in 2022. It was fixed shortly after: PR #294, by Antun Škurić (askuric), ported the parameters straight out of the MATLAB Robotics Toolbox's own mdl_panda.m, which itself traces back to the same manufacturer data robot_descriptions' URDF carries.
That fix doesn't transfer to the URDF models, and porting it directly would be a real mistake, not just redundant work. DH inertial parameters (r, the CoM offset, and I, the inertia tensor) are expressed relative to the DH link frame, a convention with its own specific axis placement rules — not the same frame a URDF joint uses. Copying DH-frame numbers into a URDF link without also transforming them through the frame difference would produce plausible-looking numbers that are dynamically wrong, silently — exactly the class of bug this whole investigation started by chasing down (see #636/#684). If you need real inertial data on a URDF Panda, get it from a source that's already self-consistent in the URDF's own frame convention — robot_descriptions, not DH.Panda.py.
That same doubt applies reflexively to DH.Panda() itself, though: PR #294's own description calls it "just a quick transfer," with no stated check that MATLAB RTB's DH link frame for each Panda joint lines up with Python RTB's for the same a/d/alpha/mdh values. Issue #688 tracks actually verifying this — cross-checked against Frankie()'s independently-sourced data, gravity torque matches at every configuration tried and the full inertia matrix M(q) matches to within ~1%, which is reassuring but not exhaustive (no Coriolis-term-specific check, no third independent reference yet). See that issue for the numbers.
Why not just always use robot_descriptions and be done with it? Measured directly, same obstacle, same robot pose, same machine:
- A single
closest_pointquery: capsule primitive (sphere/cylinder) ≈0.003ms once warmed up, vs. mesh ≈0.19ms — roughly 60x more expensive per shape pair. A mesh-vs-shape query runs full GJK/EPA against a triangulated surface; a capsule has an analytic closed-form distance formula. -
link_collision_damper()end to end (the function real-time reactive-avoidance code, includingexamples/neo.py, calls every control-loop iteration): 1.3ms with the bundled capsule geometry vs. 15.4ms withrobot_descriptions' meshes — about 12x slower, despite the mesh model having fewer total collision shapes per link (1 vs. 3–6). The per-shape mesh cost dominates enough to overcome that.
For a control loop budgeting a few milliseconds per step, that difference is the kind of thing you'd actually notice, not a rounding error. That's why Panda(use_robot_descriptions=True) is an opt-in rather than a default-flip — neither source is strictly better, it depends on what you're doing with the model.
-
FrankieOmni()doesn't have an equivalent option. It builds its link list by hand (URDF_read()twice, then manual parent-splicing) rather than going throughURDFRobot's own loader, so adding a toggle there means threading the choice through that manual assembly rather than a single constructor kwarg. - The ideal fix — real inertial data and the fast capsule collision geometry, for every model — needs a hybrid: load
robot_descriptionsfor kinematics/mass/inertia, then graft the bundled xacro's capsule shapes onto the same links by name afterward. Not yet implemented. -
dual_panda_example.urdf.xacro, also in the bundledqut_frankie_descriptionpackage, is unreferenced by anything insrc/— dead content, noted but not cleaned up. -
DH.Panda()'s own inertial data hasn't been exhaustively verified — see #688.
Tracked in issue #686 (this page) and #688 (DH.Panda() verification).
- Frequently asked questions (FAQ)
- Documentation Style Guide
- Background
- Key concepts
- Introduction to robot and link classes
- Working with Jupyter
- Working from the command line
- What about Simulink?
- How to contribute
- Contributors
- Coding conventions