Skip to content

Add collision_monitor lab_sim integration (key-gated, parallel objectives test)#718

Draft
MikeWrock wants to merge 15 commits into
mainfrom
feature/collision-monitor-integration
Draft

Add collision_monitor lab_sim integration (key-gated, parallel objectives test)#718
MikeWrock wants to merge 15 commits into
mainfrom
feature/collision-monitor-integration

Conversation

@MikeWrock

Copy link
Copy Markdown
Collaborator

Layer-2 "deploy to customer" integration: runs the licensed collision_monitor in parallel with the lab_sim MoveIt Pro objectives integration test.

  • New src/lab_sim_collision_monitor usage example (config/launch/params only — no proprietary source in this public repo).
  • Parallel-monitor test asserts both directions: no false trips on valid objectives + a deliberate contact that must trip (PROJECTED_COLLISION).
  • .github/workflows/collision-monitor-integration.yaml: on repository_dispatch (collision-monitor-integration), pulls the licensed bundle_image (never builds source), supplies MOVEIT_LICENSE_KEY from secret STUDIO_CI_LICENSE_KEY, runs the test. Without a valid key the gated node fails loudly — the intended IP protection.

Consumes the bundle published by the collision_monitor deploy-pipeline PR.

🤖 Generated with Claude Code

marioprats and others added 15 commits May 18, 2026 11:15
unfavorite kinova_sim Velocity Force Controller Zero, and zero fts
Replace `GetMasks2DFromTextQuery` (CLIPSeg) with `GetMasks2DFromExemplar`
(SAM3 multimodal segmenter) in the `ML Move Boxes to Loading Zone`
Objective and its inner Subtree. SAM3 also accepts a text prompt but
returns SUCCESS with `mask_count=0` on empty detections, letting the
Subtree skip the downstream pick pipeline cleanly with `_skipIf`.

Restructure the outer loop from the `RetryUntilSuccessful + ForceFailure`
infinite-loop pattern to
`Fallback { RepeatUnlessFailureEachTick { ... ScriptCondition(!drained) }, ScriptCondition(drained) }`
so the loop exits with Objective SUCCESS when the scene is drained but
surfaces real pick errors as Objective FAILURE.

Fixes #19112.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…Boxes

Updates the View Boxes text prompt from "brown cube" to
"a single small orange cube box" to better describe the sim assets,
then guards the SAM3 output with FilterMasks2DByArea so the
downstream pick pipeline only sees plausibly-sized box masks:
the cart frame measured ~26,285 px in calibration and was the
primary false positive driving wasted pick attempts; thin
edge-fragment masks measured ~778 px. Real boxes in this scene
measure 3,949-20,643 px, so thresholds are min=2,000 / max=23,000.

GetSizeOfVector refreshes {mask_count} after the filter so the
existing `_skipIf="mask_count == 0"` gate reflects the filtered
count rather than SAM3's raw count.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-filter

Fix: Filter SAM3 mask false positives by area in hangar_sim
…sam3

Fix: Use SAM3 instead of CLIPSeg in ML Move Boxes Objective
add a wait to give TF time to be available
Pulls in PickNikRobotics/picknik_accessories#45 — makes the lab_sim
burner pushable under realistic gripper force.
…ries-burner-v9.3

Fix: Bump picknik_accessories for lab_sim burner movable fix
Adds src/lab_sim_collision_monitor: a usage example that configures the
vendor-neutral, separately-licensed collision_monitor node for lab_sim
(UR-on-a-linear-rail). Robot specifics live only in launch/params.

- config: StateProvider <- /joint_states (model-DOF order; lab_sim reports
  driving joint angles directly, no actuator conversion). default_accel_limit
  set to the arm's 30 deg/s^2 spec; rail uses its URDF accel limit.
- launch: ComposableNodeContainer loading the licensed
  collision_monitor_ros::CollisionMonitorComponent (from the pre-bundled
  binary overlay/image, NOT built here).
