Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions docs/source/IK/ik.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ There are other arguments which may be unique to the solver, so check the docume
C++ Solvers
-----------

These solvers are written in high performance C++ and wrapped in Python methods. The methods are made available within the :py:class:`~roboticstoolbox.robot.ETS.ETS` and :py:class:`~roboticstoolbox.robot.Robot.Robot` classes. Being written in C++, these solvers are extraordinarily fast and typically take 30 to 90 µs. However, these solvers are hard to extend or modify.
These solvers are written in high performance C++ and wrapped in Python methods. The methods are made available within the :py:class:`~roboticstoolbox.ets.ETS.ETS` and :py:class:`~roboticstoolbox.robot.Robot.Robot` classes. Being written in C++, these solvers are extraordinarily fast and typically take 30 to 90 µs. However, these solvers are hard to extend or modify.

These methods have been written purely for speed so they do not contain the niceties of the Python alternative. For example, if you give the incorrect length for the ``q0`` vector, you could end up with a ``seg-fault`` or other undetermined behaviour. Therefore, when using these methods it is very important that you understand each of the parameters and the parameters passed are of the correct type and length.

Expand All @@ -90,9 +90,9 @@ The C++ solvers can be identified as methods which start with ``ik_``.
.. autosummary::
:toctree: stubs

~roboticstoolbox.robot.ETS.ETS.ik_LM
~roboticstoolbox.robot.ETS.ETS.ik_GN
~roboticstoolbox.robot.ETS.ETS.ik_NR
~roboticstoolbox.ets.ETS.ETS.ik_LM
~roboticstoolbox.ets.ETS.ETS.ik_GN
~roboticstoolbox.ets.ETS.ETS.ik_NR

.. rubric:: Robot C++ IK Methods

Expand All @@ -115,7 +115,7 @@ In the following example, we create a :py:class:`~roboticstoolbox.models.URDF.Pa
>>> # Solve the IK problem
>>> panda.ik_LM(Tep)

In the following example, we create a :py:class:`~roboticstoolbox.models.URDF.Panda` robot and and then get the :py:class:`~roboticstoolbox.robot.ETS.ETS` representation. Subsequently, we use one of the fast IK solvers available within the :py:class:`~roboticstoolbox.robot.ETS.ETS` class.
In the following example, we create a :py:class:`~roboticstoolbox.models.URDF.Panda` robot and and then get the :py:class:`~roboticstoolbox.ets.ETS.ETS` representation. Subsequently, we use one of the fast IK solvers available within the :py:class:`~roboticstoolbox.ets.ETS.ETS` class.

.. runblock:: pycon

Expand Down Expand Up @@ -181,7 +181,7 @@ These solvers can be identified as a :py:class:`Class` starting with ``IK_``.

.. rubric:: Example

In the following example, we create an IK Solver class and pass an :py:class:`~roboticstoolbox.robot.ETS.ETS` to it to solve the problem. This style may be preferable to experiments where you wish to compare the same solver on different robots.
In the following example, we create an IK Solver class and pass an :py:class:`~roboticstoolbox.ets.ETS.ETS` to it to solve the problem. This style may be preferable to experiments where you wish to compare the same solver on different robots.

.. runblock:: pycon

Expand All @@ -202,7 +202,7 @@ In the following example, we create an IK Solver class and pass an :py:class:`~r
.. IK Solvers Available with an ETS
.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Additionally, these :py:class:`Class` based solvers have been implemented as methods within the :py:class:`~roboticstoolbox.robot.ETS.ETS` and :py:class:`~roboticstoolbox.robot.Robot.Robot` classes. The method names start with ``ikine_``.
Additionally, these :py:class:`Class` based solvers have been implemented as methods within the :py:class:`~roboticstoolbox.ets.ETS.ETS` and :py:class:`~roboticstoolbox.robot.Robot.Robot` classes. The method names start with ``ikine_``.


.. toctree:
Expand All @@ -215,10 +215,10 @@ Additionally, these :py:class:`Class` based solvers have been implemented as met
.. autosummary::
:toctree: stubs

~roboticstoolbox.robot.ETS.ETS.ikine_LM
~roboticstoolbox.robot.ETS.ETS.ikine_QP
~roboticstoolbox.robot.ETS.ETS.ikine_GN
~roboticstoolbox.robot.ETS.ETS.ikine_NR
~roboticstoolbox.ets.ETS.ETS.ikine_LM
~roboticstoolbox.ets.ETS.ETS.ikine_QP
~roboticstoolbox.ets.ETS.ETS.ikine_GN
~roboticstoolbox.ets.ETS.ETS.ikine_NR


