diff --git a/docs/source/IK/ik.rst b/docs/source/IK/ik.rst index 87529ba83..2e27013f3 100644 --- a/docs/source/IK/ik.rst +++ b/docs/source/IK/ik.rst @@ -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. @@ -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 @@ -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 @@ -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 @@ -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: @@ -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 @@ -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 diff --git a/docs/source/arm_ets.rst b/docs/source/arm_ets.rst index 251b44490..49a5b33ed 100644 --- a/docs/source/arm_ets.rst +++ b/docs/source/arm_ets.rst @@ -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: @@ -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: diff --git a/pyproject.toml b/pyproject.toml index c831d4369..46eac8a15 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ dependencies = [ "typing_extensions", "colored>2.0.0", "xacrodoc", - "robot_descriptions", + "robot_descriptions>=2.0,<3.0", ] license = { file = "LICENSE" } diff --git a/tech-debt.md b/tech-debt.md index 612bdccb3..33f39ca33 100644 --- a/tech-debt.md +++ b/tech-debt.md @@ -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.