- test: parallel-monitor Layer-2 integration test reusing the objectives
  harness. Asserts BOTH (a) no false trips during a safe objective and
  (b) a deliberate self-collision pose MUST trip (PROJECTED_COLLISION).
  Doubles as the license gate: without MOVEIT_LICENSE_KEY the monitor dies
  on init and the test fails loudly. TripSink demo halts the JTC on trip.

Adds .github/workflows/collision-monitor-integration.yaml: downstream
Layer-2 workflow triggered by repository_dispatch
(collision-monitor-integration) + workflow_dispatch. PULLS the licensed
bundle image from client_payload.bundle_image, supplies MOVEIT_LICENSE_KEY
from STUDIO_CI_LICENSE_KEY, builds the example overlay on top of the bundle,
and runs the Layer-2 test. It never clones or builds collision_monitor
source (this repo is public; the monitor is proprietary).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Integrated collision monitoring system for lab_sim robot with safety validation
    • Upgraded object picking pipeline to SAM3 text-prompt segmentation
    • Enhanced behavior tree control flows for improved picking reliability
  • Tests

    • Added comprehensive collision monitor integration test suite validating safety scenarios
  • Chores

    • Updated submodule dependencies

Walkthrough

Adds a new lab_sim_collision_monitor ROS 2 package (config, launch, integration tests) and a GitHub Actions workflow that validates it against a license-gated bundle image. Migrates hangar_sim box-picking objectives to SAM3 segmentation and replaces KeepRunningUntilFailure with RepeatUnlessFailureEachTick. Updates kinova_sim velocity_force_controller_zero and write_picknik objective wiring. Bumps two submodule pins.

Changes

lab_sim_collision_monitor Package and CI Workflow

Layer / File(s) Summary
Package manifest, build config, and documentation
src/lab_sim_collision_monitor/package.xml, src/lab_sim_collision_monitor/CMakeLists.txt, src/lab_sim_collision_monitor/README.md
package.xml declares metadata and dependencies (collision_monitor_ros, lab_sim, rclcpp_components); CMakeLists.txt installs config/launch and registers a 900 s pytest integration test with MOVEIT_CONFIG_PACKAGE and MOVEIT_HOST_USER_WORKSPACE env vars; README.md documents license gating, ROS wiring, local run instructions, and integration test assertions.
YAML config and launch script
src/lab_sim_collision_monitor/config/lab_sim_collision_monitor.yaml, src/lab_sim_collision_monitor/launch/collision_monitor.launch.py
YAML sets rate_hz, deadline_us, default_accel_limit, and swept_path_samples for the UR-on-rail robot. Launch script instantiates a ComposableNodeContainer loading CollisionMonitorComponent with configurable params_file and monitor_namespace arguments.
Integration test fixtures and test cases
src/lab_sim_collision_monitor/test/conftest.py, src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py
conftest.py re-exports shared fixtures. Integration test defines MonitorProbe (subscribes to /status and /trip, deactivates joint_trajectory_controller on first trip) and three tests: test_monitor_becomes_active, test_no_false_trip_during_safe_objective (runs "Move Along Square"), and test_deliberate_self_collision_trips (drives arm to self-collision pose and asserts PROJECTED_COLLISION).
GitHub Actions CI workflow
.github/workflows/collision-monitor-integration.yaml
Handles repository_dispatch and workflow_dispatch triggers with per-github.ref concurrency cancellation; validates bundle_image and STUDIO_CI_LICENSE_KEY; checks out workspace; logs into bundle registry; pulls licensed bundle image; builds overlay CI image; runs colcon test for lab_sim_collision_monitor with license key and CI MuJoCo timestep override; uploads test artifacts unconditionally.

Hangar Sim Behavior Tree Objective Updates

