Skip to content

Add tests demonstrating failure to recover from stream starvation - #552

Open
acmorrow wants to merge 5 commits into
UniversalRobots:masterfrom
acmorrow:gh-550-streaming-starvation-recovery-tests
Open

Add tests demonstrating failure to recover from stream starvation#552
acmorrow wants to merge 5 commits into
UniversalRobots:masterfrom
acmorrow:gh-550-streaming-starvation-recovery-tests

Conversation

@acmorrow

@acmorrow acmorrow commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Hi @urrsk -

This PR, which I'm opening as a draft because some of the tests are currently failing, demonstrates the failure to correctly recover to a valid state after starving the arm of points during a streaming move.

There are also some new tests that currently pass, acting as controls/validation for existing behavior. They came into being as I was validating my understanding of the urscript behavior. But they seem like worthwhile tests on their own, and useful to prevent regressions. Easy enough to drop them if you just want the failing tests.


Note

High Risk
Breaking wire/API change (3.x) requires library and bundled URScript to upgrade together; changes real-time trajectory execution and recovery paths on the robot.

Overview
Introduces a per-move identifier on the trajectory/reverse-socket protocol so the robot can ignore stale trajectory points after a stream fails, is cancelled, or a producer keeps writing briefly. Trajectory records grow from 21 to 22 int32 fields; trajectory start messages on the reverse socket now carry move_id (formerly padding). UrDriver increments and assigns IDs on TRAJECTORY_START / TRAJECTORY_STREAM_START; TrajectoryPointInterface::setMoveId() stamps each outgoing point. writeTrajectoryControlMessage() gains a required move_id argument (documented as a 3.x breaking change in migration notes).

