|
| 1 | +:github_url: https://github.com/UniversalRobots/Universal_Robots_Client_Library/blob/master/doc/examples/trajectory_streaming.rst |
| 2 | + |
| 3 | +.. _trajectory_streaming_example: |
| 4 | + |
| 5 | +Trajectory streaming example |
| 6 | +============================ |
| 7 | + |
| 8 | +This example demonstrates open-ended *trajectory streaming*: a producer sends points to the |
| 9 | +controller without declaring a total point count up front, then signals end-of-stream when it is |
| 10 | +finished. Contrast this with the :ref:`trajecotry_joint_interface_example`, which uses the finite |
| 11 | +trajectory path where the point count is fixed in the initial ``TRAJECTORY_START`` message. |
| 12 | + |
| 13 | +The streaming communication contract -- the ``STREAM_START`` / ``STREAM_END`` handshake, the meaning |
| 14 | +of the end-of-stream point count, the producer's obligation not to starve the controller, and the |
| 15 | +trajectory result codes -- is described in :ref:`streaming_trajectories`. This page walks through the |
| 16 | +example code and refers back to that section for the authoritative contract. |
| 17 | + |
| 18 | +Setup |
| 19 | +----- |
| 20 | + |
| 21 | +As with the other examples, we create a ``UrDriver`` (here through ``ExampleRobotWrapper``) and |
| 22 | +register a callback that fires when a trajectory finishes: |
| 23 | + |
| 24 | +.. literalinclude:: ../../examples/trajectory_streaming.cpp |
| 25 | + :language: c++ |
| 26 | + :caption: examples/trajectory_streaming.cpp |
| 27 | + :linenos: |
| 28 | + :lineno-match: |
| 29 | + :start-at: const bool headless_mode = true; |
| 30 | + :end-before: // --------------- PRE-POSITION VIA FINITE TRAJECTORY |
| 31 | + |
| 32 | +Trajectory execution is asynchronous, so completion is reported through a callback. The result |
| 33 | +distinguishes a successful run from a cancellation or a failure: |
| 34 | + |
| 35 | +.. literalinclude:: ../../examples/trajectory_streaming.cpp |
| 36 | + :language: c++ |
| 37 | + :caption: examples/trajectory_streaming.cpp |
| 38 | + :linenos: |
| 39 | + :lineno-match: |
| 40 | + :start-at: void trajDoneCallback |
| 41 | + :end-at: } |
| 42 | + |
| 43 | +While a trajectory runs, the control PC must keep telling the robot program that the connection is |
| 44 | +still alive. We do this by sending ``TRAJECTORY_NOOP`` messages while we wait; without them the robot |
| 45 | +program stops waiting for input and the ``external_control`` program exits: |
| 46 | + |
| 47 | +.. literalinclude:: ../../examples/trajectory_streaming.cpp |
| 48 | + :language: c++ |
| 49 | + :caption: examples/trajectory_streaming.cpp |
| 50 | + :linenos: |
| 51 | + :lineno-match: |
| 52 | + :start-at: // Pump TRAJECTORY_NOOP |
| 53 | + :end-before: // Sample a quintic-Hermite |
| 54 | + |
| 55 | +Generating a motion |
| 56 | +------------------- |
| 57 | + |
| 58 | +To have something to stream, we sample a quintic-Hermite blend between two joint configurations. The |
| 59 | +blend has zero velocity and acceleration at both endpoints, which -- as the streaming contract |
| 60 | +recommends -- gives the final point the controlled-stop property needed to bring the robot cleanly to |
| 61 | +rest: |
| 62 | + |
| 63 | +.. literalinclude:: ../../examples/trajectory_streaming.cpp |
| 64 | + :language: c++ |
| 65 | + :caption: examples/trajectory_streaming.cpp |
| 66 | + :linenos: |
| 67 | + :lineno-match: |
| 68 | + :start-at: // Sample a quintic-Hermite |
| 69 | + :end-before: int main( |
| 70 | + |
| 71 | +Pre-positioning |
| 72 | +--------------- |
| 73 | + |
| 74 | +Before streaming, we park the robot at a known start pose using an ordinary finite trajectory. This |
| 75 | +doubles as a demonstration of the ``TRAJECTORY_START`` path for comparison: |
| 76 | + |
| 77 | +.. literalinclude:: ../../examples/trajectory_streaming.cpp |
| 78 | + :language: c++ |
| 79 | + :caption: examples/trajectory_streaming.cpp |
| 80 | + :linenos: |
| 81 | + :lineno-match: |
| 82 | + :start-after: // --------------- PRE-POSITION VIA FINITE TRAJECTORY |
| 83 | + :end-before: // ----------------- STREAMING TRAJECTORY DEMO |
| 84 | + |
| 85 | +Streaming the trajectory |
| 86 | +------------------------ |
| 87 | + |
| 88 | +We precompute all of the points up front. The final point inherits the ``qd = 0``, ``qdd = 0`` |
| 89 | +boundary condition of the quintic blend, so it is a compliant controlled-stop terminal: |
| 90 | + |
| 91 | +.. literalinclude:: ../../examples/trajectory_streaming.cpp |
| 92 | + :language: c++ |
| 93 | + :caption: examples/trajectory_streaming.cpp |
| 94 | + :linenos: |
| 95 | + :lineno-match: |
| 96 | + :start-after: // ----------------- STREAMING TRAJECTORY DEMO |
| 97 | + :end-before: URCL_LOG_INFO("Streaming %d points |
| 98 | + |
| 99 | +The stream itself is the ``STREAM_START`` -> points -> ``STREAM_END`` handshake. We open the stream, |
| 100 | +write every point back-to-back, then close it, passing the total number of points written so the |
| 101 | +controller knows how many are still outstanding before it reports completion: |
| 102 | + |
| 103 | +.. literalinclude:: ../../examples/trajectory_streaming.cpp |
| 104 | + :language: c++ |
| 105 | + :caption: examples/trajectory_streaming.cpp |
| 106 | + :linenos: |
| 107 | + :lineno-match: |
| 108 | + :start-at: URCL_LOG_INFO("Streaming %d points |
| 109 | + :end-before: g_my_robot->getUrDriver()->stopControl(); |
| 110 | + |
| 111 | +Because this example delivers the whole motion up front, it can never starve the controller: all the |
| 112 | +work is in hand before execution finishes, so the robot simply plays through it. The example also |
| 113 | +measures the time from sending ``STREAM_END`` to the trajectory-done callback. That time is large |
| 114 | +here, but not because ending a stream is costly: the producer sends every point and then |
| 115 | +``STREAM_END`` within milliseconds, long before the robot has finished moving, so the callback cannot |
| 116 | +fire until the robot has worked through the entire backlog. A producer that instead fed points in step |
| 117 | +with the robot's motion would send ``STREAM_END`` just as the robot reached the final point, and the |
| 118 | +callback would follow almost immediately. |
| 119 | + |
| 120 | +For the general case, where points are produced on the fly and pacing does matter, see the producer |
| 121 | +obligations in :ref:`streaming_trajectories`. |
0 commit comments