Skip to content

Fix flaky spline interpolation test - #556

Open
URJala wants to merge 9 commits into
UniversalRobots:masterfrom
URJala:fix_flaky_spline_interpolation_test
Open

Fix flaky spline interpolation test#556
URJala wants to merge 9 commits into
UniversalRobots:masterfrom
URJala:fix_flaky_spline_interpolation_test

Conversation

@URJala

@URJala URJala commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Made new method: sendTrajectoryAndConfirmStart which launches an async thread to confirm that a new trajectory resets the spline_travel_time and then starts executing. This is more robust than the previous implementation.

I have replaced all the calls to sendTrajectory where they were immediately followed by waitForTrajectoryStarted, with one call to sendTrajectoryAndConfirmStart. waitForTrajectoryStarted is no longer used, but I havent removed it yet.


Note

Low Risk
Test-only changes in integration tests; no production library behavior modified beyond how tests call existing driver APIs.

Overview
Hardens spline integration tests so they wait for a new trajectory to be accepted and actually running, not just a momentary zero in spline_travel_time.

Adds sendTrajectoryAndConfirmStart, which starts an async confirmTrajectoryStarted loop on RTDE output_double_register_1 before sending points. That thread checks that travel time resets (drops or goes to zero), then that it increases again after upload—sending TRAJECTORY_NOOP from the background thread while the main thread streams the spline. Tests that used sendTrajectory + waitForTrajectoryStarted now ASSERT_TRUE(sendTrajectoryAndConfirmStart(...)) and set g_trajectory_running from the helper’s result.

sendTrajectory now passes RobotReceiveTimeout::off() on TRAJECTORY_START. waitForTrajectoryStarted remains in the file but is unused; its start check was tightened to std::abs(spline_travel_time) < 0.01.

Reviewed by Cursor Bugbot for commit 12d787e. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI balanced review requested due to automatic review settings August 19, 2026 13:55
@codecov

codecov Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.27%. Comparing base (dde4869) to head (12d787e).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #556      +/-   ##
==========================================
- Coverage   80.46%   80.27%   -0.19%     
==========================================
  Files         116      116              
  Lines        6976     6975       -1     
  Branches     3083     3083              
