Instruction Executor example
This example shows how to use the Instruction Executor class. It can be used for easily executing a sequence of instructions such as motions on the robot using the built-in URScript functions.
The instruction_executor.cpp shows how to use this class:
Note
For the instruciton executor to work there has to be an established connection to the ReverseInterface. That means, the respective program has to be running on the robot. The example below will do that automatically, if the connected robot is in remote_control mode.
61 bool headless_mode = true;
62 g_my_robot = std::make_unique<urcl::ExampleRobotWrapper>(robot_ip, OUTPUT_RECIPE, INPUT_RECIPE, headless_mode,
63 "external_control.urp");
64 if (!g_my_robot->getUrDriver()->checkCalibration(CALIBRATION_CHECKSUM))
65 {
66 URCL_LOG_ERROR("Calibration checksum does not match actual robot.");
67 URCL_LOG_ERROR("Use the ur_calibration tool to extract the correct calibration from the robot and pass that into "
68 "the description. See "
69 "[https://github.com/UniversalRobots/Universal_Robots_ROS_Driver#extract-calibration-information] "
70 "for details.");
71 }
72 if (!g_my_robot->isHealthy())
73 {
74 URCL_LOG_ERROR("Something in the robot initialization went wrong. Exiting. Please check the output above.");
75 return 1;
76 }
77
78 auto instruction_executor = std::make_shared<urcl::InstructionExecutor>(g_my_robot->getUrDriver());
At first, a InstructionExecutor object is created with the URDriver object as it needs that
for communication with the robot.
Currently, the InstructionExecutor can either be used to run sequences of motions or single motions.
Execute a sequence of motions
To run a sequence of motions, create an
std::vector<std::shared_ptr<urcl::cointrol::MotionPrimitive>> and pass it to the
executeMotion function:
82 // Trajectory definition
83 std::vector<std::shared_ptr<urcl::control::MotionPrimitive>> motion_sequence{
84 std::make_shared<urcl::control::MoveJPrimitive>(urcl::vector6d_t{ -1.57, -1.57, 0, 0, 0, 0 }, 0.1,
85 std::chrono::seconds(5)),
86 // This point uses acceleration / velocity parametrization
87 std::make_shared<urcl::control::MoveJPrimitive>(urcl::vector6d_t{ -1.57, -1.6, 1.6, -0.7, 0.7, 0.2 }, 0.1,
88 std::chrono::seconds(0), 1.4, 2.0),
89
90 std::make_shared<urcl::control::MoveLPrimitive>(urcl::Pose(-0.203, 0.263, 0.559, 0.68, -1.083, -2.076), 0.1,
91 std::chrono::seconds(2)),
92 std::make_shared<urcl::control::MoveLPrimitive>(urcl::Q{ -1.57, -1.6, 1.6, -0.7, 0.7, 0.2 }, 0.1,
93 std::chrono::seconds(2)),
94 std::make_shared<urcl::control::MovePPrimitive>(urcl::Pose{ -0.203, 0.463, 0.559, 0.68, -1.083, -2.076 }, 0.1, 0.4,
95 0.4),
96 std::make_shared<urcl::control::OptimoveJPrimitive>(urcl::vector6d_t{ -1.57, -1.57, 1.6, -0.5, 0.4, 0.3 }, 0.1, 0.4,
97 0.7),
98 std::make_shared<urcl::control::OptimoveLPrimitive>(urcl::Pose(-0.203, 0.263, 0.559, 0.68, -1.083, -2.076), 0.1,
99 0.4, 0.7),
100 };
101 instruction_executor->executeMotion(motion_sequence);
Each element in the motion sequence can be a different motion type. In the example, there are two
MoveJ motions, a MoveL motion, a MoveP motion, a OptimiveJ motion and a
OptimoveL motion. The primitives’ parameters are directly forwarded to the underlying script
functions, so the parameter descriptions for them apply, as well. Particularly, you may want to
choose between either a time-based execution or an acceleration / velocity parametrization
for some move functions. The latter will be ignored if a time > 0 is given.
Each motion primitive can be constructed either with its “native” target type (vector6d_t for
MoveJ / OptimoveJ, urcl::Pose for MoveL / MoveP / MoveC / OptimoveL)
or with a urcl::MotionTarget, which can hold either a urcl::Q (joint configuration) or a
urcl::Pose (Cartesian pose). This makes it possible, for example, to use a
MoveLPrimitive with a joint configuration – the robot will then compute the forward
kinematics on the controller and linearly interpolate in tool space towards the resulting pose.
Please refer to the script manual for details.
Execute a single motion
To run a single motion, the InstructionExecutor provides the methods moveJ(...),
moveL(...), moveP(...), moveC(...), optimoveJ(...) and optimoveL(...):
103 double goal_time_sec = 2.0;
104
105 // acceleration / velocity parametrization brace-init style will be interpreted as joint
106 // positions
107 instruction_executor->moveJ({ -1.742, -1.726, -2.214, -0.773, 1.572, -0.171 }, 2.0, 2.0);
108
109 // Passing a pose to moveJ will make it internally solve inverse kinematics.
110 instruction_executor->moveJ(urcl::Pose{ -0.206, -0.6437, 0.202, 0.0, 3.140, 0.0 }, 2.0, 2.0);
111
112 // To provide a q_near hint for the IK solver a joint configuration near the target can be added to a pose.
113 urcl::Pose target_pose{ -0.206, -0.6437, 0.202, 0.0, 3.140, 0.0 };
114 target_pose.setQNear(urcl::Q{ -1.7, -4, 1.5, -1, 1.5, 0 });
115 instruction_executor->moveJ(target_pose, 2.0, 2.0);
116
117 // q_near can also be set directly upon pose construction
118 instruction_executor->moveJ(
119 urcl::Pose{ -0.206, -0.6437, 0.202, 0.0, 3.140, 0.0, urcl::Q{ -1.7, -4, 1.5, -1, 1.5, 0 } }, 2.0, 2.0);
120
121 // goal time parametrization -- acceleration and velocity will be scaled to meed the goal time.
122 instruction_executor->moveJ({ -1.57, -1.6, 1.6, -0.7, 0.7, 0.2 }, 0.1, 0.1, goal_time_sec);
123
124 // moveL calls with brace-init style is interpreted as a pose
125 instruction_executor->moveL({ -0.0203, 0.363, 0.559, 0.68, -1.083, -2.076 }, 1.5, 1.5);
126 // A pose can also be explicitly passed to moveL
127 instruction_executor->moveL(urcl::Pose{ -0.0203, 0.363, 0.559, 0.68, -1.083, -2.076 }, 1.5, 1.5);
128 // moveL can also accept a joint position target, if explicitly wrapped into a urcl::Q object
129 instruction_executor->moveL(urcl::Q{ -1.572, -1.686, 1.707, -0.833, 0.782, 0.479 }, 1.5, 1.5, goal_time_sec);
130
131 // moveJ can also accept a Cartesian pose, when given explicitly
132 instruction_executor->moveJ(urcl::Pose{ -0.0203, 0.363, 0.559, 0.68, -1.083, -2.076 }, 0.1, 0.1, goal_time_sec);
133
134 // moveP can also be called with brace-init (interpreted as pose) or explicitly using a Pose or Q
135 instruction_executor->moveP({ -0.2, 0.363, 0.559, 0.68, -1.083, -2.076 }, 0.2, 0.2);
136 instruction_executor->moveP(urcl::Pose{ -0.0203, 0.303, 0.559, 0.68, -1.083, -2.076 }, 0.2, 0.2);
137 instruction_executor->moveP(urcl::Q{ -1.57, -1.83, 1.707, -0.833, 0.782, 0.479 }, 0.2, 0.2);
138
139 // For moveC via and target can be a Pose or Q. When brace-init style lists are given, values are
140 // interpreted as Pose.
141 instruction_executor->moveP(urcl::Pose{ -0.2, 0.5, 0.5, 0.68, -1.083, -2.076 }, 0.2, 0.2);
142 instruction_executor->moveC(urcl::Pose{ -0.2, 0.4, 0.4, 0.68, -1.083, -2.076 },
143 urcl::Pose{ -0.2, 0.4, 0.6, 0.68, -1.083, -2.076 });
144 instruction_executor->moveC(urcl::Pose{ -0.2, 0.5, 0.5, 0.68, -1.083, -2.076 },
145 urcl::Q{ -1.84, -1.8, 2.7, 4.2, 0.6, -4.0 });
146
147 // For optimove functions, the same target rules as for moveJ and moveL apply.
148 instruction_executor->optimoveJ({ -1.57, -1.6, 1.6, -0.7, 0.7, 0.2 }, 1.0, 1.0);
149 instruction_executor->optimoveL(urcl::Pose{ -0.0203, 0.363, 0.559, 0.68, -1.083, -2.076 }, 1.0, 1.0);
150 instruction_executor->optimoveL(urcl::Q{ -1.572, -1.686, 1.707, -0.833, 0.782, 0.479 }, 1.0, 1.0);
151 instruction_executor->optimoveJ(urcl::Pose{ -0.0203, 0.363, 0.559, 0.68, -1.083, -2.076 }, 1.0, 1.0);
Again, time parametrization has priority over acceleration / velocity parameters.
Each motion function has two overloads: one taking the “natural” target type
(vector6d_t for moveJ / optimoveJ, urcl::Pose for the other motions), and one
taking a urcl::MotionTarget. Passing a braced-initializer-list of six doubles selects the
natural overload, so moveJ({ ... }) continues to be interpreted as joint positions and
moveL({ ... }) as a Cartesian pose. To select the other interpretation, wrap the values in
urcl::Q{...} or urcl::Pose{...} explicitly – for example,
moveJ(urcl::Pose{...}) performs a movej towards a Cartesian target and
moveL(urcl::Q{...}) performs a movel towards the pose implied by a joint configuration.
The same rules apply to moveP, moveC, optimoveJ and optimoveL.
For Cartesian targets, urcl::Pose may optionally set q_near (a urcl::Q): a joint-space
hint forwarded on the trajectory socket for inverse kinematics. The bundled external-control
URScript uses it for movej / optimovej to a pose; see Trajectory Point Interface.