Layer / File(s) Summary
RepeatUnlessFailureEachTick decorator migration
src/hangar_sim/objectives/move_boxes_looping.xml
Replaces KeepRunningUntilFailure with RepeatUnlessFailureEachTick (num_cycles="-1") and adds inline comments on failure propagation semantics and a moveit_pro 9.3+ compatibility note.
SAM3 segmentation migration and picked_box reset
src/hangar_sim/objectives/move_boxes_to_loading_zone_from_waypoint.xml
Adds an early Script resetting picked_box := false; replaces CLIPSeg+SAM2 mask generation with GetMasks2DFromExemplar using confidence_threshold and text_prompt; adds mask area filtering, mask_count computation, and a _skipIf="mask_count == 0" bypass. Updates TreeNodesModel ports: adds confidence_threshold, text_prompt, picked_box; removes old CLIPSeg/SAM2 ports.
ml_move_boxes_to_loading_zone drained-state control flow
src/hangar_sim/objectives/ml_move_boxes_to_loading_zone.xml
Initializes drained, picked_at_wp1, picked_at_wp2 via Script; enters RepeatUnlessFailureEachTick(-1) loop computing drained := !(picked_at_wp1 || picked_at_wp2) and terminating via ScriptCondition(!drained); adds a post-loop ScriptCondition(drained) as the final outcome gate.

Kinova Sim Objective Wiring Updates

Layer / File(s) Summary
velocity_force_controller_zero explicit wiring
src/moveit_pro_kinova_configs/kinova_sim/objectives/velocity_force_controller_zero.xml
Sets _favorite=false; adds reference_frame=world to twist/wrench creation; expands SwitchController with action names, timeout, strictness, and activation flags; inserts CallTriggerService targeting /velocity_force_controller/zero_fts; adds PublishVelocityForceCommand bindings for wrench, twist, publish rate, and command topic.
write_picknik control flow and execution wiring
src/moveit_pro_kinova_configs/kinova_sim/objectives/write_picknik.xml
Inserts WaitForDuration(0.5 s) before controller switching; adds automatic_activation=true to SwitchController; adds line_color_rgb/line_width to VisualizePath; adds max_optimizer_iterations=1 to PlanCartesianPath; expands ExecuteTrajectory with goal_duration_tolerance, joint_trajectory_msg, controller_action_name, and execution_pipeline.

Submodule Pointer Updates

Layer / File(s) Summary
phoebe_ws and picknik_accessories submodule bumps
src/external_dependencies/phoebe_ws, src/picknik_accessories
Advances phoebe_ws from feb72356 to 2823ed1e and picknik_accessories from aad29fac to 3b0912dc.

Possibly related PRs

Suggested reviewers

  • JWhitleyWork

Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore (reviewers only)

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Human Review Check ❌ Error PR includes auth/secrets handling and new CI/CD infrastructure (GitHub Actions workflow) with Docker and secret usage, plus unresolved review comments on security/functional issues. This PR requires review by a requested human reviewer. After review, a non-author requested reviewer should override this pre-merge check.
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The PR description accurately describes the addition of collision_monitor integration, Layer-2 testing, configuration examples, and the GitHub Actions workflow. It aligns with the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feature/collision-monitor-integration

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/collision-monitor-integration.yaml:
- Around line 143-157: The docker run command in the colcon test execution is
losing test results because the container is being removed (--rm flag) after it
exits, making artifacts unavailable for the subsequent upload step. Add a volume
mount flag to bind the host workspace directory to the container filesystem so
that test results are accessible from the host after the container exits.
Additionally, ensure that the colcon test results are being written to a
location within the mounted volume so they persist after the container
terminates and can be collected by the artifact upload step.
- Around line 86-90: Disable credential persistence in the checkout step named
"Checkout example_ws (usage example only — NO monitor source)" by adding the
persist-credentials parameter set to false in the with block of the
actions/checkout action. This prevents unnecessary retention of Git credentials
since no git operations occur after this checkout step.