==========================================
- Hits         5613     5599      -14     
- Misses        984      992       +8     
- Partials      379      384       +5     
Flag Coverage Δ
check_version_ur10-3.15.8 11.50% <ø> (-1.48%) ⬇️
check_version_ur10e-10.11.0 11.55% <ø> (ø)
check_version_ur10e-5.15.2 11.50% <ø> (-0.63%) ⬇️
check_version_ur12e-10.12.1 11.50% <ø> (-0.05%) ⬇️
check_version_ur12e-5.25.1 12.31% <ø> (+0.33%) ⬆️
check_version_ur15-10.12.1 11.50% <ø> (-0.05%) ⬇️
check_version_ur15-5.25.1 11.70% <ø> (-0.05%) ⬇️
check_version_ur16e-10.12.1 11.50% <ø> (-0.05%) ⬇️
check_version_ur16e-5.25.1 11.70% <ø> (-0.32%) ⬇️
check_version_ur18-10.12.1 11.50% <ø> (-0.05%) ⬇️
check_version_ur18-5.25.1 11.52% <ø> (-0.23%) ⬇️
check_version_ur20-10.12.1 11.50% <ø> (ø)
check_version_ur20-5.25.1 11.70% <ø> (ø)
check_version_ur3-3.14.3 12.12% <ø> (-0.89%) ⬇️
check_version_ur30-10.12.1 11.50% <ø> (ø)
check_version_ur30-5.25.1 11.70% <ø> (+0.15%) ⬆️
check_version_ur3e-10.11.0 11.50% <ø> (-0.05%) ⬇️
check_version_ur3e-5.9.4 11.50% <ø> (-0.05%) ⬇️
check_version_ur5-3.15.8 11.50% <ø> (-1.81%) ⬇️
check_version_ur5e-10.11.0 11.50% <ø> (-0.10%) ⬇️
check_version_ur5e-5.12.8 11.70% <ø> (-0.10%) ⬇️
check_version_ur7e-10.11.0 11.50% <ø> (ø)
check_version_ur7e-5.22.2 11.70% <ø> (ø)
check_version_ur8long-10.12.1 11.50% <ø> (-0.05%) ⬇️
check_version_ur8long-5.25.1 11.55% <ø> (-0.20%) ⬇️
python_scripts 75.90% <ø> (ø)
start_ursim 84.91% <ø> (-1.69%) ⬇️
ur20-latest 75.49% <ø> (-0.16%) ⬇️
ur5-3.14.3 75.46% <ø> (-0.02%) ⬇️
ur5e-10.11.0 70.22% <ø> (-0.08%) ⬇️
ur5e-10.12.0 71.20% <ø> (-0.08%) ⬇️
ur5e-10.7.0 69.30% <ø> (-0.37%) ⬇️
ur5e-5.9.4 75.77% <ø> (-0.16%) ⬇️
ur7e-10.13.0 71.89% <ø> (-0.17%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

Copilot AI 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.

Pull request overview

Improves spline interpolation integration-test reliability by monitoring trajectory startup concurrently with upload.

Changes:

  • Adds asynchronous trajectory-start confirmation.
  • Replaces separate send/wait calls with the combined helper.
  • Adds synchronization state for the watcher.
Suppressed comments (1)

tests/test_spline_interpolation.cpp:332

  • Correct the spelling of “Continously” to “Continuously”.
      // Continously check spline travel time

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/test_spline_interpolation.cpp
Comment thread tests/test_spline_interpolation.cpp
Copilot AI review requested due to automatic review settings August 19, 2026 14:04

Copilot AI 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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

tests/test_spline_interpolation.cpp:333

  • Correct the spelling of “Continously” in this new comment.
      // Continously check spline travel time

Comment thread tests/test_spline_interpolation.cpp Outdated
Comment on lines +213 to +214
// Wait for trajectory to start (should be quick)
if (confirm_future.wait_for(std::chrono::milliseconds(500)) != std::future_status::ready)
Copilot AI review requested due to automatic review settings August 20, 2026 07:11

Copilot AI 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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Suppressed comments (2)

tests/test_spline_interpolation.cpp:217

  • This 500 ms deadline preempts the helper's own 1-second start/reset timeouts, so a valid start that takes 500–1000 ms is forcibly stopped and reported as a failure. That shortens the previous test tolerance and can preserve the flakiness this change is intended to remove; make the outer deadline longer than the internal timeout.
    if (confirm_future.wait_for(std::chrono::milliseconds(500)) != std::future_status::ready)

tests/test_spline_interpolation.cpp:336

  • Correct the spelling of “Continously” to “Continuously.”
      // Continously check spline travel time

Copilot AI review requested due to automatic review settings August 20, 2026 07:26

Copilot AI 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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Suppressed comments (2)

tests/test_spline_interpolation.cpp:336

  • Correct the spelling of “Continuously.”
      // Continously check spline travel time

tests/test_spline_interpolation.cpp:342

  • This reset can be observed before sendTrajectory() has sent the new TRAJECTORY_START. Moreover, splineTimerTraveled resets for every spline segment (resources/external_control.urscript:402-404), so an existing trajectory crossing a segment boundary can set this flag and later satisfy the > 0.002 check even if the new trajectory was not accepted. Use a separate signal set immediately after sending the new START command, and only treat resets observed after that signal as confirmation; trajectory_sent is too late because it is set after all points are uploaded.
      if (spline_travel_time < start_spline_travel_time || spline_travel_time == 0.0)
      {
        spline_travel_time_reset = true;
      }

Copilot AI review requested due to automatic review settings August 20, 2026 09:02
Comment thread tests/test_spline_interpolation.cpp Outdated

Copilot AI 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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Suppressed comments (1)

tests/test_spline_interpolation.cpp:350

  • When the register is initially 0.0, spline_travel_time_reset becomes true before the upload starts, so this worker may send a NOOP concurrently with sendTrajectory() sending its NOOP/START messages. The reverse socket write path does not serialize concurrent writes, which can reorder or interleave control frames and reintroduce flakiness. Gate this keepalive on the existing trajectory_sent flag (or otherwise serialize all reverse-interface writes).
        if (!g_my_robot->getUrDriver()->writeTrajectoryControlMessage(
                urcl::control::TrajectoryControlMessage::TRAJECTORY_NOOP))

Copilot AI review requested due to automatic review settings August 20, 2026 09:34

Copilot AI 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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Suppressed comments (1)

tests/test_spline_interpolation.cpp:327

  • When the pre-send travel time is already 0.0 (notably on the first test after startup), the worker only considers the reset observed if it receives another zero-valued RTDE package after notifying the sender. If the sender starts the spline before that next package, the first value can already be positive, so the loop never sets this flag and falsely times out. Treat the zero baseline already sampled immediately before signaling readiness as the reset state, then wait for the timer to advance.
    bool spline_travel_time_reset = false;

@URJala
URJala requested a review from urfeex August 20, 2026 10:19
}

