COMPAS FAB 2.0 release#458
Open
gonzalocasas wants to merge 454 commits into
Open
Conversation
…ollision handling
…ultiple solutions and trajectory replay
The CPython Grasshopper componentizer (componentize_cpy.py) imports clr directly, which requires pythonnet. The Phase 1 build job was failing with ModuleNotFoundError. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add Cf_SetRobotConfiguration to bridge IK output back into a RobotCellState for visualization. Closes the IK loop in the offline demo path; was a missing piece from Phase 1. - Drop the `compute` gate on Cf_InverseKinematics. IK is fast enough that always-on evaluation is fine, and the gate added wiring noise. - Drop `typeHintID: "bool"` from `load_geometry` on the Library and ROS loaders. CPython GH coerced unwired bool inputs to False, defeating the in-code `None -> True` default; without the hint the input stays None when unwired and the default kicks in. - Cf_LoadRobotCellFromRos: surface the detected ROS distro on a new output and print a targeted hint when the load fails with HTTP 404 (typical symptom of ROS 1 falling back to the ROS 2 HTTP loader when rosapi is missing). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Remove the deep RobotCellState copy from PyBullet set_robot_cell_state and apply the same by-reference behavior in the analytical planner for consistency. Why: Data.copy() performs a deep serialize/deserialize copy and was a hot-path cost during collision checking (check_collision -> set_robot_cell_state). set_robot_cell_state only reads state fields and does not mutate the passed object; the copy mainly prevented aliasing with client._robot_cell_state. Side effect: client._robot_cell_state now stores the caller-provided object by reference. Added explicit docstring notes in PyBullet set_robot_cell_state and check_collision, and analytical set_robot_cell_state, advising callers to pass state.copy() when post-call mutation is intended. Validation performed: - Benchmarked 2000 collision checks with random configurations in PyBullet: ur5 1.449s -> 1.022s (29.5 percent faster); ur5_cone_tool 3.009s -> 1.844s (38.7 percent faster); abb_irb4600_40_255_gripper_one_beam 3.419s -> 1.932s (43.5 percent faster); collision counts unchanged between variants. - Regression tests: 105 passed (tests with --ignore=tests/backends/ros).
The old default sat on top of the rosbridge port used when remapping a
ROS 2 stack to coexist with a ROS 1 stack (rosbridge 9090 + ROS 2 rosbridge
9091). A user pointing the loader at their local ROS 2 stack got HTTP 404s
because the loader was hitting the bridge, not the file server.
9190 stays mnemonic ("near rosbridge") while sitting clear of the 909x
cluster where ROS-adjacent stuff tends to land. Both reference docker
stacks (integration tests and the ros2-ur10e-demo) default the host AND
container-internal port to 9190 so the stack speaks one number end to end.
The ROS 2 rosbridge port (9091) is unchanged — only the file server moved.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Unreleased section had grown four ### Changed, two ### Fixed, two ### Added, and two ### Removed blocks as separate prep-release patches were merged. Collapsed each Keep-a-Changelog category into a single heading and dropped the custom \"Fixed (examples)\" heading by folding example fixes into the regular ### Fixed list. No entries added or removed; pure reorganization. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The official ros:jazzy image is smaller (no desktop metapackage we don't use — moveit/ur/rosbridge/zenoh are installed explicitly anyway) and publishes multi-arch images including arm64, which lets Apple Silicon hosts run the demo natively. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Credit for contributions in #449 (not merged as-is, but the author is recognized in the project's author list and CITATION metadata). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
4 tasks
Atomic builders that let users construct a RobotCell and RobotCellState from scratch on the canvas, plus the missing waypoint and Configuration helpers needed to drive Cartesian motion planning. New components (Robot Cell): - Cf_LoadRobotCellFromUrdfSrdf (offline URDF/SRDF loader) - Cf_RigidBodyFromMesh (Rhino mesh -> RigidBody) - Cf_RigidBodyFromLibrary (RigidBodyLibrary entries) - Cf_ToolFromLibrary (ToolLibrary entries) - Cf_AddToolToCell (passthrough builder) - Cf_AddRigidBodyToCell (passthrough builder) New components (Cell State): - Cf_AttachToolToRobot (set_tool_attached_to_group) - Cf_AttachRigidBodyToTool (set_rigid_body_attached_to_tool) - Cf_AttachRigidBodyToLink (set_rigid_body_attached_to_link) - Cf_SetRigidBodyFrame (place static body at WCF frame) - Cf_SetTouchLinks (allowed-collision links) New components (Targets): - Cf_FrameWaypoints (planes -> FrameWaypoints) - Cf_PointAxisWaypoints (points + axes -> PointAxisWaypoints) - Cf_Configuration (joint values + names + types -> Configuration) All cell-state builders use deepcopy to keep the input state immutable — chaining Attach*/Set* components composes cleanly without surprise. Placeholder icons recycled as before. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…s compas_fab.robots The Sphinx -> MkDocs Material migration left RST role markup in the docstrings. This sweep converts the entire compas_fab.robots module (and its reachability_map subpackage) to mkdocstrings syntax: :class:`compas_fab.robots.Foo` -> [\`Foo\`][compas_fab.robots.Foo] :class:`~compas_fab.robots.Foo` -> [\`Foo\`][compas_fab.robots.Foo] :meth:`Foo.bar()` -> \`Foo.bar()\` (unqualified - no cross-ref) :meth:`compas_fab.robots.Foo.bar` -> [\`Foo.bar\`][compas_fab.robots.Foo.bar] :attr:`compas_fab.robots.Foo.bar` -> [\`Foo.bar\`][compas_fab.robots.Foo.bar] :obj:`bool/float/str/...` -> \`bool\`/\`float\`/\`str\`/... :exc:`ValueError` -> \`ValueError\` :ref:`targets` -> \`targets\` Also fixes RST hyperlinks (\`Label <url>\`_) to markdown ([Label](url)), the singular typo \`compas_fab.robot.plan_motion\` -> \`compas_fab.robots...\`, and a handful of stale cross-references to the removed \`Robot\` class (updated to point at \`RobotCell\`). 509 roles converted across 14 files. Net diff is roughly neutral on line count (-492/+478). All files still parse. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
\`uv run invoke docs\` was emitting 6 warnings from the doc build: - trajectory.py: \`compas_robots.Joint.TYPE\` / \`.REVOLUTE\` cross-refs. Joint lives at \`compas_robots.model.Joint\`, but class-level attributes aren't in compas_robots' Sphinx inventory. Switched to plain backticks since cross-linking external class attributes isn't supported. - semantics.py: stale refs to \`PyBulletClient.load_semantics\` and \`RosClient.load_robot\` (both methods removed/renamed during the API redesign). Replaced with a single working ref to \`RosClient.load_robot_cell\`. - targets.py: refs to \`compas_fab.robots.plan_motion\` / \`plan_cartesian_motion\`. These were never top-level functions; the methods live on planner backends. Reworded to "the planner's plan_motion method". - robot_library.py: ref to instance attribute \`RobotCellState.tool_states\`. mkdocstrings can't resolve instance attributes set in __init__; kept the class link and made \`.tool_states\` a plain trailing access. Docs build now warning-free. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…lToRobot Attaching a tool with no `group` wired in was a silent no-op — confusing for the common case where the user has a single-group robot (UR, ABB, Panda) and shouldn't have to look up the group name. Added an optional `robot_cell` input. When `group` is empty: - if `robot_cell` is wired, fall back to `robot_cell.main_group_name` - otherwise, raise with a message that points at the fix. Reported during Phase 3 testing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…matics Swallowing the exception with `print(...) + return None` hid the failure — on the canvas you got an empty output and a console line that's easy to miss. Removed the try/except so the exception bubbles up; Grasshopper will then turn the component red and show the message in its tooltip. Reported during Phase 3 testing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…nents Replaces silent exceptions and console prints with Grasshopper-native runtime messages (component balloons), so failures are visible without needing the user to wire an `error` output or watch the console. Components updated to use error() instead of raise / print: Cf_AddRigidBodyToCell, Cf_AddToolToCell, Cf_AnalyticalKinematicsPlanner, Cf_AttachToolToRobot, Cf_Configuration, Cf_InverseKinematics, Cf_LoadRobotCellFromLibrary, Cf_LoadRobotCellFromRos, Cf_PointAxisWaypoints, Cf_RigidBodyFromLibrary, Cf_ToolFromLibrary. Components updated to use warning() (partial success) + error() (no result): Cf_PlanMotion, Cf_PlanCartesianMotion. Cf_RosClient: warning() when the previous client fails to close cleanly, remark() when ROS distro detection fails (informational). Also adds a `visual_meshes` output to Cf_ToolFromLibrary so users can preview the tool's geometry (Rhino meshes, drawn in the tool's own base frame) before attaching it to a robot. Reported during Phase 3 testing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…mLibrary
Adds compas_fab.ghpython.ensure_value_list, a reusable helper that
auto-creates a Grasshopper Value List on an unconnected component input.
Cf_LoadRobotCellFromLibrary now uses it to expose every RobotCellLibrary
entry as a dropdown (default "ur5") instead of a free-text panel.
Loader calls are wrapped in try/except and surfaced via compas_ghpython.error
with the sticky cache cleared on failure, so retries actually retry.
Also fixes ToolLibrary.cone(): it now calls add_link("cone_link", ...) like
ToolLibrary.printing_tool() does. Without the link, the cone's underlying
ToolModel.root tree was malformed and iter_joints() crashed with
"'NoneType' object has no attribute 'joints'". This is what made
RobotCellLibrary.ur5_cone_tool(load_geometry=False) always crash and
manifested in the GH component when toggling load_geometry off while
clicking through robot names.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
witnessing you pushing HARD Mr @gonzalocasas |
ensure_value_list wired the new GH_ValueList to the input during the current solve, but the input's value collection had already happened, so the dropdown's selection didn't reach the component until the user manually re-triggered the solver. Calling doc.ScheduleSolution(5) immediately after AddSource queues a fresh solve so the value flows on the very first drop with no user intervention. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds compas_fab.ghpython.ensure_joint_sliders, a helper that on first solve (or whenever the wired robot's joint signature changes) registers one Param_Number input per configurable joint and auto-creates a GH_NumberSlider feeding each input, with min/max set to the joint's URDF limits (±2π fallback for continuous joints, ±1m for prismatic with no declared limit). Joint signature is tracked in sticky so swapping robot_cell rebuilds the bank rather than appending to it; obsolete sliders are removed from the document on rebuild. doc.ScheduleSolution(5) is used so values flow on the first drop. The new Cf_RobotConfiguration component (subcategory Targets) takes one robot_cell input, returns a Configuration with joint_names and joint_types populated from the cell — the ergonomic counterpart to the existing Cf_Configuration, which stays as the manual-list escape hatch. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The CPython userobjects build (invoke build-cpython-ghuser-components, run in CI by the build-cpython-components job) requires icon.png in every component folder; without it the build fails. Used Cf_Configuration's icon as a placeholder since the two components are siblings in subcategory Targets — can be swapped for a dedicated icon later. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
integration.yml brings up two docker compose stacks (ROS 1 on 9090, ROS 2
on 9091) with `up -d --build` and immediately runs pytest. On cold-cache
runs the rosbridge containers aren't accepting websocket connections yet
when `--doctest-modules` reaches `RosClient`'s `>>> with RosClient()`
example at client.py:162, and roslibpy's 10s connection timeout fires
with `RosTimeoutError('Failed to connect to ROS')`. The dedicated
tests/backends/ros/test_ros_client.py cases pass because they run later
in the session when the bridge is warm.
Added a `Wait for rosbridge endpoints` step that TCP-probes ports 9090
and 9091 on localhost for up to 120s before pytest. 120s is well above
the worst observed cold-start; hitting it means the container itself is
unhealthy, in which case `docker ps -a` output is dumped before exit.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This reverts commit 344084c.
…ation Temporarily point requirements.txt at the lifecycle-fixes branch on gramaziokohler/roslibpy to exercise the 2.1 candidates (singleton twisted log observer, Ros.close() blocking until clientConnectionLost) against the integration workflow. If the RosClient doctest at client.py:162 stops flaking under --doctest-modules, the upstream roslibpy fixes are doing their job and we revert this pin back to roslibpy >= 2.0, < 3 once 2.1 is released. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The two >>> with RosClient() examples in compas_fab.backends.ros.client
(RosClient class docstring at line 162; RosClient.load_robot_cell at
line 257) keep flaking under pytest --doctest-modules in the integration
workflow with `RosTimeoutError('Failed to connect to ROS')` — always on
the FIRST one, with the second succeeding milliseconds later. Marking
both # doctest: +SKIP eliminates the flake; the actual code path is
exercised by tests/backends/ros/test_ros_client.py (9 cases under the
module-scoped ros1_client fixture, never observed to flake), so the
doctests are only losing their role as a self-verifying illustration.
Also reverts the temporary `roslibpy @ git+...#lifecycle-fixes` pin
back to `roslibpy >= 2.0, < 3`. The pin was added to validate two
candidate roslibpy 2.1 fixes (singleton log observer, close() blocking
until clientConnectionLost) against this exact symptom — the
integration run with that branch failed identically, falsifying the
hypothesis that this flake was caused by either of those bugs.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…yncio Pin roslibpy to the websockets-asyncio branch (new asyncio/websockets transport) and opt the integration job into it via ROSLIBPY_TRANSPORT. Drop the two `# doctest: +SKIP` markers on the RosClient examples so we actually exercise the live path again. Validation only — not for merge as-is. Reverts the temporary +SKIP from 2cc6602 and the lifecycle-fixes pin from b64d020. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR superceedes #456 and contains the entire Project Theseus + ROS 2 / MoveIt 2 support.
What type of change is this?
Checklist
Put an
xin the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.CHANGELOG.mdfile in theUnreleasedsection under the most fitting heading (e.g.Added,Changed,Removed).invoke test).invoke lint).compas_fab.robots.CollisionMesh.