On the robot, external_control.urscript tracks trajectory_move_id, skips mismatched points in trajectoryThread, drains full records in cleanup, and on mid-stream underrun clears trajectory_streaming and trajectory_points_left so the next move is not blocked by STREAMING_SENTINEL cleanup (issue #550).

Adds unit tests for wire encoding of move IDs and broad integration tests for streaming gaps, underrun recovery (finite and stream), stale points after underrun, and cancel-with-understated count—with RTDE joint checks where motion must be verified.

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

@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.50%. Comparing base (a854de9) to head (4aaffdf).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #552      +/-   ##
==========================================
+ Coverage   78.85%   79.50%   +0.65%     
==========================================
  Files         116      116              
  Lines        7632     6978     -654     
  Branches     3153     3084      -69     
==========================================
- Hits         6018     5548     -470     
+ Misses       1224     1050     -174     
+ Partials      390      380      -10     
Flag Coverage Δ
check_version_ur10-3.15.8 11.73% <0.00%> (-0.99%) ⬇️
check_version_ur10e-10.11.0 11.49% <0.00%> (-0.13%) ⬇️
check_version_ur10e-5.15.2 11.49% <0.00%> (-1.22%) ⬇️
check_version_ur12e-10.12.1 11.53% <0.00%> (-0.08%) ⬇️
check_version_ur12e-5.25.1 11.49% <0.00%> (-0.23%) ⬇️
check_version_ur15-10.12.1 11.49% <0.00%> (-0.13%) ⬇️
check_version_ur15-5.25.1 11.68% <0.00%> (-0.03%) ⬇️
check_version_ur16e-10.12.1 11.49% <0.00%> (-0.13%) ⬇️
check_version_ur16e-5.25.1 11.49% <0.00%> (-0.47%) ⬇️
check_version_ur18-10.12.1 11.49% <0.00%> (-0.05%) ⬇️
check_version_ur18-5.25.1 11.49% <0.00%> (-0.27%) ⬇️
check_version_ur20-10.12.1 11.49% <0.00%> (-0.13%) ⬇️
check_version_ur20-5.25.1 11.68% <0.00%> (-0.58%) ⬇️
check_version_ur3-3.14.3 11.53% <0.00%> (-0.65%) ⬇️
check_version_ur30-10.12.1 11.53% <0.00%> (-0.08%) ⬇️
check_version_ur30-5.25.1 11.49% <0.00%> (-0.57%) ⬇️
check_version_ur3e-10.11.0 11.49% <0.00%> (-0.13%) ⬇️
check_version_ur3e-5.9.4 11.68% <0.00%> (-0.43%) ⬇️
check_version_ur5-3.15.8 11.49% <0.00%> (-0.45%) ⬇️
check_version_ur5e-10.11.0 11.49% <0.00%> (-0.09%) ⬇️
check_version_ur5e-5.12.8 11.49% <0.00%> (-0.61%) ⬇️
check_version_ur7e-10.11.0 11.49% <0.00%> (-0.09%) ⬇️
check_version_ur7e-5.22.2 11.49% <0.00%> (-0.31%) ⬇️
check_version_ur8long-10.12.1 11.49% <0.00%> (-0.13%) ⬇️
check_version_ur8long-5.25.1 11.68% <0.00%> (-0.58%) ⬇️
python_scripts 75.90% <ø> (ø)
start_ursim 85.95% <ø> (-0.39%) ⬇️
ur20-latest 75.46% <100.00%> (-0.12%) ⬇️
ur5-3.14.3 75.39% <100.00%> (-0.17%) ⬇️
ur5e-10.11.0 70.08% <100.00%> (+0.18%) ⬆️
ur5e-10.12.0 71.16% <100.00%> (-0.13%) ⬇️
ur5e-10.7.0 69.43% <100.00%> (+0.14%) ⬆️
ur5e-5.9.4 ?
ur7e-10.13.0 71.22% <100.00%> (+0.12%) ⬆️

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.

@urrsk urrsk self-assigned this Aug 12, 2026
Comment thread tests/test_trajectory_streaming.cpp Outdated
// Stop writing to the trajectory socket for 500ms while the thread consumes
// what we already sent. We keep answering the reverse interface with NOOPs so
// that only the trajectory socket goes quiet.
for (int i = 0; i < 10; ++i)

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.

Maybe sleep slightly shorter than 0.5 sec as this is exactly the timeout define on the robot, to avoid unstable test and the time what is used to compare here might run on different computers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sure, that's reasonable. I'll cut it to 400ms.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

@acmorrow

Copy link
Copy Markdown
Contributor Author

@urrsk - I've pushed a possible solution to cleanup after starvation based on adding an id to points in a move. I followed up on your comment in #550 to discuss some of the ways my approach differs from your notes. Definitely interested to see what you think of this. It does seem to make the newly introduced tests go green, so that's a good start.

@acmorrow
acmorrow marked this pull request as ready for review August 12, 2026 13:30
@acmorrow
acmorrow requested a review from urrsk August 15, 2026 02:13
@acmorrow

Copy link
Copy Markdown
Contributor Author

Hi @urrsk - Just checking in on this PR. Generally, does it seem like a viable approach? Can the wire protocol change be accepted? Please let me know if there is anything you need from me in order to help move a fix for this issue forward, whether under this mechanism or some other that you would prefer. I'm happy to rework it if needed.

@urfeex

urfeex commented Aug 19, 2026

Copy link
Copy Markdown
Member

Without having dived into the details too much, it is obvious that this PR would require a major version bump. We do have a couple of things in mind that we want to change with the next major bump, so it might be reasonable to start preparing a 3.x on a new branch where this could potentially get merged to. Would you agree @urrsk ?

@acmorrow

Copy link
Copy Markdown
Contributor Author

Without having dived into the details too much, it is obvious that this PR would require a major version bump. We do have a couple of things in mind that we want to change with the next major bump, so it might be reasonable to start preparing a 3.x on a new branch where this could potentially get merged to. Would you agree @urrsk ?

@urfeex that plan makes sense to me. For now, we will probably work against this PR for our stuff since it fixes a real use case for us.

@urfeex urfeex added this to the Release 2.15.0 milestone Sep 2, 2026
Comment thread include/ur_client_library/control/reverse_interface.h Outdated
Comment thread tests/test_trajectory_streaming.cpp Outdated
// Stop writing to the trajectory socket for 500ms while the thread consumes
// what we already sent. We keep answering the reverse interface with NOOPs so
// that only the trajectory socket goes quiet.
for (int i = 0; i < 10; ++i)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread doc/migration_notes.rst

It contains only breaking changes.

Migrating from 2.x.x to 3.x.x

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@urfeex - Wanted to call this to your attention, since I note that you tagged this into the 2.15 version. This was speculative that the major version would bump with the wire, so if that isn't true, this should be reverted.

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'll make a decision today when to include this. I've merely added it to the milestone so that I don't make a release without considering this beforehand. Most likely, this will indeed go to a 3.x release, though.

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.

I've moved it to a 2.15.1 milestone. We think that we can do this without an API breaking change (I will make a review about this later).

The wire-breaking changes are acceptable, since we consider the communication between the script code and the library an internal asset. We'll add a clear statement about this, separately. We have been doing wire-breaking changes in the past, as well.

@urfeex urfeex modified the milestones: Release 2.15.0, Release 2.15.1 Sep 3, 2026

@urfeex urfeex left a comment

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.

If we avoid doing API breakages here, we can merge this onto 2.x. Please also remove the migration text in that case.

// every point written within them. It issues one identifier for each command that begins a move,
// and never reuses one for the life of a connection. A value of 0 belongs to no move, and is what
// the robot holds before it has been told about any.
std::atomic<int32_t> trajectory_move_id_ = { 0 };

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.

Could we move this to the ReverseInterface, instead? This way we would not need to expose it on the ReverseInterface's writeTrajectoryControlMessage() at all and remove the API break of this PR.


- field 1: Trajectory control mode (1: TRAJECTORY_MODE_RECEIVE, 2: TRAJECTORY_MODE_STREAM_START, 3: TRAJECTORY_MODE_STREAM_END, -1: TRAJECTORY_MODE_CANCEL). See :ref:`streaming_trajectories` for the streaming modes.
- field 2: Trajectory point count. Its interpretation depends on the control mode in field 1.
- field 3: The identifier of the move that is being started, for the two control modes which start one. The robot adopts this identifier and then executes only those trajectory points which carry it, and that is what prevents points left over from a move that has already ended from running as part of the next one. The remaining control modes do not start a move, and the robot ignores the field for them. See :ref:`trajectory_point_interface` for the point record which carries the identifier back.

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.

One way to avoid wire-breaking here, would be to re-use the ScriptReader::isVariableRegistered(const std::string& key) function introduced in 01292bd.

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