In `@src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py`:
- Around line 316-321: After the rclpy.spin_until_future_complete call completes
for the goal_future returned by _send_arm_trajectory, retrieve the goal handle
result from the future and add an assertion to verify it is not None. This
ensures that if the action server rejects the goal, the test immediately fails
with a clear assertion error rather than misattributing the failure to collision
monitoring issues later in the test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: faffd8d1-e194-4d63-bbe0-f027ecf60580

📥 Commits

Reviewing files that changed from the base of the PR and between 35b3525 and 2db1ebd.

📒 Files selected for processing (15)
  • .github/workflows/collision-monitor-integration.yaml
  • src/external_dependencies/phoebe_ws
  • src/hangar_sim/objectives/ml_move_boxes_to_loading_zone.xml
  • src/hangar_sim/objectives/move_boxes_looping.xml
  • src/hangar_sim/objectives/move_boxes_to_loading_zone_from_waypoint.xml
  • src/lab_sim_collision_monitor/CMakeLists.txt
  • src/lab_sim_collision_monitor/README.md
  • src/lab_sim_collision_monitor/config/lab_sim_collision_monitor.yaml
  • src/lab_sim_collision_monitor/launch/collision_monitor.launch.py
  • src/lab_sim_collision_monitor/package.xml
  • src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py
  • src/lab_sim_collision_monitor/test/conftest.py
  • src/moveit_pro_kinova_configs/kinova_sim/objectives/velocity_force_controller_zero.xml
  • src/moveit_pro_kinova_configs/kinova_sim/objectives/write_picknik.xml
  • src/picknik_accessories

Comment on lines +86 to +90
- name: Checkout example_ws (usage example only — NO monitor source)
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
submodules: recursive

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/collision-monitor-integration.yaml

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 8394


Disable persisted Git credentials for checkout.

This workflow does not perform any git operations after checkout (no push, pull, or clone), so persisting credentials is unnecessary security exposure.

Proposed fix
       - name: Checkout example_ws (usage example only — NO monitor source)
         uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
         with:
           submodules: recursive
+          persist-credentials: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Checkout example_ws (usage example only — NO monitor source)
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
submodules: recursive
- name: Checkout example_ws (usage example only — NO monitor source)
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
submodules: recursive
persist-credentials: false
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 86-89: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/collision-monitor-integration.yaml around lines 86 - 90,
Disable credential persistence in the checkout step named "Checkout example_ws
(usage example only — NO monitor source)" by adding the persist-credentials
parameter set to false in the with block of the actions/checkout action. This
prevents unnecessary retention of Git credentials since no git operations occur
after this checkout step.

Source: Linters/SAST tools

Comment on lines +143 to +157
docker run --rm \
-e MOVEIT_CONFIG_PACKAGE=lab_sim \
-e MOVEIT_LICENSE_KEY="${MOVEIT_LICENSE_KEY}" \
-e MUJOCO_CI_TIMESTEP=0.003 \
"${BUNDLE_IMAGE}" \
bash -lc '
set -euo pipefail
source /opt/ros/humble/setup.bash
source "${USER_WS}/install/setup.bash"
colcon test \
--packages-select lab_sim_collision_monitor \
--executor sequential \
--event-handlers console_direct+
colcon test-result --verbose
'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd /tmp && find . -name "collision-monitor-integration.yaml" -type f 2>/dev/null | head -5

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 63


🏁 Script executed:

# First, let's locate the workflow file in the repository
git ls-files | grep -i collision-monitor-integration

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 134


🏁 Script executed:

# Get the workflow file and examine it around the specified lines
cat -n .github/workflows/collision-monitor-integration.yaml | sed -n '130,175p'

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 1842


Add volume mount and copy test results from container to host filesystem.

Test results written inside the container during colcon test are lost when docker run --rm exits, so the artifact upload step has nothing to collect. Bind mount the host workspace and copy results out after test completion.