.. rubric:: Robot Python IK Methods
Expand Down Expand Up @@ -246,7 +246,7 @@ In the following example, we create a :py:class:`~roboticstoolbox.models.URDF.Pa
>>> # Solve the IK problem
>>> panda.ikine_LM(Tep)

In the following example, we create a :py:class:`~roboticstoolbox.models.URDF.Panda` robot and and then get the :py:class:`~roboticstoolbox.robot.ETS.ETS` representation. Subsequently, we use one of the IK solvers available within the :py:class:`~roboticstoolbox.robot.ETS.ETS` class.
In the following example, we create a :py:class:`~roboticstoolbox.models.URDF.Panda` robot and and then get the :py:class:`~roboticstoolbox.ets.ETS.ETS` representation. Subsequently, we use one of the IK solvers available within the :py:class:`~roboticstoolbox.ets.ETS.ETS` class.

.. runblock:: pycon

Expand Down
4 changes: 2 additions & 2 deletions docs/source/arm_ets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ The ETS inherits list-like properties and has methods like ``reverse`` and ``pop
ETS - 3D
--------

.. autoclass:: roboticstoolbox.robot.ETS.ETS
.. autoclass:: roboticstoolbox.ets.ETS.ETS
:members: __str__, __repr__, __mul__, __getitem__, n, m, structure, joints, jointset, split, inv, compile, insert, fkine, jacob0, jacobe, hessian0, hessiane
:undoc-members:
:show-inheritance:
Expand All @@ -78,7 +78,7 @@ ETS - 3D
ETS - 2D
--------

.. autoclass:: roboticstoolbox.robot.ETS.ETS2
.. autoclass:: roboticstoolbox.ets.ETS2.ETS2
:members: __str__, __repr__, __mul__, __getitem__, n, m, structure, joints, jointset, split, inv, compile, insert, fkine, jacob0, jacobe
:undoc-members:
:show-inheritance:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ dependencies = [
"typing_extensions",
"colored>2.0.0",
"xacrodoc",
"robot_descriptions",
"robot_descriptions>=2.0,<3.0",
]

license = { file = "LICENSE" }
Expand Down
61 changes: 61 additions & 0 deletions tech-debt.md
Original file line number Diff line number Diff line change
Expand Up @@ -1096,3 +1096,64 @@ the real dependency becomes explicit rather than implicit.
`/robot`, see the ETS/fknm refactor entry above) is underway — worth
revisiting together since the import surface `IK.py` needs from the new
package location is the same shape this protocol would formalize.

## `URDF.UR5`'s `gripper_link_index=7` is a hardcoded position, not a stable identifier

### Background

Found 2026-07-17: CI failed on `URDF.UR5` construction (`ValueError:
incorrect vector length: expected 4, got (6,)` from `addconfiguration_attr`)
across every OS/Python combination, while local runs passed. Root cause:
`pyproject.toml`'s `robot_descriptions` dependency had no upper bound, and
`robot_descriptions` 3.0.0 (uploaded 2026-07-11) changed which upstream repo
"ur5" resolves to — `Universal_Robots_ROS2_Description` instead of whatever
2.0.0 pointed at. `UR5.__init__` calls `super().__init__("ur5", ...,
gripper_link_index=7)`, a raw positional index into the parsed link list
meant to mark the gripper/tool attachment link. The two versions parse to
different link counts (11 vs. 13) and orderings, so index `7` now lands on
`wrist_2_link` — a real arm joint — instead of the intended attachment
point, silently dropping 2 of 6 joints from `self.n`.

`gripper_link_index` was calibrated against `UR5.py`'s older local, vendored
xacro file (before it was switched to the bare name `"ur5"`, which triggers
live `robot_descriptions` resolution) — it was never designed to survive the
upstream source changing under it, which is now possible on every fresh
install.

**Immediate fix**: pinned `robot_descriptions>=2.0,<3.0` in `pyproject.toml`
(same floor+ceiling pattern already used for `rtb-data`), restoring the
known-working data. This does not fix the underlying fragility, just stops
it from firing today.

### Confirmed: a name/structure-based fix is viable, not a dead end

Compared the full raw link lists (`URDF_file("ur5")`, independent of the
gripper-link logic) between the two `robot_descriptions` versions:

- 2.0.0 (11 links): `world, base_link, shoulder_link, upper_arm_link,
forearm_link, wrist_1_link, wrist_2_link, wrist_3_link, ee_link, base,
tool0`
- 3.0.0 (13 links): `world, base_link, base_link_inertia, shoulder_link,
upper_arm_link, forearm_link, wrist_1_link, wrist_2_link, wrist_3_link,
ft_frame, base, flange, tool0`

All 6 real arm joints have identical names and `isjoint` status in both.
Only the gripper-attachment link's name differs (`ee_link` in 2.0.0), but
`tool0` exists in **both** — just at a different index (9 vs. 12). So a
name-based lookup (`"tool0"`) or, more robustly, a structural one ("the
first fixed link after the last actuated joint") would survive this exact
upstream change, unlike the index.

### Proposed fix

Replace `gripper_link_index: int` with a lookup that doesn't depend on
absolute position — either match by a small set of known tool-frame names
(`tool0`, `ee_link`, `flange`, ...) with a fallback, or derive it
structurally (first non-actuated link following the last actuated one in
the kinematic chain). Worth checking how many other `URDF.*` models pass a
raw `gripper_link_index` the same fragile way before deciding on the
general fix — this UR5 case is likely not unique.

**Deferred**: not fixed now, since the pin already resolves the immediate
CI break and this needs its own design pass rather than a rushed fix
bundled into a dependency-pin PR.