// Confirm that the new trajectory is running
if (std::abs(spline_travel_time) > start_spline_travel_time)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Wouldn't this be problematic when there was a long trajectory running beforehand? I don't remember by hard when we reset the spline_travel_time, but it seems fragile to rely on it being small in the beginning. Once it has been reset, being larger than a reasonable threshold should be sufficient, right?

@URJala URJala Aug 25, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It only gets to this stage if we have seen that it is either zero, or at least has become smaller (where start_spline_travel_time is reset), and then we check that it advances one timestep.

Comment thread tests/test_spline_interpolation.cpp Outdated
waitForTrajectoryStarted();
ASSERT_TRUE(sendTrajectoryAndConfirmStart(s_pos, s_vel, std::vector<urcl::vector6d_t>(), s_time));

g_trajectory_running = true;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could probably set this inside sendTrajectoryAndConfirmStart, right?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes, I think we could

Comment thread tests/test_spline_interpolation.cpp Outdated
URJala and others added 6 commits August 25, 2026 08:19
Made new method: sendTrajectoryAndConfirmStart which launches an async thread to confirm that a new trajectory resets the spline_travel_time and then starts executing. This is more robust than the previous implementation.

I have replaced all the calls to sendTrajectory where they were immediately followed by waitForTrajectoryStarted, with one call to sendTrajectoryAndConfirmStart.
waitForTrajectoryStarted is no longer used, but I havent removed it yet.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Also add debug messages when failing
Also make reverse socket read blocking
Copilot AI review requested due to automatic review settings August 25, 2026 08:36
@URJala
URJala force-pushed the fix_flaky_spline_interpolation_test branch from 4e94127 to 4704c98 Compare August 25, 2026 08:36

Copilot AI 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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comment on lines +227 to +228
bool trajectory_running = confirm_future.get();
g_trajectory_running = trajectory_running;

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 4704c98. Configure here.

{
g_trajectory_running = true;
return true;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fragile travel-time start detection

Medium Severity

confirmTrajectoryStarted treats a new trajectory as started only after spline_travel_time drops below the sampled baseline (or hits exactly 0.0), then advances past that updated baseline. jointSplineRun increments before the first register write, so a new segment often starts at about one step time, never writing 0.0. If a prior trajectory was only briefly running and the baseline is already near that same small value, the drop is never observed and confirmation times out. That is especially likely for back-to-back sendTrajectoryAndConfirmStart calls.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4704c98. Configure here.

Copilot AI review requested due to automatic review settings August 25, 2026 08:44

Copilot AI 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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

tests/test_spline_interpolation.cpp:346

  • This can confirm the old trajectory instead of the one just sent. The monitor starts before TRAJECTORY_START, and spline_travel_time resets at every spline segment, so a segment boundary in an already-running trajectory can satisfy this reset check and the subsequent increase can return true before the new start message is processed. Gate the reset/start state machine on an explicit signal emitted immediately after this helper successfully writes the new TRAJECTORY_START message; trajectory_sent currently only controls NOOP writes and does not prevent the false positive.
      // Confirm that a new trajectory was transferred (Travel time = 0.0 or lower than it was before)
      if (spline_travel_time < start_spline_travel_time || spline_travel_time == 0.0)

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.

3 participants