Proposed fix
       - name: Run the Layer-2 parallel-monitor test
         env:
           BUNDLE_IMAGE: lab-sim-with-monitor:ci
           MOVEIT_LICENSE_KEY: ${{ secrets.STUDIO_CI_LICENSE_KEY }}
         run: |
           set -euo pipefail
+          mkdir -p build/lab_sim_collision_monitor/test_results log/latest_test
           # Headless, license-keyed run of lab_sim + the licensed monitor.
           # Coarsen the MuJoCo timestep on CI (matches ci.yaml) so the heavier
           # 3.6.0 solver stays at-or-under realtime on the runner.
           docker run --rm \
+            -v "${PWD}:/host_ws" \
             -e MOVEIT_CONFIG_PACKAGE=lab_sim \
             -e MOVEIT_LICENSE_KEY="${MOVEIT_LICENSE_KEY}" \
             -e MUJOCO_CI_TIMESTEP=0.003 \
             "${BUNDLE_IMAGE}" \
             bash -lc '
               set -euo pipefail
               source /opt/ros/humble/setup.bash
               source "${USER_WS}/install/setup.bash"
               colcon test \
                 --packages-select lab_sim_collision_monitor \
                 --executor sequential \
                 --event-handlers console_direct+
               colcon test-result --verbose
+              cp -r "${USER_WS}/build/lab_sim_collision_monitor/test_results/." \
+                /host_ws/build/lab_sim_collision_monitor/test_results/ || true
+              cp -r "${USER_WS}/log/latest_test/." /host_ws/log/latest_test/ || true
             '

Also applies to: 159-167

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/collision-monitor-integration.yaml around lines 143 - 157,
The docker run command in the colcon test execution is losing test results
because the container is being removed (--rm flag) after it exits, making
artifacts unavailable for the subsequent upload step. Add a volume mount flag to
bind the host workspace directory to the container filesystem so that test
results are accessible from the host after the container exits. Additionally,
ensure that the colcon test results are being written to a location within the
mounted volume so they persist after the container terminates and can be
collected by the artifact upload step.

Comment on lines +316 to +321
goal_future = _send_arm_trajectory(
monitor_probe.node, SELF_COLLISION_POSE, move_time_s=4.0
)
rclpy.spin_until_future_complete(
monitor_probe.node, goal_future, timeout_sec=30.0
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check the file and read the specific lines
wc -l src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 158


🏁 Script executed:

# Read the target lines with context
sed -n '310,330p' src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 896


🏁 Script executed:

# Find the _send_arm_trajectory function definition
rg "_send_arm_trajectory" src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py -B 2 -A 10

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 1131


🏁 Script executed:

# Search for patterns of goal_handle usage and goal acceptance checks in the test file
rg "goal_handle|\.accepted|\.result()" src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 63


🏁 Script executed:

# Get the full _send_arm_trajectory implementation
rg "_send_arm_trajectory" src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py -A 25

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 2208


🏁 Script executed:

# Search for any goal acceptance validation patterns in the entire test file
rg "accepted|goal_handle" src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 63


🏁 Script executed:

# Check what type of future is returned and how it's used elsewhere
sed -n '1,100p' src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py | head -50

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 2920


🏁 Script executed:

# Search for other uses of send_goal_async in test files to see if goal acceptance is validated elsewhere
rg "send_goal_async|goal_handle|\.accepted" src/lab_sim_collision_monitor/test/ -B 2 -A 3

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 635


🏁 Script executed:

# Check if there are other integration tests that might validate goal acceptance
find src/lab_sim_collision_monitor/test -name "*.py" -type f

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 201


🏁 Script executed:

# Look for FollowJointTrajectory usage patterns in the codebase
rg "FollowJointTrajectory|ActionClient.*FollowJointTrajectory" --type py -B 2 -A 8

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 3143


🏁 Script executed:

# Check if goal_handle.result() is called or used anywhere after the spin_until_future_complete
sed -n '316,350p' src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 1303


🏁 Script executed:

# Look for patterns of goal validation in other ROS 2 action client code in the repo
rg "goal_future|send_goal_async" src/ -B 2 -A 5 --type py | head -60

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 2076


🏁 Script executed:

# Verify the ROS 2 ActionClient API - check what send_goal_async returns
web_search ROS 2 ActionClient send_goal_async goal_handle future API documentation

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 132


🏁 Script executed:

# Check the actual behavior - read more of the context around the test
sed -n '290,350p' src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 2209


🏁 Script executed:

# Check if there's documentation or examples in the codebase about goal handle validation
rg "goal_handle\|\.accepted" src/ --type py -B 1 -A 1

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 63


🏁 Script executed:

# Look at the test structure more broadly - how does the test detect failures
sed -n '300,360p' src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 1930


🏁 Script executed:

# Check ROS 2 rclpy ActionClient behavior by looking at imports and usage
head -50 src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py | grep -E "import|from"

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 158


🏁 Script executed:

# Get the full imports section
sed -n '1,80p' src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py | grep -E "^import|^from"

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 911


🏁 Script executed:

# Search for ActionClient import
rg "ActionClient" src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 186


🏁 Script executed:

# Let's check the ROS 2 documentation about send_goal_async by looking for related patterns
web_search
ROS 2 rclpy ActionClient send_goal_async returns GoalHandle future accepted

Repository: PickNikRobotics/moveit_pro_example_ws

Length of output: 174


🌐 Web query:

ROS 2 rclpy ActionClient send_goal_async GoalHandle future accepted API

💡 Result:

In ROS 2, the rclpy ActionClient's send_goal_async method is used to send a goal to an action server asynchronously [1][2]. It returns a Future object that completes when the action server acknowledges the request (either by accepting or rejecting it) [1][3]. When the future completes, its result is a ClientGoalHandle instance [1][2]. You can check if the goal was successfully accepted by the action server by accessing the accepted property on this ClientGoalHandle [1][3][4]. Example usage: def goal_response_callback(self, future): goal_handle = future.result if not goal_handle.accepted: self.get_logger.info('Goal rejected') return self.get_logger.info('Goal accepted') # Proceed to get result or monitor progress via goal_handle [5][6] Key points: - Return Type: send_goal_async returns an rclpy.task.Future [1][7]. - Future Resolution: The future resolves to a ClientGoalHandle [1][2]. - Acceptance Check: Use goal_handle.accepted (a boolean) to verify if the server accepted the goal [3][4]. - Workflow: Typically, you add a callback to the future using add_done_callback to handle the response once the server processes the request [4][5].

Citations:


Assert the trajectory goal is accepted before waiting for trip.

If this goal is rejected by the controller, the test failure is misattributed to collision monitoring instead of action server rejection. The goal_future completes when the action server responds with acceptance or rejection, but the code never retrieves or validates the result. Validate the goal handle immediately after spin_until_future_complete() returns.

Proposed fix
     goal_future = _send_arm_trajectory(
         monitor_probe.node, SELF_COLLISION_POSE, move_time_s=4.0
     )
     rclpy.spin_until_future_complete(
         monitor_probe.node, goal_future, timeout_sec=30.0
     )
+    goal_handle = goal_future.result()
+    assert goal_handle is not None and goal_handle.accepted, (
+        "Self-collision trajectory goal was rejected by joint_trajectory_controller."
+    )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lab_sim_collision_monitor/test/collision_monitor_integration_test.py`
around lines 316 - 321, After the rclpy.spin_until_future_complete call
completes for the goal_future returned by _send_arm_trajectory, retrieve the
goal handle result from the future and add an assertion to verify it is not
None. This ensures that if the action server rejects the goal, the test
immediately fails with a clear assertion error rather than misattributing the
failure to collision monitoring issues later in the test.

@JWhitleyWork

Copy link
Copy Markdown
Member

This needs a fresh rebase on main.

@shaur-k shaur-k marked this pull request as draft June 19, 2026 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants